+ Something went wrong. Please refresh or contact us.
+
+ `;
+ let no_results_section = `
+
+
+
+
+
${ __('No products found') }
+
+ `;
+
+ this.products_section.append(error ? error_section : no_results_section);
+ }
+
+ render_item_sub_categories(categories) {
+ if (categories && categories.length) {
+ let sub_group_html = `
+
`;
+
+ $("#product-listing").prepend(sub_group_html);
+ }
+ }
+
+ get_query_string(object) {
+ const url = new URLSearchParams();
+ for (let key in object) {
+ const value = object[key];
+ if (value) {
+ url.append(key, value);
+ }
+ }
+ return url.toString();
+ }
+
+ if_key_exists(obj) {
+ let exists = false;
+ for (let key in obj) {
+ if (Object.prototype.hasOwnProperty.call(obj, key) && obj[key]) {
+ exists = true;
+ break;
+ }
+ }
+ return exists ? obj : undefined;
+ }
+};
\ No newline at end of file
diff --git a/erpnext/e_commerce/redisearch.py b/erpnext/e_commerce/redisearch.py
new file mode 100644
index 00000000000..5cfb5ae2920
--- /dev/null
+++ b/erpnext/e_commerce/redisearch.py
@@ -0,0 +1,208 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+import frappe
+from frappe.utils.redis_wrapper import RedisWrapper
+from redisearch import AutoCompleter, Client, IndexDefinition, Suggestion, TagField, TextField
+
+WEBSITE_ITEM_INDEX = 'website_items_index'
+WEBSITE_ITEM_KEY_PREFIX = 'website_item:'
+WEBSITE_ITEM_NAME_AUTOCOMPLETE = 'website_items_name_dict'
+WEBSITE_ITEM_CATEGORY_AUTOCOMPLETE = 'website_items_category_dict'
+
+def get_indexable_web_fields():
+ "Return valid fields from Website Item that can be searched for."
+ web_item_meta = frappe.get_meta("Website Item", cached=True)
+ valid_fields = filter(
+ lambda df: df.fieldtype in ("Link", "Table MultiSelect", "Data", "Small Text", "Text Editor"),
+ web_item_meta.fields)
+
+ return [df.fieldname for df in valid_fields]
+
+def is_search_module_loaded():
+ cache = frappe.cache()
+ out = cache.execute_command('MODULE LIST')
+
+ parsed_output = " ".join(
+ (" ".join([s.decode() for s in o if not isinstance(s, int)]) for o in out)
+ )
+
+ return "search" in parsed_output
+
+def if_redisearch_loaded(function):
+ "Decorator to check if Redisearch is loaded."
+ def wrapper(*args, **kwargs):
+ if is_search_module_loaded():
+ func = function(*args, **kwargs)
+ return func
+ return
+
+ return wrapper
+
+def make_key(key):
+ return "{0}|{1}".format(frappe.conf.db_name, key).encode('utf-8')
+
+@if_redisearch_loaded
+def create_website_items_index():
+ "Creates Index Definition."
+
+ # CREATE index
+ client = Client(make_key(WEBSITE_ITEM_INDEX), conn=frappe.cache())
+
+ # DROP if already exists
+ try:
+ client.drop_index()
+ except Exception:
+ pass
+
+ idx_def = IndexDefinition([make_key(WEBSITE_ITEM_KEY_PREFIX)])
+
+ # Based on e-commerce settings
+ idx_fields = frappe.db.get_single_value(
+ 'E Commerce Settings',
+ 'search_index_fields'
+ )
+ idx_fields = idx_fields.split(',') if idx_fields else []
+
+ if 'web_item_name' in idx_fields:
+ idx_fields.remove('web_item_name')
+
+ idx_fields = list(map(to_search_field, idx_fields))
+
+ client.create_index(
+ [TextField("web_item_name", sortable=True)] + idx_fields,
+ definition=idx_def,
+ )
+
+ reindex_all_web_items()
+ define_autocomplete_dictionary()
+
+def to_search_field(field):
+ if field == "tags":
+ return TagField("tags", separator=",")
+
+ return TextField(field)
+
+@if_redisearch_loaded
+def insert_item_to_index(website_item_doc):
+ # Insert item to index
+ key = get_cache_key(website_item_doc.name)
+ cache = frappe.cache()
+ web_item = create_web_item_map(website_item_doc)
+
+ for k, v in web_item.items():
+ super(RedisWrapper, cache).hset(make_key(key), k, v)
+
+ insert_to_name_ac(website_item_doc.web_item_name, website_item_doc.name)
+
+@if_redisearch_loaded
+def insert_to_name_ac(web_name, doc_name):
+ ac = AutoCompleter(make_key(WEBSITE_ITEM_NAME_AUTOCOMPLETE), conn=frappe.cache())
+ ac.add_suggestions(Suggestion(web_name, payload=doc_name))
+
+def create_web_item_map(website_item_doc):
+ fields_to_index = get_fields_indexed()
+ web_item = {}
+
+ for f in fields_to_index:
+ web_item[f] = website_item_doc.get(f) or ''
+
+ return web_item
+
+@if_redisearch_loaded
+def update_index_for_item(website_item_doc):
+ # Reinsert to Cache
+ insert_item_to_index(website_item_doc)
+ define_autocomplete_dictionary()
+
+@if_redisearch_loaded
+def delete_item_from_index(website_item_doc):
+ cache = frappe.cache()
+ key = get_cache_key(website_item_doc.name)
+
+ try:
+ cache.delete(key)
+ except Exception:
+ return False
+
+ delete_from_ac_dict(website_item_doc)
+ return True
+
+@if_redisearch_loaded
+def delete_from_ac_dict(website_item_doc):
+ '''Removes this items's name from autocomplete dictionary'''
+ cache = frappe.cache()
+ name_ac = AutoCompleter(make_key(WEBSITE_ITEM_NAME_AUTOCOMPLETE), conn=cache)
+ name_ac.delete(website_item_doc.web_item_name)
+
+@if_redisearch_loaded
+def define_autocomplete_dictionary():
+ """Creates an autocomplete search dictionary for `name`.
+ Also creats autocomplete dictionary for `categories` if
+ checked in E Commerce Settings"""
+
+ cache = frappe.cache()
+ name_ac = AutoCompleter(make_key(WEBSITE_ITEM_NAME_AUTOCOMPLETE), conn=cache)
+ cat_ac = AutoCompleter(make_key(WEBSITE_ITEM_CATEGORY_AUTOCOMPLETE), conn=cache)
+
+ ac_categories = frappe.db.get_single_value(
+ 'E Commerce Settings',
+ 'show_categories_in_search_autocomplete'
+ )
+
+ # Delete both autocomplete dicts
+ try:
+ cache.delete(make_key(WEBSITE_ITEM_NAME_AUTOCOMPLETE))
+ cache.delete(make_key(WEBSITE_ITEM_CATEGORY_AUTOCOMPLETE))
+ except Exception:
+ return False
+
+ items = frappe.get_all(
+ 'Website Item',
+ fields=['web_item_name', 'item_group'],
+ filters={"published": 1}
+ )
+
+ for item in items:
+ name_ac.add_suggestions(Suggestion(item.web_item_name))
+ if ac_categories and item.item_group:
+ cat_ac.add_suggestions(Suggestion(item.item_group))
+
+ return True
+
+@if_redisearch_loaded
+def reindex_all_web_items():
+ items = frappe.get_all(
+ 'Website Item',
+ fields=get_fields_indexed(),
+ filters={"published": True}
+ )
+
+ cache = frappe.cache()
+ for item in items:
+ web_item = create_web_item_map(item)
+ key = make_key(get_cache_key(item.name))
+
+ for k, v in web_item.items():
+ super(RedisWrapper, cache).hset(key, k, v)
+
+def get_cache_key(name):
+ name = frappe.scrub(name)
+ return f"{WEBSITE_ITEM_KEY_PREFIX}{name}"
+
+def get_fields_indexed():
+ fields_to_index = frappe.db.get_single_value(
+ 'E Commerce Settings',
+ 'search_index_fields'
+ )
+ fields_to_index = fields_to_index.split(',') if fields_to_index else []
+
+ mandatory_fields = ['name', 'web_item_name', 'route', 'thumbnail', 'ranking']
+ fields_to_index = fields_to_index + mandatory_fields
+
+ return fields_to_index
+
+# TODO: Remove later
+# # Figure out a way to run this at startup
+define_autocomplete_dictionary()
+create_website_items_index()
diff --git a/erpnext/e_commerce/shopping_cart/__init__.py b/erpnext/e_commerce/shopping_cart/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/e_commerce/shopping_cart/cart.py
similarity index 92%
rename from erpnext/shopping_cart/cart.py
rename to erpnext/e_commerce/shopping_cart/cart.py
index e9f4bd57a6a..1b4d68e4f58 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/e_commerce/shopping_cart/cart.py
@@ -2,23 +2,27 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import throw, _
import frappe.defaults
-from frappe.utils import cint, flt, get_fullname, cstr
+from frappe import _, throw
from frappe.contacts.doctype.address.address import get_address_display
-from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import get_shopping_cart_settings
-from frappe.utils.nestedset import get_root_of
-from erpnext.accounts.utils import get_account_name
-from erpnext.utilities.product import get_qty_in_stock
from frappe.contacts.doctype.contact.contact import get_contact_name
+from frappe.utils import cint, cstr, flt, get_fullname
+from frappe.utils.nestedset import get_root_of
+
+from erpnext.accounts.utils import get_account_name
+from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import (
+ get_shopping_cart_settings,
+)
+from erpnext.utilities.product import get_web_item_qty_in_stock
class WebsitePriceListMissingError(frappe.ValidationError):
pass
def set_cart_count(quotation=None):
- if cint(frappe.db.get_singles_value("Shopping Cart Settings", "enabled")):
+ if cint(frappe.db.get_singles_value("E Commerce Settings", "enabled")):
if not quotation:
quotation = _get_cart_quotation()
cart_count = cstr(len(quotation.get("items")))
@@ -45,7 +49,7 @@ def get_cart_quotation(doc=None):
"shipping_addresses": get_shipping_addresses(party),
"billing_addresses": get_billing_addresses(party),
"shipping_rules": get_applicable_shipping_rules(party),
- "cart_settings": frappe.get_cached_doc("Shopping Cart Settings")
+ "cart_settings": frappe.get_cached_doc("E Commerce Settings")
}
@frappe.whitelist()
@@ -69,7 +73,7 @@ def get_billing_addresses(party=None):
@frappe.whitelist()
def place_order():
quotation = _get_cart_quotation()
- cart_settings = frappe.db.get_value("Shopping Cart Settings", None,
+ cart_settings = frappe.db.get_value("E Commerce Settings", None,
["company", "allow_items_not_in_stock"], as_dict=1)
quotation.company = cart_settings.company
@@ -89,13 +93,19 @@ def place_order():
if not cint(cart_settings.allow_items_not_in_stock):
for item in sales_order.get("items"):
- item.reserved_warehouse, is_stock_item = frappe.db.get_value("Item",
- item.item_code, ["website_warehouse", "is_stock_item"])
+ item.warehouse = frappe.db.get_value(
+ "Website Item",
+ {
+ "item_code": item.item_code
+ },
+ "website_warehouse"
+ )
+ is_stock_item = frappe.db.get_value("Item", item.item_code, "is_stock_item")
if is_stock_item:
- item_stock = get_qty_in_stock(item.item_code, "website_warehouse")
+ item_stock = get_web_item_qty_in_stock(item.item_code, "website_warehouse")
if not cint(item_stock.in_stock):
- throw(_("{1} Not in Stock").format(item.item_code))
+ throw(_("{0} Not in Stock").format(item.item_code))
if item.qty > item_stock.stock_qty[0][0]:
throw(_("Only {0} in Stock for item {1}").format(item_stock.stock_qty[0][0], item.item_code))
@@ -153,19 +163,19 @@ def update_cart(item_code, qty, additional_notes=None, with_items=False):
set_cart_count(quotation)
- context = get_cart_quotation(quotation)
-
if cint(with_items):
+ context = get_cart_quotation(quotation)
return {
"items": frappe.render_template("templates/includes/cart/cart_items.html",
context),
- "taxes": frappe.render_template("templates/includes/order/order_taxes.html",
+ "total": frappe.render_template("templates/includes/cart/cart_items_total.html",
context),
+ "taxes_and_totals": frappe.render_template("templates/includes/cart/cart_payment_summary.html",
+ context)
}
else:
return {
- 'name': quotation.name,
- 'shopping_cart_menu': get_shopping_cart_menu(context)
+ 'name': quotation.name
}
@frappe.whitelist()
@@ -259,13 +269,17 @@ def guess_territory():
territory = frappe.db.get_value("Territory", geoip_country)
return territory or \
- frappe.db.get_value("Shopping Cart Settings", None, "territory") or \
+ frappe.db.get_value("E Commerce Settings", None, "territory") or \
get_root_of("Territory")
def decorate_quotation_doc(doc):
for d in doc.get("items", []):
- d.update(frappe.db.get_value("Item", d.item_code,
- ["thumbnail", "website_image", "description", "route"], as_dict=True))
+ d.update(frappe.db.get_value(
+ "Website Item",
+ {"item_code": d.item_code},
+ ["web_item_name", "thumbnail", "website_image", "description", "route"],
+ as_dict=True)
+ )
return doc
@@ -282,7 +296,7 @@ def _get_cart_quotation(party=None):
if quotation:
qdoc = frappe.get_doc("Quotation", quotation[0].name)
else:
- company = frappe.db.get_value("Shopping Cart Settings", None, ["company"])
+ company = frappe.db.get_value("E Commerce Settings", None, ["company"])
qdoc = frappe.get_doc({
"doctype": "Quotation",
"naming_series": get_shopping_cart_settings().quotation_series or "QTN-CART-",
@@ -337,7 +351,7 @@ def apply_cart_settings(party=None, quotation=None):
if not quotation:
quotation = _get_cart_quotation(party)
- cart_settings = frappe.get_doc("Shopping Cart Settings")
+ cart_settings = frappe.get_doc("E Commerce Settings")
set_price_list_and_rate(quotation, cart_settings)
@@ -414,7 +428,7 @@ def get_party(user=None):
party_doctype = contact.links[0].link_doctype
party = contact.links[0].link_name
- cart_settings = frappe.get_doc("Shopping Cart Settings")
+ cart_settings = frappe.get_doc("E Commerce Settings")
debtors_account = ''
diff --git a/erpnext/shopping_cart/product_info.py b/erpnext/e_commerce/shopping_cart/product_info.py
similarity index 55%
rename from erpnext/shopping_cart/product_info.py
rename to erpnext/e_commerce/shopping_cart/product_info.py
index 6c9e531a4d1..5e3bdc5c362 100644
--- a/erpnext/shopping_cart/product_info.py
+++ b/erpnext/e_commerce/shopping_cart/product_info.py
@@ -4,10 +4,18 @@
from __future__ import unicode_literals
import frappe
-from erpnext.shopping_cart.cart import _get_cart_quotation, _set_price_list
-from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings \
- import get_shopping_cart_settings, show_quantity_in_website
-from erpnext.utilities.product import get_price, get_qty_in_stock, get_non_stock_item_status
+
+from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import (
+ get_shopping_cart_settings,
+ show_quantity_in_website,
+)
+from erpnext.e_commerce.shopping_cart.cart import _get_cart_quotation, _set_price_list
+from erpnext.utilities.product import (
+ get_non_stock_item_status,
+ get_price,
+ get_web_item_qty_in_stock,
+)
+
@frappe.whitelist(allow_guest=True)
def get_product_info_for_website(item_code, skip_quotation_creation=False):
@@ -23,25 +31,43 @@ def get_product_info_for_website(item_code, skip_quotation_creation=False):
selling_price_list = cart_quotation.get("selling_price_list") if cart_quotation else _set_price_list(cart_settings, None)
- price = get_price(
- item_code,
- selling_price_list,
- cart_settings.default_customer_group,
- cart_settings.company
- )
+ price = {}
+ if cart_settings.show_price:
+ is_guest = frappe.session.user == "Guest"
+ # Show Price if logged in.
+ # If not logged in, check if price is hidden for guest.
+ if not is_guest or not cart_settings.hide_price_for_guest:
+ price = get_price(
+ item_code,
+ selling_price_list,
+ cart_settings.default_customer_group,
+ cart_settings.company
+ )
- stock_status = get_qty_in_stock(item_code, "website_warehouse")
+ stock_status = None
+
+ if cart_settings.show_stock_availability:
+ on_backorder = frappe.get_cached_value("Website Item", {"item_code": item_code}, "on_backorder")
+ if on_backorder:
+ stock_status = frappe._dict({"on_backorder": True})
+ else:
+ stock_status = get_web_item_qty_in_stock(item_code, "website_warehouse")
product_info = {
"price": price,
- "stock_qty": stock_status.stock_qty,
- "in_stock": stock_status.in_stock if stock_status.is_stock_item else get_non_stock_item_status(item_code, "website_warehouse"),
"qty": 0,
"uom": frappe.db.get_value("Item", item_code, "stock_uom"),
- "show_stock_qty": show_quantity_in_website(),
"sales_uom": frappe.db.get_value("Item", item_code, "sales_uom")
}
+ if stock_status:
+ if stock_status.on_backorder:
+ product_info["on_backorder"] = True
+ else:
+ product_info["stock_qty"] = stock_status.stock_qty
+ product_info["in_stock"] = stock_status.in_stock if stock_status.is_stock_item else get_non_stock_item_status(item_code, "website_warehouse")
+ product_info["show_stock_qty"] = show_quantity_in_website()
+
if product_info["price"]:
if frappe.session.user != "Guest":
item = cart_quotation.get({"item_code": item_code}) if cart_quotation else None
diff --git a/erpnext/shopping_cart/test_shopping_cart.py b/erpnext/e_commerce/shopping_cart/test_shopping_cart.py
similarity index 90%
rename from erpnext/shopping_cart/test_shopping_cart.py
rename to erpnext/e_commerce/shopping_cart/test_shopping_cart.py
index ac61aebc564..96614d0cb64 100644
--- a/erpnext/shopping_cart/test_shopping_cart.py
+++ b/erpnext/e_commerce/shopping_cart/test_shopping_cart.py
@@ -2,14 +2,17 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import unittest
-import frappe
-from frappe.utils import nowdate, add_months
-from erpnext.shopping_cart.cart import _get_cart_quotation, update_cart, get_party
-from erpnext.tests.utils import create_test_contact_and_address
-from erpnext.accounts.doctype.tax_rule.tax_rule import ConflictingTaxRule
-# test_dependencies = ['Payment Terms Template']
+import unittest
+
+import frappe
+from frappe.utils import add_months, nowdate
+
+from erpnext.accounts.doctype.tax_rule.tax_rule import ConflictingTaxRule
+from erpnext.e_commerce.doctype.website_item.website_item import make_website_item
+from erpnext.e_commerce.shopping_cart.cart import _get_cart_quotation, get_party, update_cart
+from erpnext.tests.utils import create_test_contact_and_address
+
class TestShoppingCart(unittest.TestCase):
"""
@@ -25,6 +28,11 @@ class TestShoppingCart(unittest.TestCase):
frappe.set_user("Administrator")
create_test_contact_and_address()
self.enable_shopping_cart()
+ if not frappe.db.exists("Website Item", {"item_code": "_Test Item"}):
+ make_website_item(frappe.get_cached_doc("Item", "_Test Item"))
+
+ if not frappe.db.exists("Website Item", {"item_code": "_Test Item 2"}):
+ make_website_item(frappe.get_cached_doc("Item", "_Test Item 2"))
def tearDown(self):
frappe.set_user("Administrator")
@@ -164,7 +172,7 @@ class TestShoppingCart(unittest.TestCase):
# helper functions
def enable_shopping_cart(self):
- settings = frappe.get_doc("Shopping Cart Settings", "Shopping Cart Settings")
+ settings = frappe.get_doc("E Commerce Settings", "E Commerce Settings")
settings.update({
"enabled": 1,
@@ -194,7 +202,7 @@ class TestShoppingCart(unittest.TestCase):
frappe.local.shopping_cart_settings = None
def disable_shopping_cart(self):
- settings = frappe.get_doc("Shopping Cart Settings", "Shopping Cart Settings")
+ settings = frappe.get_doc("E Commerce Settings", "E Commerce Settings")
settings.enabled = 0
settings.save()
frappe.local.shopping_cart_settings = None
diff --git a/erpnext/shopping_cart/utils.py b/erpnext/e_commerce/shopping_cart/utils.py
similarity index 87%
rename from erpnext/shopping_cart/utils.py
rename to erpnext/e_commerce/shopping_cart/utils.py
index 0e1466fd1fa..51398596fd8 100644
--- a/erpnext/shopping_cart/utils.py
+++ b/erpnext/e_commerce/shopping_cart/utils.py
@@ -5,7 +5,9 @@ from __future__ import unicode_literals
import frappe
import frappe.defaults
-from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import is_cart_enabled
+
+from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import is_cart_enabled
+
def show_cart_count():
if (is_cart_enabled() and
@@ -18,7 +20,7 @@ def set_cart_count(login_manager):
role, parties = check_customer_or_supplier()
if role == 'Supplier': return
if show_cart_count():
- from erpnext.shopping_cart.cart import set_cart_count
+ from erpnext.e_commerce.shopping_cart.cart import set_cart_count
set_cart_count()
def clear_cart_count(login_manager):
diff --git a/erpnext/e_commerce/variant_selector/__init__.py b/erpnext/e_commerce/variant_selector/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/portal/product_configurator/item_variants_cache.py b/erpnext/e_commerce/variant_selector/item_variants_cache.py
similarity index 90%
rename from erpnext/portal/product_configurator/item_variants_cache.py
rename to erpnext/e_commerce/variant_selector/item_variants_cache.py
index fc294ce58bb..39eb9155d5e 100644
--- a/erpnext/portal/product_configurator/item_variants_cache.py
+++ b/erpnext/e_commerce/variant_selector/item_variants_cache.py
@@ -1,5 +1,6 @@
import frappe
+
class ItemVariantsCacheManager:
def __init__(self, item_code):
self.item_code = item_code
@@ -66,12 +67,16 @@ class ItemVariantsCacheManager:
as_list=1
)
- disabled_items = set([i.name for i in frappe.db.get_all('Item', {'disabled': 1})])
+ unpublished_items = set([i.item_code for i in frappe.db.get_all('Website Item', filters={'published': 0}, fields=["item_code"])])
attribute_value_item_map = frappe._dict({})
item_attribute_value_map = frappe._dict({})
- item_variants_data = [r for r in item_variants_data if r[0] not in disabled_items]
+ # dont consider variants that are unpublished
+ # (either have no Website Item or are unpublished in Website Item)
+ item_variants_data = [r for r in item_variants_data if r[0] not in unpublished_items]
+ item_variants_data = [r for r in item_variants_data if frappe.db.exists("Website Item", {"item_code": r[0]})]
+
for row in item_variants_data:
item_code, attribute, attribute_value = row
# (attr, value) => [item1, item2]
diff --git a/erpnext/e_commerce/variant_selector/test_variant_selector.py b/erpnext/e_commerce/variant_selector/test_variant_selector.py
new file mode 100644
index 00000000000..c70fee5fff5
--- /dev/null
+++ b/erpnext/e_commerce/variant_selector/test_variant_selector.py
@@ -0,0 +1,11 @@
+# import frappe
+import unittest
+
+# from erpnext.e_commerce.product_data_engine.query import ProductQuery
+# from erpnext.e_commerce.doctype.website_item.website_item import make_website_item
+
+test_dependencies = ["Item"]
+
+class TestVariantSelector(unittest.TestCase):
+ # TODO: Variant Selector Tests
+ pass
\ No newline at end of file
diff --git a/erpnext/e_commerce/variant_selector/utils.py b/erpnext/e_commerce/variant_selector/utils.py
new file mode 100644
index 00000000000..61df3adca58
--- /dev/null
+++ b/erpnext/e_commerce/variant_selector/utils.py
@@ -0,0 +1,197 @@
+import frappe
+from frappe.utils import cint
+
+from erpnext.e_commerce.variant_selector.item_variants_cache import ItemVariantsCacheManager
+
+
+def get_item_codes_by_attributes(attribute_filters, template_item_code=None):
+ items = []
+
+ for attribute, values in attribute_filters.items():
+ attribute_values = values
+
+ if not isinstance(attribute_values, list):
+ attribute_values = [attribute_values]
+
+ if not attribute_values:
+ continue
+
+ wheres = []
+ query_values = []
+ for attribute_value in attribute_values:
+ wheres.append('( attribute = %s and attribute_value = %s )')
+ query_values += [attribute, attribute_value]
+
+ attribute_query = ' or '.join(wheres)
+
+ if template_item_code:
+ variant_of_query = 'AND t2.variant_of = %s'
+ query_values.append(template_item_code)
+ else:
+ variant_of_query = ''
+
+ query = '''
+ SELECT
+ t1.parent
+ FROM
+ `tabItem Variant Attribute` t1
+ WHERE
+ 1 = 1
+ AND (
+ {attribute_query}
+ )
+ AND EXISTS (
+ SELECT
+ 1
+ FROM
+ `tabItem` t2
+ WHERE
+ t2.name = t1.parent
+ {variant_of_query}
+ )
+ GROUP BY
+ t1.parent
+ ORDER BY
+ NULL
+ '''.format(attribute_query=attribute_query, variant_of_query=variant_of_query)
+
+ item_codes = set([r[0] for r in frappe.db.sql(query, query_values)])
+ items.append(item_codes)
+
+ res = list(set.intersection(*items))
+
+ return res
+
+@frappe.whitelist(allow_guest=True)
+def get_attributes_and_values(item_code):
+ '''Build a list of attributes and their possible values.
+ This will ignore the values upon selection of which there cannot exist one item.
+ '''
+ item_cache = ItemVariantsCacheManager(item_code)
+ item_variants_data = item_cache.get_item_variants_data()
+
+ attributes = get_item_attributes(item_code)
+ attribute_list = [a.attribute for a in attributes]
+
+ valid_options = {}
+ for item_code, attribute, attribute_value in item_variants_data:
+ if attribute in attribute_list:
+ valid_options.setdefault(attribute, set()).add(attribute_value)
+
+ item_attribute_values = frappe.db.get_all('Item Attribute Value',
+ ['parent', 'attribute_value', 'idx'], order_by='parent asc, idx asc')
+ ordered_attribute_value_map = frappe._dict()
+ for iv in item_attribute_values:
+ ordered_attribute_value_map.setdefault(iv.parent, []).append(iv.attribute_value)
+
+ # build attribute values in idx order
+ for attr in attributes:
+ valid_attribute_values = valid_options.get(attr.attribute, [])
+ ordered_values = ordered_attribute_value_map.get(attr.attribute, [])
+ attr['values'] = [v for v in ordered_values if v in valid_attribute_values]
+
+ return attributes
+
+
+@frappe.whitelist(allow_guest=True)
+def get_next_attribute_and_values(item_code, selected_attributes):
+ '''Find the count of Items that match the selected attributes.
+ Also, find the attribute values that are not applicable for further searching.
+ If less than equal to 10 items are found, return item_codes of those items.
+ If one item is matched exactly, return item_code of that item.
+ '''
+ selected_attributes = frappe.parse_json(selected_attributes)
+
+ item_cache = ItemVariantsCacheManager(item_code)
+ item_variants_data = item_cache.get_item_variants_data()
+
+ attributes = get_item_attributes(item_code)
+ attribute_list = [a.attribute for a in attributes]
+ filtered_items = get_items_with_selected_attributes(item_code, selected_attributes)
+
+ next_attribute = None
+
+ for attribute in attribute_list:
+ if attribute not in selected_attributes:
+ next_attribute = attribute
+ break
+
+ valid_options_for_attributes = frappe._dict()
+
+ for a in attribute_list:
+ valid_options_for_attributes[a] = set()
+
+ selected_attribute = selected_attributes.get(a, None)
+ if selected_attribute:
+ # already selected attribute values are valid options
+ valid_options_for_attributes[a].add(selected_attribute)
+
+ for row in item_variants_data:
+ item_code, attribute, attribute_value = row
+ if item_code in filtered_items and attribute not in selected_attributes and attribute in attribute_list:
+ valid_options_for_attributes[attribute].add(attribute_value)
+
+ optional_attributes = item_cache.get_optional_attributes()
+ exact_match = []
+ # search for exact match if all selected attributes are required attributes
+ if len(selected_attributes.keys()) >= (len(attribute_list) - len(optional_attributes)):
+ item_attribute_value_map = item_cache.get_item_attribute_value_map()
+ for item_code, attr_dict in item_attribute_value_map.items():
+ if item_code in filtered_items and set(attr_dict.keys()) == set(selected_attributes.keys()):
+ exact_match.append(item_code)
+
+ filtered_items_count = len(filtered_items)
+
+ # get product info if exact match
+ from erpnext.e_commerce.shopping_cart.product_info import get_product_info_for_website
+ if exact_match:
+ data = get_product_info_for_website(exact_match[0])
+ product_info = data.product_info
+ if product_info:
+ product_info["allow_items_not_in_stock"] = cint(data.cart_settings.allow_items_not_in_stock)
+ if not data.cart_settings.show_price:
+ product_info = None
+ else:
+ product_info = None
+
+ return {
+ 'next_attribute': next_attribute,
+ 'valid_options_for_attributes': valid_options_for_attributes,
+ 'filtered_items_count': filtered_items_count,
+ 'filtered_items': filtered_items if filtered_items_count < 10 else [],
+ 'exact_match': exact_match,
+ 'product_info': product_info
+ }
+
+
+def get_items_with_selected_attributes(item_code, selected_attributes):
+ item_cache = ItemVariantsCacheManager(item_code)
+ attribute_value_item_map = item_cache.get_attribute_value_item_map()
+
+ items = []
+ for attribute, value in selected_attributes.items():
+ filtered_items = attribute_value_item_map.get((attribute, value), [])
+ items.append(set(filtered_items))
+
+ return set.intersection(*items)
+
+# utilities
+
+def get_item_attributes(item_code):
+ attributes = frappe.db.get_all('Item Variant Attribute',
+ fields=['attribute'],
+ filters={
+ 'parenttype': 'Item',
+ 'parent': item_code
+ },
+ order_by='idx asc'
+ )
+
+ optional_attributes = ItemVariantsCacheManager(item_code).get_optional_attributes()
+
+ for a in attributes:
+ if a.attribute in optional_attributes:
+ a.optional = True
+
+ return attributes
+
diff --git a/erpnext/e_commerce/web_template/__init__.py b/erpnext/e_commerce/web_template/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/e_commerce/web_template/hero_slider/__init__.py b/erpnext/e_commerce/web_template/hero_slider/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html b/erpnext/e_commerce/web_template/hero_slider/hero_slider.html
similarity index 100%
rename from erpnext/shopping_cart/web_template/hero_slider/hero_slider.html
rename to erpnext/e_commerce/web_template/hero_slider/hero_slider.html
diff --git a/erpnext/shopping_cart/web_template/hero_slider/hero_slider.json b/erpnext/e_commerce/web_template/hero_slider/hero_slider.json
similarity index 98%
rename from erpnext/shopping_cart/web_template/hero_slider/hero_slider.json
rename to erpnext/e_commerce/web_template/hero_slider/hero_slider.json
index 04fb1d27059..2b1807c9651 100644
--- a/erpnext/shopping_cart/web_template/hero_slider/hero_slider.json
+++ b/erpnext/e_commerce/web_template/hero_slider/hero_slider.json
@@ -1,4 +1,5 @@
{
+ "__unsaved": 1,
"creation": "2020-11-17 15:21:51.207221",
"docstatus": 0,
"doctype": "Web Template",
@@ -273,9 +274,9 @@
}
],
"idx": 2,
- "modified": "2020-12-29 12:30:02.794994",
+ "modified": "2021-02-24 15:57:05.889709",
"modified_by": "Administrator",
- "module": "Shopping Cart",
+ "module": "E-commerce",
"name": "Hero Slider",
"owner": "Administrator",
"standard": 1,
diff --git a/erpnext/e_commerce/web_template/item_card_group/__init__.py b/erpnext/e_commerce/web_template/item_card_group/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/shopping_cart/web_template/item_card_group/item_card_group.html b/erpnext/e_commerce/web_template/item_card_group/item_card_group.html
similarity index 86%
rename from erpnext/shopping_cart/web_template/item_card_group/item_card_group.html
rename to erpnext/e_commerce/web_template/item_card_group/item_card_group.html
index fe061d5f5f5..33d7bccc23a 100644
--- a/erpnext/shopping_cart/web_template/item_card_group/item_card_group.html
+++ b/erpnext/e_commerce/web_template/item_card_group/item_card_group.html
@@ -25,9 +25,8 @@
{%- if item -%}
{%- set item = frappe.get_doc("Item", item) -%}
{{ item_card(
- item.item_name, item.image, item.route, item.description,
- None, item.item_group, values['card_' + index + '_featured'],
- True, "Center"
+ item, is_featured=values['card_' + index + '_featured'],
+ is_full_width=True, align="Center"
) }}
{%- endif -%}
{%- endfor -%}
diff --git a/erpnext/shopping_cart/web_template/item_card_group/item_card_group.json b/erpnext/e_commerce/web_template/item_card_group/item_card_group.json
similarity index 97%
rename from erpnext/shopping_cart/web_template/item_card_group/item_card_group.json
rename to erpnext/e_commerce/web_template/item_card_group/item_card_group.json
index ad087b04704..724c4379121 100644
--- a/erpnext/shopping_cart/web_template/item_card_group/item_card_group.json
+++ b/erpnext/e_commerce/web_template/item_card_group/item_card_group.json
@@ -17,15 +17,12 @@
"reqd": 0
},
{
- "__unsaved": 1,
"fieldname": "primary_action_label",
"fieldtype": "Data",
"label": "Primary Action Label",
"reqd": 0
},
{
- "__islocal": 1,
- "__unsaved": 1,
"fieldname": "primary_action",
"fieldtype": "Data",
"label": "Primary Action",
@@ -262,9 +259,9 @@
}
],
"idx": 0,
- "modified": "2020-11-19 18:48:52.633045",
+ "modified": "2021-02-24 16:05:31.242342",
"modified_by": "Administrator",
- "module": "Shopping Cart",
+ "module": "E-commerce",
"name": "Item Card Group",
"owner": "Administrator",
"standard": 1,
diff --git a/erpnext/e_commerce/web_template/product_card/__init__.py b/erpnext/e_commerce/web_template/product_card/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/e_commerce/web_template/product_card/product_card.html b/erpnext/e_commerce/web_template/product_card/product_card.html
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/shopping_cart/web_template/product_card/product_card.json b/erpnext/e_commerce/web_template/product_card/product_card.json
similarity index 82%
rename from erpnext/shopping_cart/web_template/product_card/product_card.json
rename to erpnext/e_commerce/web_template/product_card/product_card.json
index 1059c1b2519..2eb73741efb 100644
--- a/erpnext/shopping_cart/web_template/product_card/product_card.json
+++ b/erpnext/e_commerce/web_template/product_card/product_card.json
@@ -5,7 +5,6 @@
"doctype": "Web Template",
"fields": [
{
- "__unsaved": 1,
"fieldname": "item",
"fieldtype": "Link",
"label": "Item",
@@ -13,7 +12,6 @@
"reqd": 0
},
{
- "__unsaved": 1,
"fieldname": "featured",
"fieldtype": "Check",
"label": "Featured",
@@ -22,9 +20,9 @@
}
],
"idx": 0,
- "modified": "2020-11-17 15:33:34.982515",
+ "modified": "2021-02-24 16:05:17.926610",
"modified_by": "Administrator",
- "module": "Shopping Cart",
+ "module": "E-commerce",
"name": "Product Card",
"owner": "Administrator",
"standard": 1,
diff --git a/erpnext/e_commerce/web_template/product_category_cards/__init__.py b/erpnext/e_commerce/web_template/product_category_cards/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/shopping_cart/web_template/product_category_cards/product_category_cards.html b/erpnext/e_commerce/web_template/product_category_cards/product_category_cards.html
similarity index 81%
rename from erpnext/shopping_cart/web_template/product_category_cards/product_category_cards.html
rename to erpnext/e_commerce/web_template/product_category_cards/product_category_cards.html
index 06b76af9018..6d75a8b1d5e 100644
--- a/erpnext/shopping_cart/web_template/product_category_cards/product_category_cards.html
+++ b/erpnext/e_commerce/web_template/product_category_cards/product_category_cards.html
@@ -6,8 +6,15 @@
}) -%}
{% if image %}
-
+
+ {% else %}
+
+
+ {{ frappe.utils.get_abbr(title or '') }}
+
+
{% endif %}
+
{{ title or '' }}
diff --git a/erpnext/shopping_cart/web_template/product_category_cards/product_category_cards.json b/erpnext/e_commerce/web_template/product_category_cards/product_category_cards.json
similarity index 95%
rename from erpnext/shopping_cart/web_template/product_category_cards/product_category_cards.json
rename to erpnext/e_commerce/web_template/product_category_cards/product_category_cards.json
index ba5f63b48b2..0202165d08e 100644
--- a/erpnext/shopping_cart/web_template/product_category_cards/product_category_cards.json
+++ b/erpnext/e_commerce/web_template/product_category_cards/product_category_cards.json
@@ -74,9 +74,9 @@
}
],
"idx": 0,
- "modified": "2020-11-18 17:26:28.726260",
+ "modified": "2021-02-24 16:03:33.835635",
"modified_by": "Administrator",
- "module": "Shopping Cart",
+ "module": "E-commerce",
"name": "Product Category Cards",
"owner": "Administrator",
"standard": 1,
diff --git a/erpnext/education/__init__.py b/erpnext/education/__init__.py
index c0589bb489b..a3164b25970 100644
--- a/erpnext/education/__init__.py
+++ b/erpnext/education/__init__.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
class StudentNotInGroupError(frappe.ValidationError): pass
def validate_student_belongs_to_group(student, student_group):
diff --git a/erpnext/education/api.py b/erpnext/education/api.py
index 4493a3fef17..d2a8805c897 100644
--- a/erpnext/education/api.py
+++ b/erpnext/education/api.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
+
+import frappe
from frappe import _
-from frappe.model.mapper import get_mapped_doc
-from frappe.utils import flt, cstr, getdate
from frappe.email.doctype.email_group.email_group import add_subscribers
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import cstr, flt, getdate
+
def get_course(program):
'''Return list of courses for a particular program
diff --git a/erpnext/education/doctype/academic_term/academic_term.py b/erpnext/education/doctype/academic_term/academic_term.py
index fa7f2899dcb..b8e22b68c62 100644
--- a/erpnext/education/doctype/academic_term/academic_term.py
+++ b/erpnext/education/doctype/academic_term/academic_term.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import getdate
from frappe.model.document import Document
+from frappe.utils import getdate
+
class AcademicTerm(Document):
def autoname(self):
diff --git a/erpnext/education/doctype/academic_term/academic_term_dashboard.py b/erpnext/education/doctype/academic_term/academic_term_dashboard.py
index eb2f90742ce..a1087b8fc42 100644
--- a/erpnext/education/doctype/academic_term/academic_term_dashboard.py
+++ b/erpnext/education/doctype/academic_term/academic_term_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'academic_term',
diff --git a/erpnext/education/doctype/academic_term/test_academic_term.py b/erpnext/education/doctype/academic_term/test_academic_term.py
index 0964a56454b..6329103870f 100644
--- a/erpnext/education/doctype/academic_term/test_academic_term.py
+++ b/erpnext/education/doctype/academic_term/test_academic_term.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Academic Term')
diff --git a/erpnext/education/doctype/academic_year/academic_year.py b/erpnext/education/doctype/academic_year/academic_year.py
index f2858a42d4b..77b67d8a5d7 100644
--- a/erpnext/education/doctype/academic_year/academic_year.py
+++ b/erpnext/education/doctype/academic_year/academic_year.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import msgprint, _
+from frappe import _
from frappe.model.document import Document
+
class AcademicYear(Document):
def validate(self):
#Check that start of academic year is earlier than end of academic year
diff --git a/erpnext/education/doctype/academic_year/academic_year_dashboard.py b/erpnext/education/doctype/academic_year/academic_year_dashboard.py
index d3734df8036..49d68c3af28 100644
--- a/erpnext/education/doctype/academic_year/academic_year_dashboard.py
+++ b/erpnext/education/doctype/academic_year/academic_year_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'academic_year',
diff --git a/erpnext/education/doctype/academic_year/test_academic_year.js b/erpnext/education/doctype/academic_year/test_academic_year.js
deleted file mode 100644
index 51e9cf307d8..00000000000
--- a/erpnext/education/doctype/academic_year/test_academic_year.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Testing Setup Module in Education
-QUnit.module('education');
-
-QUnit.test('Test: Academic Year', function(assert){
- assert.expect(3);
- let done = assert.async();
- frappe.run_serially([
- () => {
- return frappe.tests.make('Academic Year', [
- {academic_year_name: '2016-17'},
- {year_start_date: '2016-07-20'},
- {year_end_date:'2017-06-20'},
- ]);
- },
-
- () => {
- assert.ok(cur_frm.doc.academic_year_name=='2016-17');
- assert.ok(cur_frm.doc.year_start_date=='2016-07-20');
- assert.ok(cur_frm.doc.year_end_date=='2017-06-20');
- },
- () => done()
- ]);
-});
diff --git a/erpnext/education/doctype/academic_year/test_academic_year.py b/erpnext/education/doctype/academic_year/test_academic_year.py
index 9da75a72143..31135c40f38 100644
--- a/erpnext/education/doctype/academic_year/test_academic_year.py
+++ b/erpnext/education/doctype/academic_year/test_academic_year.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Academic Year')
diff --git a/erpnext/education/doctype/article/article.py b/erpnext/education/doctype/article/article.py
index b5cc5cbc7a6..f3c77880fc1 100644
--- a/erpnext/education/doctype/article/article.py
+++ b/erpnext/education/doctype/article/article.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class Article(Document):
def get_article(self):
pass
diff --git a/erpnext/education/doctype/article/test_article.js b/erpnext/education/doctype/article/test_article.js
deleted file mode 100644
index 9dbf063e844..00000000000
--- a/erpnext/education/doctype/article/test_article.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Article", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Article
- () => frappe.tests.make('Article', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/article/test_article.py b/erpnext/education/doctype/article/test_article.py
index 2fce07f82c1..cda79ad4579 100644
--- a/erpnext/education/doctype/article/test_article.py
+++ b/erpnext/education/doctype/article/test_article.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestArticle(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/assessment_criteria/assessment_criteria.py b/erpnext/education/doctype/assessment_criteria/assessment_criteria.py
index bfbf26cf6c1..f8f04bf5135 100644
--- a/erpnext/education/doctype/assessment_criteria/assessment_criteria.py
+++ b/erpnext/education/doctype/assessment_criteria/assessment_criteria.py
@@ -3,6 +3,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
diff --git a/erpnext/education/doctype/assessment_criteria/test_assessment_criteria.py b/erpnext/education/doctype/assessment_criteria/test_assessment_criteria.py
index fc0d7451108..1098d0369fb 100644
--- a/erpnext/education/doctype/assessment_criteria/test_assessment_criteria.py
+++ b/erpnext/education/doctype/assessment_criteria/test_assessment_criteria.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Assessment Criteria')
diff --git a/erpnext/education/doctype/assessment_criteria_group/assessment_criteria_group.py b/erpnext/education/doctype/assessment_criteria_group/assessment_criteria_group.py
index 75381e1d0bf..e62c0305520 100644
--- a/erpnext/education/doctype/assessment_criteria_group/assessment_criteria_group.py
+++ b/erpnext/education/doctype/assessment_criteria_group/assessment_criteria_group.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class AssessmentCriteriaGroup(Document):
pass
diff --git a/erpnext/education/doctype/assessment_criteria_group/test_assessment_criteria_group.py b/erpnext/education/doctype/assessment_criteria_group/test_assessment_criteria_group.py
index 5b293371bb8..d65f1e78d1d 100644
--- a/erpnext/education/doctype/assessment_criteria_group/test_assessment_criteria_group.py
+++ b/erpnext/education/doctype/assessment_criteria_group/test_assessment_criteria_group.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Assessment Criteria Group')
diff --git a/erpnext/education/doctype/assessment_group/assessment_group.py b/erpnext/education/doctype/assessment_group/assessment_group.py
index 88acc124d31..3425109331f 100644
--- a/erpnext/education/doctype/assessment_group/assessment_group.py
+++ b/erpnext/education/doctype/assessment_group/assessment_group.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class AssessmentGroup(Document):
pass
diff --git a/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py b/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py
index 1a23606a61d..83438c0ed74 100644
--- a/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py
+++ b/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py
@@ -1,8 +1,10 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'assessment_group',
diff --git a/erpnext/education/doctype/assessment_group/test_assessment_group.py b/erpnext/education/doctype/assessment_group/test_assessment_group.py
index 2fd98b6d02f..822d65c9bb7 100644
--- a/erpnext/education/doctype/assessment_group/test_assessment_group.py
+++ b/erpnext/education/doctype/assessment_group/test_assessment_group.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Assessment Group')
diff --git a/erpnext/education/doctype/assessment_plan/assessment_plan.py b/erpnext/education/doctype/assessment_plan/assessment_plan.py
index 16136c19f71..2a58a313cdd 100644
--- a/erpnext/education/doctype/assessment_plan/assessment_plan.py
+++ b/erpnext/education/doctype/assessment_plan/assessment_plan.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe.model.document import Document
+
import frappe
from frappe import _
+from frappe.model.document import Document
+
class AssessmentPlan(Document):
def validate(self):
diff --git a/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py b/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py
index 8ac3faf6dde..672953852ed 100644
--- a/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py
+++ b/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py
@@ -1,8 +1,10 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'assessment_plan',
diff --git a/erpnext/education/doctype/assessment_plan/test_assessment_plan.py b/erpnext/education/doctype/assessment_plan/test_assessment_plan.py
index 2de4f23f5b9..9a6b8860358 100644
--- a/erpnext/education/doctype/assessment_plan/test_assessment_plan.py
+++ b/erpnext/education/doctype/assessment_plan/test_assessment_plan.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Assessment Plan')
diff --git a/erpnext/education/doctype/assessment_plan_criteria/assessment_plan_criteria.py b/erpnext/education/doctype/assessment_plan_criteria/assessment_plan_criteria.py
index 53b477f700a..795462d6308 100644
--- a/erpnext/education/doctype/assessment_plan_criteria/assessment_plan_criteria.py
+++ b/erpnext/education/doctype/assessment_plan_criteria/assessment_plan_criteria.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class AssessmentPlanCriteria(Document):
pass
diff --git a/erpnext/education/doctype/assessment_result/assessment_result.py b/erpnext/education/doctype/assessment_result/assessment_result.py
index 7dfe0cf6c27..01f483f8b0b 100644
--- a/erpnext/education/doctype/assessment_result/assessment_result.py
+++ b/erpnext/education/doctype/assessment_result/assessment_result.py
@@ -3,14 +3,16 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt
from frappe.model.document import Document
-from erpnext.education.api import get_grade
-from erpnext.education.api import get_assessment_details
+from frappe.utils import flt
from frappe.utils.csvutils import getlink
+
import erpnext.education
+from erpnext.education.api import get_assessment_details, get_grade
+
class AssessmentResult(Document):
def validate(self):
diff --git a/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py b/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py
index 2526076d308..f9e2008ebc7 100644
--- a/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py
+++ b/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py
@@ -1,8 +1,10 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'reports': [
diff --git a/erpnext/education/doctype/assessment_result/test_assessment_result.py b/erpnext/education/doctype/assessment_result/test_assessment_result.py
index adce57769dd..fa0ad1f692c 100644
--- a/erpnext/education/doctype/assessment_result/test_assessment_result.py
+++ b/erpnext/education/doctype/assessment_result/test_assessment_result.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
from erpnext.education.api import get_grade
# test_records = frappe.get_test_records('Assessment Result')
diff --git a/erpnext/education/doctype/assessment_result_detail/assessment_result_detail.py b/erpnext/education/doctype/assessment_result_detail/assessment_result_detail.py
index d0515931590..234dff044f5 100644
--- a/erpnext/education/doctype/assessment_result_detail/assessment_result_detail.py
+++ b/erpnext/education/doctype/assessment_result_detail/assessment_result_detail.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class AssessmentResultDetail(Document):
pass
diff --git a/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.py b/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.py
index a0d286ccbe9..83b4f5634e9 100644
--- a/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.py
+++ b/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class AssessmentResultTool(Document):
pass
diff --git a/erpnext/education/doctype/assessment_result_tool/test_assessment_result_tool.py b/erpnext/education/doctype/assessment_result_tool/test_assessment_result_tool.py
index f784ccb256b..bcc57220e78 100644
--- a/erpnext/education/doctype/assessment_result_tool/test_assessment_result_tool.py
+++ b/erpnext/education/doctype/assessment_result_tool/test_assessment_result_tool.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestAssessmentResultTool(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/content_activity/content_activity.py b/erpnext/education/doctype/content_activity/content_activity.py
index 2ae7a5c94c9..076e2d37c00 100644
--- a/erpnext/education/doctype/content_activity/content_activity.py
+++ b/erpnext/education/doctype/content_activity/content_activity.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ContentActivity(Document):
pass
diff --git a/erpnext/education/doctype/content_question/content_question.py b/erpnext/education/doctype/content_question/content_question.py
index b239d211a3f..9c2491697de 100644
--- a/erpnext/education/doctype/content_question/content_question.py
+++ b/erpnext/education/doctype/content_question/content_question.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ContentQuestion(Document):
pass
diff --git a/erpnext/education/doctype/content_question/test_content_question.js b/erpnext/education/doctype/content_question/test_content_question.js
deleted file mode 100644
index cc869a87fcf..00000000000
--- a/erpnext/education/doctype/content_question/test_content_question.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Content Question", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Content Question
- () => frappe.tests.make('Content Question', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/content_question/test_content_question.py b/erpnext/education/doctype/content_question/test_content_question.py
index 268b9be2e7a..f6bd49bb802 100644
--- a/erpnext/education/doctype/content_question/test_content_question.py
+++ b/erpnext/education/doctype/content_question/test_content_question.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestContentQuestion(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/course/course.py b/erpnext/education/doctype/course/course.py
index 92f92ed9f3e..9cc373a5fe2 100644
--- a/erpnext/education/doctype/course/course.py
+++ b/erpnext/education/doctype/course/course.py
@@ -3,10 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
-from frappe.model.document import Document
+
+import frappe
from frappe import _
+from frappe.model.document import Document
+
class Course(Document):
def validate(self):
diff --git a/erpnext/education/doctype/course/course_dashboard.py b/erpnext/education/doctype/course/course_dashboard.py
index 8de91b1c092..8eca2a13509 100644
--- a/erpnext/education/doctype/course/course_dashboard.py
+++ b/erpnext/education/doctype/course/course_dashboard.py
@@ -1,8 +1,10 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'course',
diff --git a/erpnext/education/doctype/course/test_course.py b/erpnext/education/doctype/course/test_course.py
index 4667ac45a23..dd43ef447c2 100644
--- a/erpnext/education/doctype/course/test_course.py
+++ b/erpnext/education/doctype/course/test_course.py
@@ -2,11 +2,12 @@
# Copyright (c) 2015, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals
-from erpnext.education.doctype.topic.test_topic import make_topic
-from erpnext.education.doctype.topic.test_topic import make_topic_and_linked_content
+
+import unittest
import frappe
-import unittest
+
+from erpnext.education.doctype.topic.test_topic import make_topic, make_topic_and_linked_content
# test_records = frappe.get_test_records('Course')
diff --git a/erpnext/education/doctype/course_activity/course_activity.py b/erpnext/education/doctype/course_activity/course_activity.py
index 3aa1ea0c5b3..61b51a05a16 100644
--- a/erpnext/education/doctype/course_activity/course_activity.py
+++ b/erpnext/education/doctype/course_activity/course_activity.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
class CourseActivity(Document):
def validate(self):
self.check_if_enrolled()
diff --git a/erpnext/education/doctype/course_activity/test_course_activity.js b/erpnext/education/doctype/course_activity/test_course_activity.js
deleted file mode 100644
index c89c89e5d3c..00000000000
--- a/erpnext/education/doctype/course_activity/test_course_activity.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Course Activity", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Course Activity
- () => frappe.tests.make('Course Activity', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/course_activity/test_course_activity.py b/erpnext/education/doctype/course_activity/test_course_activity.py
index 5269a6b71a3..778cefecab1 100644
--- a/erpnext/education/doctype/course_activity/test_course_activity.py
+++ b/erpnext/education/doctype/course_activity/test_course_activity.py
@@ -3,9 +3,11 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
+
class TestCourseActivity(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/course_assessment_criteria/course_assessment_criteria.py b/erpnext/education/doctype/course_assessment_criteria/course_assessment_criteria.py
index ade2a390a27..df384c53143 100644
--- a/erpnext/education/doctype/course_assessment_criteria/course_assessment_criteria.py
+++ b/erpnext/education/doctype/course_assessment_criteria/course_assessment_criteria.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class CourseAssessmentCriteria(Document):
pass
diff --git a/erpnext/education/doctype/course_content/course_content.py b/erpnext/education/doctype/course_content/course_content.py
index 0d2f85ab500..1dd08adbb01 100644
--- a/erpnext/education/doctype/course_content/course_content.py
+++ b/erpnext/education/doctype/course_content/course_content.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class CourseContent(Document):
pass
diff --git a/erpnext/education/doctype/course_content/test_course_content.js b/erpnext/education/doctype/course_content/test_course_content.js
deleted file mode 100644
index 786e67e9a37..00000000000
--- a/erpnext/education/doctype/course_content/test_course_content.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Course Content", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Course Content
- () => frappe.tests.make('Course Content', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/course_content/test_course_content.py b/erpnext/education/doctype/course_content/test_course_content.py
index 9be4b1f5ce3..320fa111f7e 100644
--- a/erpnext/education/doctype/course_content/test_course_content.py
+++ b/erpnext/education/doctype/course_content/test_course_content.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestCourseContent(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/course_enrollment/course_enrollment.py b/erpnext/education/doctype/course_enrollment/course_enrollment.py
index ce88990a70d..21e74516f89 100644
--- a/erpnext/education/doctype/course_enrollment/course_enrollment.py
+++ b/erpnext/education/doctype/course_enrollment/course_enrollment.py
@@ -3,11 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
+from functools import reduce
+
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import get_link_to_form
-from functools import reduce
+
class CourseEnrollment(Document):
def validate(self):
diff --git a/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py b/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py
index 37972fe354c..253325c586e 100644
--- a/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py
+++ b/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py
@@ -1,8 +1,10 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'enrollment',
diff --git a/erpnext/education/doctype/course_enrollment/test_course_enrollment.js b/erpnext/education/doctype/course_enrollment/test_course_enrollment.js
deleted file mode 100644
index 216cc307991..00000000000
--- a/erpnext/education/doctype/course_enrollment/test_course_enrollment.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Course Enrollment", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Course Enrollment
- () => frappe.tests.make('Course Enrollment', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/course_enrollment/test_course_enrollment.py b/erpnext/education/doctype/course_enrollment/test_course_enrollment.py
index 874bf121f47..e5feb1b7f7c 100644
--- a/erpnext/education/doctype/course_enrollment/test_course_enrollment.py
+++ b/erpnext/education/doctype/course_enrollment/test_course_enrollment.py
@@ -3,14 +3,14 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
-from erpnext.education.doctype.student.test_student import create_student
-from erpnext.education.doctype.student.test_student import get_student
-from erpnext.education.doctype.program.test_program import setup_program
from erpnext.education.doctype.course_activity.test_course_activity import make_course_activity
+from erpnext.education.doctype.program.test_program import setup_program
+from erpnext.education.doctype.student.test_student import create_student, get_student
+
class TestCourseEnrollment(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/education/doctype/course_schedule/course_schedule.py b/erpnext/education/doctype/course_schedule/course_schedule.py
index 748728d104e..38379e4c778 100644
--- a/erpnext/education/doctype/course_schedule/course_schedule.py
+++ b/erpnext/education/doctype/course_schedule/course_schedule.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
class CourseSchedule(Document):
def validate(self):
self.instructor_name = frappe.db.get_value("Instructor", self.instructor, "instructor_name")
diff --git a/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py b/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py
index 22ce7e1ec24..12a1735f4ea 100644
--- a/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py
+++ b/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py
@@ -1,8 +1,10 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'course_schedule',
diff --git a/erpnext/education/doctype/course_schedule/test_course_schedule.js b/erpnext/education/doctype/course_schedule/test_course_schedule.js
deleted file mode 100644
index 5cdb67be482..00000000000
--- a/erpnext/education/doctype/course_schedule/test_course_schedule.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Course Schedule", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Course Schedule
- () => frappe.tests.make('Course Schedule', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/course_schedule/test_course_schedule.py b/erpnext/education/doctype/course_schedule/test_course_schedule.py
index 5bb4de85846..1b45ceda484 100644
--- a/erpnext/education/doctype/course_schedule/test_course_schedule.py
+++ b/erpnext/education/doctype/course_schedule/test_course_schedule.py
@@ -3,13 +3,13 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
+import datetime
import unittest
-import datetime
-from frappe.utils import today, to_timedelta
+import frappe
+from frappe.utils import to_timedelta, today
+
from erpnext.education.utils import OverlapError
-from frappe.utils.make_random import get_random
# test_records = frappe.get_test_records('Course Schedule')
diff --git a/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.py b/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.py
index 0f2ea96a583..4f7ed368211 100644
--- a/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.py
+++ b/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.py
@@ -3,11 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import calendar
+
+import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import add_days, getdate
+
from erpnext.education.utils import OverlapError
@@ -95,7 +98,7 @@ class CourseSchedulingTool(Document):
if self.day == calendar.day_name[getdate(d.schedule_date).weekday()]:
frappe.delete_doc("Course Schedule", d.name)
rescheduled.append(d.name)
- except:
+ except Exception:
reschedule_errors.append(d.name)
return rescheduled, reschedule_errors
diff --git a/erpnext/education/doctype/course_scheduling_tool/test_course_scheduling_tool.js b/erpnext/education/doctype/course_scheduling_tool/test_course_scheduling_tool.js
deleted file mode 100644
index 4419d181167..00000000000
--- a/erpnext/education/doctype/course_scheduling_tool/test_course_scheduling_tool.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Course Scheduling Tool", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Course Scheduling Tool
- () => frappe.tests.make('Course Scheduling Tool', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/course_scheduling_tool/test_course_scheduling_tool.py b/erpnext/education/doctype/course_scheduling_tool/test_course_scheduling_tool.py
index d921f8e0e15..27379b70e1c 100644
--- a/erpnext/education/doctype/course_scheduling_tool/test_course_scheduling_tool.py
+++ b/erpnext/education/doctype/course_scheduling_tool/test_course_scheduling_tool.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestCourseSchedulingTool(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/course_topic/course_topic.py b/erpnext/education/doctype/course_topic/course_topic.py
index 2364f17a49c..11eb457b7c3 100644
--- a/erpnext/education/doctype/course_topic/course_topic.py
+++ b/erpnext/education/doctype/course_topic/course_topic.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class CourseTopic(Document):
pass
diff --git a/erpnext/education/doctype/course_topic/test_course_topic.js b/erpnext/education/doctype/course_topic/test_course_topic.js
deleted file mode 100644
index d8d154fb9c8..00000000000
--- a/erpnext/education/doctype/course_topic/test_course_topic.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Course Topic", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Course Topic
- () => frappe.tests.make('Course Topic', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/course_topic/test_course_topic.py b/erpnext/education/doctype/course_topic/test_course_topic.py
index 7ce46d28adf..0bba7f54788 100644
--- a/erpnext/education/doctype/course_topic/test_course_topic.py
+++ b/erpnext/education/doctype/course_topic/test_course_topic.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestCourseTopic(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/education_settings/education_settings.py b/erpnext/education/doctype/education_settings/education_settings.py
index 6c7e95c80da..71d13f733bd 100644
--- a/erpnext/education/doctype/education_settings/education_settings.py
+++ b/erpnext/education/doctype/education_settings/education_settings.py
@@ -3,6 +3,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
import frappe.defaults
from frappe.model.document import Document
diff --git a/erpnext/education/doctype/education_settings/test_education_settings.py b/erpnext/education/doctype/education_settings/test_education_settings.py
index 038fb6e57e1..3611cbef21a 100644
--- a/erpnext/education/doctype/education_settings/test_education_settings.py
+++ b/erpnext/education/doctype/education_settings/test_education_settings.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestEducationSettings(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/fee_category/fee_category.py b/erpnext/education/doctype/fee_category/fee_category.py
index 55234442bae..f531f8af6ee 100644
--- a/erpnext/education/doctype/fee_category/fee_category.py
+++ b/erpnext/education/doctype/fee_category/fee_category.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class FeeCategory(Document):
pass
diff --git a/erpnext/education/doctype/fee_category/test_fee_category.js b/erpnext/education/doctype/fee_category/test_fee_category.js
deleted file mode 100644
index a08ed33e8b6..00000000000
--- a/erpnext/education/doctype/fee_category/test_fee_category.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Fee Category", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Fee Category
- () => frappe.tests.make('Fee Category', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/fee_category/test_fee_category.py b/erpnext/education/doctype/fee_category/test_fee_category.py
index 48e7589a0c0..875568416f5 100644
--- a/erpnext/education/doctype/fee_category/test_fee_category.py
+++ b/erpnext/education/doctype/fee_category/test_fee_category.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Fee Category')
diff --git a/erpnext/education/doctype/fee_component/fee_component.py b/erpnext/education/doctype/fee_component/fee_component.py
index 8694610927b..dba39af5948 100644
--- a/erpnext/education/doctype/fee_component/fee_component.py
+++ b/erpnext/education/doctype/fee_component/fee_component.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class FeeComponent(Document):
pass
diff --git a/erpnext/education/doctype/fee_schedule/fee_schedule.py b/erpnext/education/doctype/fee_schedule/fee_schedule.py
index 0b025c75347..6bf46671790 100644
--- a/erpnext/education/doctype/fee_schedule/fee_schedule.py
+++ b/erpnext/education/doctype/fee_schedule/fee_schedule.py
@@ -3,13 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+
+import frappe
+from frappe import _
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
-from frappe.utils import money_in_words
-from frappe.utils import cint, flt, cstr
+from frappe.utils import cint, cstr, flt, money_in_words
from frappe.utils.background_jobs import enqueue
-from frappe import _
+
+import erpnext
class FeeSchedule(Document):
diff --git a/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py b/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py
index 4d7da21ea17..34f870578fd 100644
--- a/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py
+++ b/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py
@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
def get_data():
return {
'fieldname': 'fee_schedule',
diff --git a/erpnext/education/doctype/fee_schedule/test_fee_schedule.js b/erpnext/education/doctype/fee_schedule/test_fee_schedule.js
deleted file mode 100644
index d495b4ce7b1..00000000000
--- a/erpnext/education/doctype/fee_schedule/test_fee_schedule.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Fee Schedule", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially('Fee Schedule', [
- // insert a new Fee Schedule
- () => frappe.tests.make([
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/fee_schedule/test_fee_schedule.py b/erpnext/education/doctype/fee_schedule/test_fee_schedule.py
index 44e0756d64d..86b74de3421 100644
--- a/erpnext/education/doctype/fee_schedule/test_fee_schedule.py
+++ b/erpnext/education/doctype/fee_schedule/test_fee_schedule.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestFeeSchedule(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/fee_schedule_program/fee_schedule_program.py b/erpnext/education/doctype/fee_schedule_program/fee_schedule_program.py
index 11d56973808..5e9ed61ba82 100644
--- a/erpnext/education/doctype/fee_schedule_program/fee_schedule_program.py
+++ b/erpnext/education/doctype/fee_schedule_program/fee_schedule_program.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class FeeScheduleProgram(Document):
pass
diff --git a/erpnext/education/doctype/fee_schedule_student_group/fee_schedule_student_group.py b/erpnext/education/doctype/fee_schedule_student_group/fee_schedule_student_group.py
index 776534d6faf..ba30a91516f 100644
--- a/erpnext/education/doctype/fee_schedule_student_group/fee_schedule_student_group.py
+++ b/erpnext/education/doctype/fee_schedule_student_group/fee_schedule_student_group.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class FeeScheduleStudentGroup(Document):
pass
diff --git a/erpnext/education/doctype/fee_structure/fee_structure.py b/erpnext/education/doctype/fee_structure/fee_structure.py
index 9755717ee94..a6cc7019215 100644
--- a/erpnext/education/doctype/fee_structure/fee_structure.py
+++ b/erpnext/education/doctype/fee_structure/fee_structure.py
@@ -3,6 +3,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
diff --git a/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py b/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py
index fdf7df7aa26..c053b4ea4ba 100644
--- a/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py
+++ b/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py
@@ -1,8 +1,10 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'fee_structure',
diff --git a/erpnext/education/doctype/fee_structure/test_fee_structure.js b/erpnext/education/doctype/fee_structure/test_fee_structure.js
deleted file mode 100644
index 61f41354c34..00000000000
--- a/erpnext/education/doctype/fee_structure/test_fee_structure.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Fee Structure", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Fee Structure
- () => frappe.tests.make('Fee Structure', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/fee_structure/test_fee_structure.py b/erpnext/education/doctype/fee_structure/test_fee_structure.py
index 785ae4e7d37..1311f13997e 100644
--- a/erpnext/education/doctype/fee_structure/test_fee_structure.py
+++ b/erpnext/education/doctype/fee_structure/test_fee_structure.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Fee Structure')
diff --git a/erpnext/education/doctype/fees/fees.py b/erpnext/education/doctype/fees/fees.py
index 7e867049047..a5dc0dca31c 100644
--- a/erpnext/education/doctype/fees/fees.py
+++ b/erpnext/education/doctype/fees/fees.py
@@ -3,14 +3,16 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe.model.document import Document
-import frappe, erpnext
+
+import frappe
from frappe import _
from frappe.utils import money_in_words
-from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
from frappe.utils.csvutils import getlink
-from erpnext.controllers.accounts_controller import AccountsController
+
+import erpnext
+from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
from erpnext.accounts.general_ledger import make_reverse_gl_entries
+from erpnext.controllers.accounts_controller import AccountsController
class Fees(AccountsController):
diff --git a/erpnext/education/doctype/fees/test_fees.py b/erpnext/education/doctype/fees/test_fees.py
index c6bb704b412..fbf7a571fe8 100644
--- a/erpnext/education/doctype/fees/test_fees.py
+++ b/erpnext/education/doctype/fees/test_fees.py
@@ -3,10 +3,12 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
from frappe.utils import nowdate
from frappe.utils.make_random import get_random
+
from erpnext.education.doctype.program.test_program import make_program_and_linked_courses
test_dependencies = ['Company']
diff --git a/erpnext/education/doctype/grading_scale/grading_scale.py b/erpnext/education/doctype/grading_scale/grading_scale.py
index 0e732971619..ed75f31d841 100644
--- a/erpnext/education/doctype/grading_scale/grading_scale.py
+++ b/erpnext/education/doctype/grading_scale/grading_scale.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import cint
from frappe.model.document import Document
+from frappe.utils import cint
+
class GradingScale(Document):
def validate(self):
diff --git a/erpnext/education/doctype/grading_scale/grading_scale_dashboard.py b/erpnext/education/doctype/grading_scale/grading_scale_dashboard.py
index 2a3f13b156d..268871a04e8 100644
--- a/erpnext/education/doctype/grading_scale/grading_scale_dashboard.py
+++ b/erpnext/education/doctype/grading_scale/grading_scale_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'grading_scale',
diff --git a/erpnext/education/doctype/grading_scale/test_grading_scale.py b/erpnext/education/doctype/grading_scale/test_grading_scale.py
index 5364d7c8879..e5d83c20c12 100644
--- a/erpnext/education/doctype/grading_scale/test_grading_scale.py
+++ b/erpnext/education/doctype/grading_scale/test_grading_scale.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Grading Scale')
diff --git a/erpnext/education/doctype/grading_scale_interval/grading_scale_interval.py b/erpnext/education/doctype/grading_scale_interval/grading_scale_interval.py
index 41ac5ffd5c0..6e55aac40ba 100644
--- a/erpnext/education/doctype/grading_scale_interval/grading_scale_interval.py
+++ b/erpnext/education/doctype/grading_scale_interval/grading_scale_interval.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class GradingScaleInterval(Document):
pass
diff --git a/erpnext/education/doctype/guardian/guardian.py b/erpnext/education/doctype/guardian/guardian.py
index e82cc546af4..f79e1310345 100644
--- a/erpnext/education/doctype/guardian/guardian.py
+++ b/erpnext/education/doctype/guardian/guardian.py
@@ -3,11 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils.csvutils import getlink
+
class Guardian(Document):
def __setup__(self):
self.onload()
diff --git a/erpnext/education/doctype/guardian/test_guardian.py b/erpnext/education/doctype/guardian/test_guardian.py
index 61420f6cec5..446e2612215 100644
--- a/erpnext/education/doctype/guardian/test_guardian.py
+++ b/erpnext/education/doctype/guardian/test_guardian.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Guardian')
diff --git a/erpnext/education/doctype/guardian_interest/guardian_interest.py b/erpnext/education/doctype/guardian_interest/guardian_interest.py
index f5c4cf1d49c..4a3040f0600 100644
--- a/erpnext/education/doctype/guardian_interest/guardian_interest.py
+++ b/erpnext/education/doctype/guardian_interest/guardian_interest.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class GuardianInterest(Document):
pass
diff --git a/erpnext/education/doctype/guardian_student/guardian_student.py b/erpnext/education/doctype/guardian_student/guardian_student.py
index bf6f5c13730..62867d89089 100644
--- a/erpnext/education/doctype/guardian_student/guardian_student.py
+++ b/erpnext/education/doctype/guardian_student/guardian_student.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class GuardianStudent(Document):
pass
diff --git a/erpnext/education/doctype/instructor/instructor.py b/erpnext/education/doctype/instructor/instructor.py
index b1bfcbb2f10..92fb8b04b90 100644
--- a/erpnext/education/doctype/instructor/instructor.py
+++ b/erpnext/education/doctype/instructor/instructor.py
@@ -3,11 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.model.naming import set_name_by_naming_series
+
class Instructor(Document):
def autoname(self):
naming_method = frappe.db.get_value("Education Settings", None, "instructor_created_by")
diff --git a/erpnext/education/doctype/instructor/instructor_dashboard.py b/erpnext/education/doctype/instructor/instructor_dashboard.py
index c19c85947d6..bb08a54903c 100644
--- a/erpnext/education/doctype/instructor/instructor_dashboard.py
+++ b/erpnext/education/doctype/instructor/instructor_dashboard.py
@@ -1,8 +1,10 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'heatmap': True,
diff --git a/erpnext/education/doctype/instructor/test_instructor.py b/erpnext/education/doctype/instructor/test_instructor.py
index 4061422a74d..b698a20e111 100644
--- a/erpnext/education/doctype/instructor/test_instructor.py
+++ b/erpnext/education/doctype/instructor/test_instructor.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Instructor')
diff --git a/erpnext/education/doctype/instructor_log/instructor_log.py b/erpnext/education/doctype/instructor_log/instructor_log.py
index 75217b22f67..68ab7a639e9 100644
--- a/erpnext/education/doctype/instructor_log/instructor_log.py
+++ b/erpnext/education/doctype/instructor_log/instructor_log.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class InstructorLog(Document):
pass
diff --git a/erpnext/education/doctype/options/options.py b/erpnext/education/doctype/options/options.py
index a11d77afb23..a064384129b 100644
--- a/erpnext/education/doctype/options/options.py
+++ b/erpnext/education/doctype/options/options.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class Options(Document):
pass
diff --git a/erpnext/education/doctype/program/program.py b/erpnext/education/doctype/program/program.py
index 9d886b7b9e6..7de34cf30fb 100644
--- a/erpnext/education/doctype/program/program.py
+++ b/erpnext/education/doctype/program/program.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class Program(Document):
def get_course_list(self):
diff --git a/erpnext/education/doctype/program/program_dashboard.py b/erpnext/education/doctype/program/program_dashboard.py
index 6c503e1bf1f..66960767f16 100644
--- a/erpnext/education/doctype/program/program_dashboard.py
+++ b/erpnext/education/doctype/program/program_dashboard.py
@@ -1,5 +1,6 @@
from frappe import _
+
def get_data():
return {
'fieldname': 'program',
diff --git a/erpnext/education/doctype/program/test_program.py b/erpnext/education/doctype/program/test_program.py
index 204f2961e7f..3222aa6004b 100644
--- a/erpnext/education/doctype/program/test_program.py
+++ b/erpnext/education/doctype/program/test_program.py
@@ -2,12 +2,13 @@
# Copyright (c) 2015, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals
-from erpnext.education.doctype.course.test_course import make_course
-from erpnext.education.doctype.topic.test_topic import make_topic_and_linked_content
-from erpnext.education.doctype.course.test_course import make_course_and_linked_topic
+
+import unittest
import frappe
-import unittest
+
+from erpnext.education.doctype.course.test_course import make_course, make_course_and_linked_topic
+from erpnext.education.doctype.topic.test_topic import make_topic_and_linked_content
test_data = {
"program_name": "_Test Program",
diff --git a/erpnext/education/doctype/program_course/program_course.py b/erpnext/education/doctype/program_course/program_course.py
index 684b6fade76..d5236a109a4 100644
--- a/erpnext/education/doctype/program_course/program_course.py
+++ b/erpnext/education/doctype/program_course/program_course.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ProgramCourse(Document):
pass
diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment.py b/erpnext/education/doctype/program_enrollment/program_enrollment.py
index dd4aa576ac0..79c5a14d8c8 100644
--- a/erpnext/education/doctype/program_enrollment/program_enrollment.py
+++ b/erpnext/education/doctype/program_enrollment/program_enrollment.py
@@ -3,12 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import msgprint, _
+from frappe import _, msgprint
+from frappe.desk.reportview import get_match_cond
from frappe.model.document import Document
-from frappe.desk.reportview import get_match_cond, get_filters_cond
from frappe.utils import comma_and, get_link_to_form, getdate
-import erpnext.www.lms as lms
+
class ProgramEnrollment(Document):
def validate(self):
diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py b/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py
index c47f8666898..f829276dac9 100644
--- a/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py
+++ b/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'program_enrollment',
diff --git a/erpnext/education/doctype/program_enrollment/test_program_enrollment.js b/erpnext/education/doctype/program_enrollment/test_program_enrollment.js
deleted file mode 100644
index aea81a0714e..00000000000
--- a/erpnext/education/doctype/program_enrollment/test_program_enrollment.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Program Enrollment", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Program Enrollment
- () => frappe.tests.make('Program Enrollment', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/program_enrollment/test_program_enrollment.py b/erpnext/education/doctype/program_enrollment/test_program_enrollment.py
index 497ee288aac..65de38af2dd 100644
--- a/erpnext/education/doctype/program_enrollment/test_program_enrollment.py
+++ b/erpnext/education/doctype/program_enrollment/test_program_enrollment.py
@@ -3,13 +3,13 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from erpnext.education.doctype.student.test_student import create_student
-from erpnext.education.doctype.student.test_student import get_student
+import frappe
+
from erpnext.education.doctype.program.test_program import make_program_and_linked_courses
-from erpnext.education.doctype.course_activity.test_course_activity import make_course_activity
+from erpnext.education.doctype.student.test_student import create_student, get_student
+
class TestProgramEnrollment(unittest.TestCase):
diff --git a/erpnext/education/doctype/program_enrollment_course/program_enrollment_course.py b/erpnext/education/doctype/program_enrollment_course/program_enrollment_course.py
index e1f564eff0f..5c0706dbce1 100644
--- a/erpnext/education/doctype/program_enrollment_course/program_enrollment_course.py
+++ b/erpnext/education/doctype/program_enrollment_course/program_enrollment_course.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ProgramEnrollmentCourse(Document):
pass
diff --git a/erpnext/education/doctype/program_enrollment_fee/program_enrollment_fee.py b/erpnext/education/doctype/program_enrollment_fee/program_enrollment_fee.py
index 03a311e1640..53bae7c1504 100644
--- a/erpnext/education/doctype/program_enrollment_fee/program_enrollment_fee.py
+++ b/erpnext/education/doctype/program_enrollment_fee/program_enrollment_fee.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ProgramEnrollmentFee(Document):
pass
diff --git a/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py b/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py
index 5833b67f9bb..69fa66558d3 100644
--- a/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py
+++ b/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
-from erpnext.education.api import enroll_student
from frappe.utils import cint
+from erpnext.education.api import enroll_student
+
+
class ProgramEnrollmentTool(Document):
def onload(self):
academic_term_reqd = cint(frappe.db.get_single_value('Education Settings', 'academic_term_reqd'))
diff --git a/erpnext/education/doctype/program_enrollment_tool/test_program_enrollment_tool.js b/erpnext/education/doctype/program_enrollment_tool/test_program_enrollment_tool.js
deleted file mode 100644
index 8d55104a0f3..00000000000
--- a/erpnext/education/doctype/program_enrollment_tool/test_program_enrollment_tool.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Program Enrollment Tool", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Program Enrollment Tool
- () => frappe.tests.make('Program Enrollment Tool', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/program_enrollment_tool/test_program_enrollment_tool.py b/erpnext/education/doctype/program_enrollment_tool/test_program_enrollment_tool.py
index f22b3b1c8d4..55734cbc94b 100644
--- a/erpnext/education/doctype/program_enrollment_tool/test_program_enrollment_tool.py
+++ b/erpnext/education/doctype/program_enrollment_tool/test_program_enrollment_tool.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestProgramEnrollmentTool(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/program_enrollment_tool_student/program_enrollment_tool_student.py b/erpnext/education/doctype/program_enrollment_tool_student/program_enrollment_tool_student.py
index 38dc1c8437a..67653458f5f 100644
--- a/erpnext/education/doctype/program_enrollment_tool_student/program_enrollment_tool_student.py
+++ b/erpnext/education/doctype/program_enrollment_tool_student/program_enrollment_tool_student.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ProgramEnrollmentToolStudent(Document):
pass
diff --git a/erpnext/education/doctype/program_fee/program_fee.py b/erpnext/education/doctype/program_fee/program_fee.py
index cadcc4eeb80..70105ee6be9 100644
--- a/erpnext/education/doctype/program_fee/program_fee.py
+++ b/erpnext/education/doctype/program_fee/program_fee.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ProgramFee(Document):
pass
diff --git a/erpnext/education/doctype/question/question.py b/erpnext/education/doctype/question/question.py
index fb3b50478c8..e74aa93ad8e 100644
--- a/erpnext/education/doctype/question/question.py
+++ b/erpnext/education/doctype/question/question.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
class Question(Document):
def validate(self):
diff --git a/erpnext/education/doctype/question/test_question.js b/erpnext/education/doctype/question/test_question.js
deleted file mode 100644
index 509939c6b56..00000000000
--- a/erpnext/education/doctype/question/test_question.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Question", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Question
- () => frappe.tests.make('Question', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/question/test_question.py b/erpnext/education/doctype/question/test_question.py
index 552872e15fb..1ce10c0cb83 100644
--- a/erpnext/education/doctype/question/test_question.py
+++ b/erpnext/education/doctype/question/test_question.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestQuestion(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/quiz/quiz.py b/erpnext/education/doctype/quiz/quiz.py
index a128e1f3427..474bea111b9 100644
--- a/erpnext/education/doctype/quiz/quiz.py
+++ b/erpnext/education/doctype/quiz/quiz.py
@@ -3,11 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-import json
from frappe import _
from frappe.model.document import Document
+
class Quiz(Document):
def validate(self):
if self.passing_score > 100:
diff --git a/erpnext/education/doctype/quiz/test_quiz.js b/erpnext/education/doctype/quiz/test_quiz.js
deleted file mode 100644
index 147d13952ab..00000000000
--- a/erpnext/education/doctype/quiz/test_quiz.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Quiz", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Quiz
- () => frappe.tests.make('Quiz', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/quiz/test_quiz.py b/erpnext/education/doctype/quiz/test_quiz.py
index 344fd544ee8..22eb23d4fda 100644
--- a/erpnext/education/doctype/quiz/test_quiz.py
+++ b/erpnext/education/doctype/quiz/test_quiz.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestQuiz(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/quiz_activity/quiz_activity.py b/erpnext/education/doctype/quiz_activity/quiz_activity.py
index 24c7175397d..0fc76032283 100644
--- a/erpnext/education/doctype/quiz_activity/quiz_activity.py
+++ b/erpnext/education/doctype/quiz_activity/quiz_activity.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class QuizActivity(Document):
pass
diff --git a/erpnext/education/doctype/quiz_activity/test_quiz_activity.js b/erpnext/education/doctype/quiz_activity/test_quiz_activity.js
deleted file mode 100644
index 94b5ab796ac..00000000000
--- a/erpnext/education/doctype/quiz_activity/test_quiz_activity.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Quiz Activity", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Quiz Activity
- () => frappe.tests.make('Quiz Activity', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/quiz_activity/test_quiz_activity.py b/erpnext/education/doctype/quiz_activity/test_quiz_activity.py
index fb0425d8096..44e3a3f92ba 100644
--- a/erpnext/education/doctype/quiz_activity/test_quiz_activity.py
+++ b/erpnext/education/doctype/quiz_activity/test_quiz_activity.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestQuizActivity(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/quiz_question/quiz_question.py b/erpnext/education/doctype/quiz_question/quiz_question.py
index 317e75b2cb2..20cb9f7b38c 100644
--- a/erpnext/education/doctype/quiz_question/quiz_question.py
+++ b/erpnext/education/doctype/quiz_question/quiz_question.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class QuizQuestion(Document):
pass
diff --git a/erpnext/education/doctype/quiz_result/quiz_result.py b/erpnext/education/doctype/quiz_result/quiz_result.py
index a4fd9f062f3..059d294cff6 100644
--- a/erpnext/education/doctype/quiz_result/quiz_result.py
+++ b/erpnext/education/doctype/quiz_result/quiz_result.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class QuizResult(Document):
pass
diff --git a/erpnext/education/doctype/quiz_result/test_quiz_result.js b/erpnext/education/doctype/quiz_result/test_quiz_result.js
deleted file mode 100644
index 43f53a1dc77..00000000000
--- a/erpnext/education/doctype/quiz_result/test_quiz_result.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Quiz Result", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Quiz Result
- () => frappe.tests.make('Quiz Result', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/quiz_result/test_quiz_result.py b/erpnext/education/doctype/quiz_result/test_quiz_result.py
index 86ee52d87d3..08ac4811bca 100644
--- a/erpnext/education/doctype/quiz_result/test_quiz_result.py
+++ b/erpnext/education/doctype/quiz_result/test_quiz_result.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestQuizResult(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/room/room.py b/erpnext/education/doctype/room/room.py
index f26e9c4b45b..dc68a0dd0cf 100644
--- a/erpnext/education/doctype/room/room.py
+++ b/erpnext/education/doctype/room/room.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class Room(Document):
pass
diff --git a/erpnext/education/doctype/room/room_dashboard.py b/erpnext/education/doctype/room/room_dashboard.py
index 7bcb97f709f..6a43b6037f8 100644
--- a/erpnext/education/doctype/room/room_dashboard.py
+++ b/erpnext/education/doctype/room/room_dashboard.py
@@ -1,8 +1,10 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'room',
diff --git a/erpnext/education/doctype/room/test_room.py b/erpnext/education/doctype/room/test_room.py
index 33ffd9173e1..5718d51d658 100644
--- a/erpnext/education/doctype/room/test_room.py
+++ b/erpnext/education/doctype/room/test_room.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Room')
diff --git a/erpnext/education/doctype/school_house/school_house.py b/erpnext/education/doctype/school_house/school_house.py
index 8751e5c646c..2f9c5f46a80 100644
--- a/erpnext/education/doctype/school_house/school_house.py
+++ b/erpnext/education/doctype/school_house/school_house.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class SchoolHouse(Document):
pass
diff --git a/erpnext/education/doctype/school_house/test_school_house.js b/erpnext/education/doctype/school_house/test_school_house.js
deleted file mode 100644
index dde63ecc4c6..00000000000
--- a/erpnext/education/doctype/school_house/test_school_house.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: School House", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new School House
- () => frappe.tests.make('School House', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/school_house/test_school_house.py b/erpnext/education/doctype/school_house/test_school_house.py
index 5cf96d5daa2..b58b7d49ce1 100644
--- a/erpnext/education/doctype/school_house/test_school_house.py
+++ b/erpnext/education/doctype/school_house/test_school_house.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestSchoolHouse(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/student/student.py b/erpnext/education/doctype/student/student.py
index 6be9e7104b2..ae498ba57db 100644
--- a/erpnext/education/doctype/student/student.py
+++ b/erpnext/education/doctype/student/student.py
@@ -3,12 +3,16 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
-from frappe.utils import getdate,today
from frappe import _
from frappe.desk.form.linked_with import get_linked_doctypes
+from frappe.model.document import Document
+from frappe.utils import getdate, today
+
from erpnext.education.utils import check_content_completion, check_quiz_completion
+
+
class Student(Document):
def validate(self):
self.title = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name]))
diff --git a/erpnext/education/doctype/student/student_dashboard.py b/erpnext/education/doctype/student/student_dashboard.py
index d2614628b10..efff2e64907 100644
--- a/erpnext/education/doctype/student/student_dashboard.py
+++ b/erpnext/education/doctype/student/student_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'heatmap': True,
diff --git a/erpnext/education/doctype/student/test_student.js b/erpnext/education/doctype/student/test_student.js
deleted file mode 100644
index e18d39aee07..00000000000
--- a/erpnext/education/doctype/student/test_student.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Student", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Student
- () => frappe.tests.make('Student', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/student/test_student.py b/erpnext/education/doctype/student/test_student.py
index fcb2b5fb930..ec6abb56efb 100644
--- a/erpnext/education/doctype/student/test_student.py
+++ b/erpnext/education/doctype/student/test_student.py
@@ -2,12 +2,12 @@
# Copyright (c) 2015, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals
-from frappe.test_runner import make_test_records
-from erpnext.education.doctype.program.test_program import make_program_and_linked_courses
-from erpnext.education.doctype.course.test_course import make_course
+
+import unittest
import frappe
-import unittest
+
+from erpnext.education.doctype.program.test_program import make_program_and_linked_courses
test_records = frappe.get_test_records('Student')
class TestStudent(unittest.TestCase):
diff --git a/erpnext/education/doctype/student_admission/student_admission.py b/erpnext/education/doctype/student_admission/student_admission.py
index 0febb96aebb..67ef67b4aa2 100644
--- a/erpnext/education/doctype/student_admission/student_admission.py
+++ b/erpnext/education/doctype/student_admission/student_admission.py
@@ -3,6 +3,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import nowdate
diff --git a/erpnext/education/doctype/student_admission/test_student_admission.py b/erpnext/education/doctype/student_admission/test_student_admission.py
index 748c7ae1b39..c9cfbca14a7 100644
--- a/erpnext/education/doctype/student_admission/test_student_admission.py
+++ b/erpnext/education/doctype/student_admission/test_student_admission.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Student Admission')
diff --git a/erpnext/education/doctype/student_admission_program/student_admission_program.py b/erpnext/education/doctype/student_admission_program/student_admission_program.py
index 406027ca2cb..2377d2648da 100644
--- a/erpnext/education/doctype/student_admission_program/student_admission_program.py
+++ b/erpnext/education/doctype/student_admission_program/student_admission_program.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class StudentAdmissionProgram(Document):
pass
diff --git a/erpnext/education/doctype/student_applicant/student_applicant.py b/erpnext/education/doctype/student_applicant/student_applicant.py
index 193b6d32977..36a0757531b 100644
--- a/erpnext/education/doctype/student_applicant/student_applicant.py
+++ b/erpnext/education/doctype/student_applicant/student_applicant.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import print_function, unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import getdate, add_years, nowdate, date_diff
+from frappe.utils import add_years, date_diff, getdate, nowdate
+
class StudentApplicant(Document):
def autoname(self):
diff --git a/erpnext/education/doctype/student_applicant/test_student_applicant.py b/erpnext/education/doctype/student_applicant/test_student_applicant.py
index 9734a88b935..b7258a4ae1d 100644
--- a/erpnext/education/doctype/student_applicant/test_student_applicant.py
+++ b/erpnext/education/doctype/student_applicant/test_student_applicant.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Student Applicant')
diff --git a/erpnext/education/doctype/student_attendance/student_attendance.py b/erpnext/education/doctype/student_attendance/student_attendance.py
index 2e9e6cf8d65..3826afb0492 100644
--- a/erpnext/education/doctype/student_attendance/student_attendance.py
+++ b/erpnext/education/doctype/student_attendance/student_attendance.py
@@ -3,14 +3,17 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
from frappe import _
-from frappe.utils import get_link_to_form, getdate, formatdate
+from frappe.model.document import Document
+from frappe.utils import formatdate, get_link_to_form, getdate
+
from erpnext import get_default_company
from erpnext.education.api import get_student_group_students
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
+
class StudentAttendance(Document):
def validate(self):
self.validate_mandatory()
diff --git a/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py b/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py
index e405b8aed9d..489f64d6804 100644
--- a/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py
+++ b/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'reports': [
diff --git a/erpnext/education/doctype/student_attendance/test_student_attendance.py b/erpnext/education/doctype/student_attendance/test_student_attendance.py
index 9f4153845b5..d453aeda1c6 100644
--- a/erpnext/education/doctype/student_attendance/test_student_attendance.py
+++ b/erpnext/education/doctype/student_attendance/test_student_attendance.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Student Attendance')
diff --git a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py
index 972973fbadb..96767deb6d2 100644
--- a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py
+++ b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class StudentAttendanceTool(Document):
pass
diff --git a/erpnext/education/doctype/student_attendance_tool/test_student_attendance_tool.py b/erpnext/education/doctype/student_attendance_tool/test_student_attendance_tool.py
index ffc42af4749..a94a3f235df 100644
--- a/erpnext/education/doctype/student_attendance_tool/test_student_attendance_tool.py
+++ b/erpnext/education/doctype/student_attendance_tool/test_student_attendance_tool.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestStudentAttendanceTool(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/student_batch_name/student_batch_name.py b/erpnext/education/doctype/student_batch_name/student_batch_name.py
index e6d38ea2545..ce507160e05 100644
--- a/erpnext/education/doctype/student_batch_name/student_batch_name.py
+++ b/erpnext/education/doctype/student_batch_name/student_batch_name.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class StudentBatchName(Document):
pass
diff --git a/erpnext/education/doctype/student_batch_name/test_student_batch_name.py b/erpnext/education/doctype/student_batch_name/test_student_batch_name.py
index 09534f355c9..75ebeb29b80 100644
--- a/erpnext/education/doctype/student_batch_name/test_student_batch_name.py
+++ b/erpnext/education/doctype/student_batch_name/test_student_batch_name.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Student Batch Name')
diff --git a/erpnext/education/doctype/student_category/student_category.py b/erpnext/education/doctype/student_category/student_category.py
index bd3a8358898..bb362d5834a 100644
--- a/erpnext/education/doctype/student_category/student_category.py
+++ b/erpnext/education/doctype/student_category/student_category.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class StudentCategory(Document):
pass
diff --git a/erpnext/education/doctype/student_category/student_category_dashboard.py b/erpnext/education/doctype/student_category/student_category_dashboard.py
index f31c34bd941..92386237883 100644
--- a/erpnext/education/doctype/student_category/student_category_dashboard.py
+++ b/erpnext/education/doctype/student_category/student_category_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'student_category',
diff --git a/erpnext/education/doctype/student_category/test_student_category.py b/erpnext/education/doctype/student_category/test_student_category.py
index 756cab87eb8..0893769045e 100644
--- a/erpnext/education/doctype/student_category/test_student_category.py
+++ b/erpnext/education/doctype/student_category/test_student_category.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Student Category')
diff --git a/erpnext/education/doctype/student_group/student_group.py b/erpnext/education/doctype/student_group/student_group.py
index 3d4572abf70..2347d317317 100644
--- a/erpnext/education/doctype/student_group/student_group.py
+++ b/erpnext/education/doctype/student_group/student_group.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
from frappe import _
-from erpnext.education.utils import validate_duplicate_student
+from frappe.model.document import Document
from frappe.utils import cint
+from erpnext.education.utils import validate_duplicate_student
+
+
class StudentGroup(Document):
def validate(self):
self.validate_mandatory_fields()
diff --git a/erpnext/education/doctype/student_group/student_group_dashboard.py b/erpnext/education/doctype/student_group/student_group_dashboard.py
index d37445f7b98..36329bd8d85 100644
--- a/erpnext/education/doctype/student_group/student_group_dashboard.py
+++ b/erpnext/education/doctype/student_group/student_group_dashboard.py
@@ -1,8 +1,10 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'student_group',
diff --git a/erpnext/education/doctype/student_group/test_student_group.py b/erpnext/education/doctype/student_group/test_student_group.py
index 8b9b47d9ceb..06022511e5b 100644
--- a/erpnext/education/doctype/student_group/test_student_group.py
+++ b/erpnext/education/doctype/student_group/test_student_group.py
@@ -3,10 +3,13 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
+
import erpnext.education
+
def get_random_group():
doc = frappe.get_doc({
"doctype": "Student Group",
diff --git a/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.py b/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.py
index 28ff7d618c1..2007f8aa7cc 100644
--- a/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.py
+++ b/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.py
@@ -3,11 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
from erpnext.education.doctype.student_group.student_group import get_students
+
class StudentGroupCreationTool(Document):
@frappe.whitelist()
def get_courses(self):
diff --git a/erpnext/education/doctype/student_group_creation_tool/test_student_group_creation_tool.py b/erpnext/education/doctype/student_group_creation_tool/test_student_group_creation_tool.py
index 9ca56588f2c..432da090134 100644
--- a/erpnext/education/doctype/student_group_creation_tool/test_student_group_creation_tool.py
+++ b/erpnext/education/doctype/student_group_creation_tool/test_student_group_creation_tool.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestStudentGroupCreationTool(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.py b/erpnext/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.py
index b3411ea7c55..b9d1e0d7fe7 100644
--- a/erpnext/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.py
+++ b/erpnext/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class StudentGroupCreationToolCourse(Document):
pass
diff --git a/erpnext/education/doctype/student_group_instructor/student_group_instructor.py b/erpnext/education/doctype/student_group_instructor/student_group_instructor.py
index b6cc588b673..81a7ed25af5 100644
--- a/erpnext/education/doctype/student_group_instructor/student_group_instructor.py
+++ b/erpnext/education/doctype/student_group_instructor/student_group_instructor.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class StudentGroupInstructor(Document):
pass
diff --git a/erpnext/education/doctype/student_group_student/student_group_student.py b/erpnext/education/doctype/student_group_student/student_group_student.py
index 1fe4ea1dc35..7ee4caec5e3 100644
--- a/erpnext/education/doctype/student_group_student/student_group_student.py
+++ b/erpnext/education/doctype/student_group_student/student_group_student.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class StudentGroupStudent(Document):
pass
diff --git a/erpnext/education/doctype/student_guardian/student_guardian.py b/erpnext/education/doctype/student_guardian/student_guardian.py
index 04445bcc594..56d7df7d0a8 100644
--- a/erpnext/education/doctype/student_guardian/student_guardian.py
+++ b/erpnext/education/doctype/student_guardian/student_guardian.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class StudentGuardian(Document):
pass
diff --git a/erpnext/education/doctype/student_language/student_language.py b/erpnext/education/doctype/student_language/student_language.py
index be6d5debe4b..6ec0b1fc6e1 100644
--- a/erpnext/education/doctype/student_language/student_language.py
+++ b/erpnext/education/doctype/student_language/student_language.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class StudentLanguage(Document):
pass
diff --git a/erpnext/education/doctype/student_language/test_student_language.js b/erpnext/education/doctype/student_language/test_student_language.js
deleted file mode 100644
index 9b25569961a..00000000000
--- a/erpnext/education/doctype/student_language/test_student_language.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Student Language", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Student Language
- () => frappe.tests.make('Student Language', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/student_language/test_student_language.py b/erpnext/education/doctype/student_language/test_student_language.py
index 592b94a4fc2..1d7c003ae5e 100644
--- a/erpnext/education/doctype/student_language/test_student_language.py
+++ b/erpnext/education/doctype/student_language/test_student_language.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Student Language')
diff --git a/erpnext/education/doctype/student_leave_application/student_leave_application.py b/erpnext/education/doctype/student_leave_application/student_leave_application.py
index ef670124c31..50c14aae22b 100644
--- a/erpnext/education/doctype/student_leave_application/student_leave_application.py
+++ b/erpnext/education/doctype/student_leave_application/student_leave_application.py
@@ -3,13 +3,17 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
+from datetime import timedelta
+
import frappe
from frappe import _
-from datetime import timedelta
-from frappe.utils import get_link_to_form, getdate, date_diff, flt
-from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
-from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
from frappe.model.document import Document
+from frappe.utils import date_diff, flt, get_link_to_form, getdate
+
+from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
+from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
+
class StudentLeaveApplication(Document):
def validate(self):
diff --git a/erpnext/education/doctype/student_leave_application/student_leave_application_dashboard.py b/erpnext/education/doctype/student_leave_application/student_leave_application_dashboard.py
index 0ff6d1a76ea..2674f5415d9 100644
--- a/erpnext/education/doctype/student_leave_application/student_leave_application_dashboard.py
+++ b/erpnext/education/doctype/student_leave_application/student_leave_application_dashboard.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+
def get_data():
return {
'fieldname': 'leave_application',
diff --git a/erpnext/education/doctype/student_leave_application/test_student_leave_application.py b/erpnext/education/doctype/student_leave_application/test_student_leave_application.py
index 9cae2577481..506dc738d88 100644
--- a/erpnext/education/doctype/student_leave_application/test_student_leave_application.py
+++ b/erpnext/education/doctype/student_leave_application/test_student_leave_application.py
@@ -3,12 +3,15 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import getdate, add_days, add_months
+
+import frappe
+from frappe.utils import add_days, add_months, getdate
+
from erpnext import get_default_company
-from erpnext.education.doctype.student_group.test_student_group import get_random_group
from erpnext.education.doctype.student.test_student import create_student
+from erpnext.education.doctype.student_group.test_student_group import get_random_group
+
class TestStudentLeaveApplication(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/education/doctype/student_log/student_log.py b/erpnext/education/doctype/student_log/student_log.py
index 8b12886863c..2ca49ca12d3 100644
--- a/erpnext/education/doctype/student_log/student_log.py
+++ b/erpnext/education/doctype/student_log/student_log.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class StudentLog(Document):
pass
diff --git a/erpnext/education/doctype/student_log/test_student_log.py b/erpnext/education/doctype/student_log/test_student_log.py
index 1fe191fe955..533191f3b47 100644
--- a/erpnext/education/doctype/student_log/test_student_log.py
+++ b/erpnext/education/doctype/student_log/test_student_log.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Student Log')
diff --git a/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.py b/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.py
index 17bc3678266..1cf79213150 100644
--- a/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.py
+++ b/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.py
@@ -3,13 +3,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, json
+
+import json
+
+import frappe
from frappe import _
from frappe.model.document import Document
-from erpnext.education.api import get_grade
from frappe.utils.pdf import get_pdf
-from erpnext.education.report.course_wise_assessment_report.course_wise_assessment_report import get_formatted_result
-from erpnext.education.report.course_wise_assessment_report.course_wise_assessment_report import get_child_assessment_groups
+
+from erpnext.education.report.course_wise_assessment_report.course_wise_assessment_report import (
+ get_child_assessment_groups,
+ get_formatted_result,
+)
class StudentReportGenerationTool(Document):
diff --git a/erpnext/education/doctype/student_report_generation_tool/test_student_report_generation_tool.js b/erpnext/education/doctype/student_report_generation_tool/test_student_report_generation_tool.js
deleted file mode 100644
index 10be092bb92..00000000000
--- a/erpnext/education/doctype/student_report_generation_tool/test_student_report_generation_tool.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Student Report Generation Tool", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Student Report Generation Tool
- () => frappe.tests.make('Student Report Generation Tool', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/student_report_generation_tool/test_student_report_generation_tool.py b/erpnext/education/doctype/student_report_generation_tool/test_student_report_generation_tool.py
index 417816642ec..f6227136d9d 100644
--- a/erpnext/education/doctype/student_report_generation_tool/test_student_report_generation_tool.py
+++ b/erpnext/education/doctype/student_report_generation_tool/test_student_report_generation_tool.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestStudentReportGenerationTool(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/student_sibling/student_sibling.py b/erpnext/education/doctype/student_sibling/student_sibling.py
index 4adc3f35bae..b36cf59dbb3 100644
--- a/erpnext/education/doctype/student_sibling/student_sibling.py
+++ b/erpnext/education/doctype/student_sibling/student_sibling.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class StudentSibling(Document):
pass
diff --git a/erpnext/education/doctype/student_siblings/student_siblings.py b/erpnext/education/doctype/student_siblings/student_siblings.py
index 4e20d84ae71..412cf050c16 100644
--- a/erpnext/education/doctype/student_siblings/student_siblings.py
+++ b/erpnext/education/doctype/student_siblings/student_siblings.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class StudentSiblings(Document):
pass
diff --git a/erpnext/education/doctype/topic/test_topic.js b/erpnext/education/doctype/topic/test_topic.js
deleted file mode 100644
index 4460b794786..00000000000
--- a/erpnext/education/doctype/topic/test_topic.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Topic", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Topic
- () => frappe.tests.make('Topic', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/topic/test_topic.py b/erpnext/education/doctype/topic/test_topic.py
index d03db1cb93a..b6c6c7516fa 100644
--- a/erpnext/education/doctype/topic/test_topic.py
+++ b/erpnext/education/doctype/topic/test_topic.py
@@ -3,9 +3,11 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
+
class TestTopic(unittest.TestCase):
def setUp(self):
make_topic_and_linked_content("_Test Topic 1", [{"type":"Article", "name": "_Test Article 1"}])
diff --git a/erpnext/education/doctype/topic/topic.py b/erpnext/education/doctype/topic/topic.py
index fb680d725b0..1834b2e060c 100644
--- a/erpnext/education/doctype/topic/topic.py
+++ b/erpnext/education/doctype/topic/topic.py
@@ -3,11 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
+
+import frappe
from frappe import _
from frappe.model.document import Document
+
class Topic(Document):
def get_contents(self):
try:
diff --git a/erpnext/education/doctype/topic_content/test_topic_content.js b/erpnext/education/doctype/topic_content/test_topic_content.js
deleted file mode 100644
index bf9a62d0376..00000000000
--- a/erpnext/education/doctype/topic_content/test_topic_content.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Topic Content", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Topic Content
- () => frappe.tests.make('Topic Content', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/education/doctype/topic_content/test_topic_content.py b/erpnext/education/doctype/topic_content/test_topic_content.py
index cf304f60bc3..6fdcbdae717 100644
--- a/erpnext/education/doctype/topic_content/test_topic_content.py
+++ b/erpnext/education/doctype/topic_content/test_topic_content.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestTopicContent(unittest.TestCase):
pass
diff --git a/erpnext/education/doctype/topic_content/topic_content.py b/erpnext/education/doctype/topic_content/topic_content.py
index 9b2c90bb4f2..9339bbde5aa 100644
--- a/erpnext/education/doctype/topic_content/topic_content.py
+++ b/erpnext/education/doctype/topic_content/topic_content.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class TopicContent(Document):
pass
diff --git a/erpnext/education/report/absent_student_report/absent_student_report.py b/erpnext/education/report/absent_student_report/absent_student_report.py
index c3487ccaffb..d5b66757fcd 100644
--- a/erpnext/education/report/absent_student_report/absent_student_report.py
+++ b/erpnext/education/report/absent_student_report/absent_student_report.py
@@ -2,12 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+from frappe import _, msgprint
from frappe.utils import formatdate
-from frappe import msgprint, _
+
from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/education/report/assessment_plan_status/assessment_plan_status.py b/erpnext/education/report/assessment_plan_status/assessment_plan_status.py
index 21184a637ca..64ceb42731a 100644
--- a/erpnext/education/report/assessment_plan_status/assessment_plan_status.py
+++ b/erpnext/education/report/assessment_plan_status/assessment_plan_status.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
+from itertools import groupby
+
import frappe
from frappe import _
-from itertools import groupby
from frappe.utils import cint
DOCSTATUS = {
diff --git a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py
index 1043e5bd45b..ad07ee1949c 100644
--- a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py
+++ b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py
@@ -2,10 +2,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
+from collections import OrderedDict, defaultdict
+
import frappe
from frappe import _
-from frappe.utils import flt
-from collections import defaultdict, OrderedDict
+
from erpnext.education.api import get_grade
diff --git a/erpnext/education/report/final_assessment_grades/final_assessment_grades.py b/erpnext/education/report/final_assessment_grades/final_assessment_grades.py
index e6e0ba2ebc2..ae7f34b5e1c 100644
--- a/erpnext/education/report/final_assessment_grades/final_assessment_grades.py
+++ b/erpnext/education/report/final_assessment_grades/final_assessment_grades.py
@@ -2,12 +2,16 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe import _
+
from collections import defaultdict
-from erpnext.education.report.course_wise_assessment_report.course_wise_assessment_report import get_formatted_result
-from erpnext.education.report.course_wise_assessment_report.course_wise_assessment_report import get_chart_data
+import frappe
+from frappe import _
+
+from erpnext.education.report.course_wise_assessment_report.course_wise_assessment_report import (
+ get_chart_data,
+ get_formatted_result,
+)
def execute(filters=None):
diff --git a/erpnext/education/report/program_wise_fee_collection/program_wise_fee_collection.py b/erpnext/education/report/program_wise_fee_collection/program_wise_fee_collection.py
index c0ec0357cc6..1717ed55aec 100644
--- a/erpnext/education/report/program_wise_fee_collection/program_wise_fee_collection.py
+++ b/erpnext/education/report/program_wise_fee_collection/program_wise_fee_collection.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
if not filters:
filters = {}
diff --git a/erpnext/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py b/erpnext/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py
index 5bebd4385c6..a21a93686ef 100644
--- a/erpnext/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py
+++ b/erpnext/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py
@@ -2,6 +2,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
diff --git a/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py b/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py
index e2576a0c710..b65350f1b22 100644
--- a/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py
+++ b/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py
@@ -2,12 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+from frappe import _, msgprint
from frappe.utils import formatdate
-from frappe import msgprint, _
+
from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py b/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
index 04dc8c0e563..f6d9c5a012e 100644
--- a/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
+++ b/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
@@ -2,14 +2,16 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import cstr, cint, getdate, get_first_day, get_last_day, date_diff, add_days
-from frappe import msgprint, _
-from calendar import monthrange
+from frappe import _
+from frappe.utils import add_days, cstr, date_diff, get_first_day, get_last_day, getdate
+
from erpnext.education.api import get_student_group_students
from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
from erpnext.support.doctype.issue.issue import get_holidays
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/education/setup.py b/erpnext/education/setup.py
index 5c4092849a7..faa4e39b400 100644
--- a/erpnext/education/setup.py
+++ b/erpnext/education/setup.py
@@ -5,6 +5,7 @@
from __future__ import unicode_literals
import frappe
+
from erpnext.setup.utils import insert_record
diff --git a/erpnext/education/utils.py b/erpnext/education/utils.py
index 3070e6a3e8a..33394e17963 100644
--- a/erpnext/education/utils.py
+++ b/erpnext/education/utils.py
@@ -1,10 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and contributors
-from __future__ import unicode_literals, division
+from __future__ import division, unicode_literals
+
import frappe
from frappe import _
+
class OverlapError(frappe.ValidationError): pass
def validate_overlap_for(doc, doctype, fieldname, value=None):
@@ -219,7 +221,7 @@ def get_quiz(quiz_name, course):
try:
quiz = frappe.get_doc("Quiz", quiz_name)
questions = quiz.get_questions()
- except:
+ except Exception:
frappe.throw(_("Quiz {0} does not exist").format(quiz_name), frappe.DoesNotExistError)
return None
diff --git a/erpnext/education/web_form/student_applicant/student_applicant.py b/erpnext/education/web_form/student_applicant/student_applicant.py
index 2334f8b26d8..f57de916dd1 100644
--- a/erpnext/education/web_form/student_applicant/student_applicant.py
+++ b/erpnext/education/web_form/student_applicant/student_applicant.py
@@ -1,6 +1,5 @@
from __future__ import unicode_literals
-import frappe
def get_context(context):
# do your magic here
diff --git a/erpnext/erpnext_integrations/connectors/github_connection.py b/erpnext/erpnext_integrations/connectors/github_connection.py
index ab7708df305..1d3fced1201 100644
--- a/erpnext/erpnext_integrations/connectors/github_connection.py
+++ b/erpnext/erpnext_integrations/connectors/github_connection.py
@@ -1,8 +1,10 @@
from __future__ import unicode_literals
+
import frappe
from frappe.data_migration.doctype.data_migration_connector.connectors.base import BaseConnection
from github import Github
+
class GithubConnection(BaseConnection):
def __init__(self, connector):
self.connector = connector
diff --git a/erpnext/erpnext_integrations/connectors/shopify_connection.py b/erpnext/erpnext_integrations/connectors/shopify_connection.py
index 912674ff1a2..ff91b09f18e 100644
--- a/erpnext/erpnext_integrations/connectors/shopify_connection.py
+++ b/erpnext/erpnext_integrations/connectors/shopify_connection.py
@@ -1,14 +1,26 @@
from __future__ import unicode_literals
+
+import json
+
import frappe
from frappe import _
-import json
-from frappe.utils import cstr, cint, nowdate, getdate, flt, get_request_session, get_datetime
+from frappe.utils import cint, cstr, flt, get_datetime, get_request_session, getdate, nowdate
+
+from erpnext.erpnext_integrations.doctype.shopify_log.shopify_log import (
+ dump_request_data,
+ make_shopify_log,
+)
+from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings import (
+ get_header,
+ get_shopify_url,
+)
+from erpnext.erpnext_integrations.doctype.shopify_settings.sync_customer import create_customer
+from erpnext.erpnext_integrations.doctype.shopify_settings.sync_product import (
+ sync_item_from_shopify,
+)
from erpnext.erpnext_integrations.utils import validate_webhooks_request
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note, make_sales_invoice
-from erpnext.erpnext_integrations.doctype.shopify_settings.sync_product import sync_item_from_shopify
-from erpnext.erpnext_integrations.doctype.shopify_settings.sync_customer import create_customer
-from erpnext.erpnext_integrations.doctype.shopify_log.shopify_log import make_shopify_log, dump_request_data
-from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings import get_shopify_url, get_header
+
@frappe.whitelist(allow_guest=True)
@validate_webhooks_request("Shopify Settings", 'X-Shopify-Hmac-Sha256', secret_key='shared_secret')
diff --git a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
index a505ee09d28..192ec147e36 100644
--- a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
+++ b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
@@ -1,8 +1,15 @@
from __future__ import unicode_literals
-import frappe, base64, hashlib, hmac, json
-from frappe.utils import cstr
+
+import base64
+import hashlib
+import hmac
+import json
+
+import frappe
from frappe import _
+from frappe.utils import cstr
+
def verify_request():
woocommerce_settings = frappe.get_doc("Woocommerce Settings")
diff --git a/erpnext/erpnext_integrations/data_migration_mapping/issue_to_task/__init__.py b/erpnext/erpnext_integrations/data_migration_mapping/issue_to_task/__init__.py
index aeb5352a220..5a4a57c2e25 100644
--- a/erpnext/erpnext_integrations/data_migration_mapping/issue_to_task/__init__.py
+++ b/erpnext/erpnext_integrations/data_migration_mapping/issue_to_task/__init__.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def pre_process(issue):
project = frappe.db.get_value('Project', filters={'project_name': issue.milestone})
diff --git a/erpnext/erpnext_integrations/data_migration_mapping/milestone_to_project/__init__.py b/erpnext/erpnext_integrations/data_migration_mapping/milestone_to_project/__init__.py
index 9d3f02eaaf6..bab8031e024 100644
--- a/erpnext/erpnext_integrations/data_migration_mapping/milestone_to_project/__init__.py
+++ b/erpnext/erpnext_integrations/data_migration_mapping/milestone_to_project/__init__.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+
def pre_process(milestone):
return {
'title': milestone.title,
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py
index 148c1a6a166..c21453a5c53 100644
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py
+++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py
@@ -3,10 +3,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, time, dateutil, math, csv
-from six import StringIO
-import erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_mws_api as mws
+
+import csv
+import math
+import time
+
+import dateutil
+import frappe
from frappe import _
+from six import StringIO
+
+import erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_mws_api as mws
+
#Get and Create Products
def get_products_details():
@@ -143,7 +151,6 @@ def create_item_code(amazon_item_json, sku):
item.description = amazon_item_json.Product.AttributeSets.ItemAttributes.Title
item.brand = new_brand
item.manufacturer = new_manufacturer
- item.web_long_description = amazon_item_json.Product.AttributeSets.ItemAttributes.Title
item.image = amazon_item_json.Product.AttributeSets.ItemAttributes.SmallImage.URL
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py
index 7fd3b34fd5d..652fa9200d9 100755
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py
+++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py
@@ -6,24 +6,24 @@
# Extended to include finances object
from __future__ import unicode_literals
-import urllib
-from urllib.parse import quote
+import base64
import hashlib
import hmac
-import base64
-import six
-from erpnext.erpnext_integrations.doctype.amazon_mws_settings import xml_utils
import re
+from urllib.parse import quote
+
+from erpnext.erpnext_integrations.doctype.amazon_mws_settings import xml_utils
+
try:
from xml.etree.ElementTree import ParseError as XMLError
except ImportError:
from xml.parsers.expat import ExpatError as XMLError
-from time import strftime, gmtime
+
+from time import gmtime, strftime
from requests import request
from requests.exceptions import HTTPError
-
__all__ = [
'Feeds',
'Inventory',
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py
index 9c598401492..ac59eb7925c 100644
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py
+++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
+
import dateutil
+import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+from frappe.model.document import Document
+
from erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_methods import get_orders
+
class AmazonMWSSettings(Document):
def validate(self):
if self.enable_amazon == 1:
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.js b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.js
deleted file mode 100644
index 9c8990986e2..00000000000
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Amazon MWS Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Amazon MWS Settings
- () => frappe.tests.make('Amazon MWS Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.py
index 7b40014c521..844df59576a 100644
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.py
+++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestAmazonMWSSettings(unittest.TestCase):
pass
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py
index 99ede8f31de..88ef64d307c 100644
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py
+++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py
@@ -8,8 +8,8 @@ Borrowed from https://github.com/timotheus/ebaysdk-python
"""
from __future__ import unicode_literals
-import xml.etree.ElementTree as ET
import re
+import xml.etree.ElementTree as ET
class object_dict(dict):
@@ -88,7 +88,7 @@ class xml2dict(object):
ns = http://cs.sfsu.edu/csc867/myscheduler
name = patients
"""
- result = re.compile("\{(.*)\}(.*)").search(tag)
+ result = re.compile(r"\{(.*)\}(.*)").search(tag)
if result:
value.namespace, tag = result.groups()
diff --git a/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py b/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py
index bff928c1c96..f1314fc122f 100644
--- a/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py
+++ b/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe.model.document import Document
-import requests
+
import frappe
+import requests
from frappe import _
+from frappe.model.document import Document
+
class ExotelSettings(Document):
def validate(self):
diff --git a/erpnext/erpnext_integrations/doctype/gocardless_mandate/gocardless_mandate.py b/erpnext/erpnext_integrations/doctype/gocardless_mandate/gocardless_mandate.py
index 9c9df653145..b416ce8808f 100644
--- a/erpnext/erpnext_integrations/doctype/gocardless_mandate/gocardless_mandate.py
+++ b/erpnext/erpnext_integrations/doctype/gocardless_mandate/gocardless_mandate.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class GoCardlessMandate(Document):
pass
diff --git a/erpnext/erpnext_integrations/doctype/gocardless_mandate/test_gocardless_mandate.js b/erpnext/erpnext_integrations/doctype/gocardless_mandate/test_gocardless_mandate.js
deleted file mode 100644
index caa9399eb6c..00000000000
--- a/erpnext/erpnext_integrations/doctype/gocardless_mandate/test_gocardless_mandate.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: GoCardless Mandate", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new GoCardless Mandate
- () => frappe.tests.make('GoCardless Mandate', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/erpnext_integrations/doctype/gocardless_mandate/test_gocardless_mandate.py b/erpnext/erpnext_integrations/doctype/gocardless_mandate/test_gocardless_mandate.py
index d77a352cdb1..1b76ee5afc7 100644
--- a/erpnext/erpnext_integrations/doctype/gocardless_mandate/test_gocardless_mandate.py
+++ b/erpnext/erpnext_integrations/doctype/gocardless_mandate/test_gocardless_mandate.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestGoCardlessMandate(unittest.TestCase):
pass
diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py
index 25784a5620a..d003edb9b0e 100644
--- a/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py
+++ b/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py
@@ -3,10 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-import json
-import hmac
+
import hashlib
+import hmac
+import json
+
+import frappe
+
@frappe.whitelist(allow_guest=True)
def webhooks():
diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py
index c65e3cefeeb..6484973106a 100644
--- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py
+++ b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py
@@ -3,13 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
import gocardless_pro
from frappe import _
+from frappe.integrations.utils import create_payment_gateway, create_request_log
+from frappe.model.document import Document
+from frappe.utils import call_hook_method, cint, flt, get_url
from six.moves.urllib.parse import urlencode
-from frappe.utils import get_url, call_hook_method, flt, cint
-from frappe.integrations.utils import create_request_log, create_payment_gateway
+
class GoCardlessSettings(Document):
supported_currencies = ["EUR", "DKK", "GBP", "SEK"]
diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.js b/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.js
deleted file mode 100644
index b6daad8de48..00000000000
--- a/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: GoCardless Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new GoCardless Settings
- () => frappe.tests.make('GoCardless Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py
index e377f3482cb..b17aef50986 100644
--- a/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py
+++ b/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestGoCardlessSettings(unittest.TestCase):
pass
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py
index d1adeeee072..6d46a1c884a 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py
@@ -1,7 +1,9 @@
import base64
+import datetime
+
import requests
from requests.auth import HTTPBasicAuth
-import datetime
+
class MpesaConnector():
def __init__(self, env="sandbox", app_key=None, app_secret=None, sandbox_url="https://sandbox.safaricom.co.ke",
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_custom_fields.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_custom_fields.py
index 139e2fb192b..368139b872f 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_custom_fields.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_custom_fields.py
@@ -1,6 +1,7 @@
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
def create_custom_pos_fields():
"""Create custom fields corresponding to POS Settings and POS Invoice."""
pos_field = {
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
index de933578613..4ce85e58a61 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
@@ -4,17 +4,21 @@
from __future__ import unicode_literals
-from json import loads, dumps
+
+from json import dumps, loads
import frappe
-from frappe.model.document import Document
from frappe import _
-from frappe.utils import call_hook_method, fmt_money
-from frappe.integrations.utils import create_request_log, create_payment_gateway
-from frappe.utils import get_request_site_address
-from erpnext.erpnext_integrations.utils import create_mode_of_payment
+from frappe.integrations.utils import create_payment_gateway, create_request_log
+from frappe.model.document import Document
+from frappe.utils import call_hook_method, fmt_money, get_request_site_address
+
from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_connector import MpesaConnector
-from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_custom_fields import create_custom_pos_fields
+from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_custom_fields import (
+ create_custom_pos_fields,
+)
+from erpnext.erpnext_integrations.utils import create_mode_of_payment
+
class MpesaSettings(Document):
supported_currencies = ["KES"]
@@ -39,7 +43,9 @@ class MpesaSettings(Document):
for i, amount in enumerate(request_amounts):
args.request_amount = amount
if frappe.flags.in_test:
- from erpnext.erpnext_integrations.doctype.mpesa_settings.test_mpesa_settings import get_payment_request_response_payload
+ from erpnext.erpnext_integrations.doctype.mpesa_settings.test_mpesa_settings import (
+ get_payment_request_response_payload,
+ )
response = frappe._dict(get_payment_request_response_payload(amount))
else:
response = frappe._dict(generate_stk_push(**args))
@@ -71,7 +77,9 @@ class MpesaSettings(Document):
)
if frappe.flags.in_test:
- from erpnext.erpnext_integrations.doctype.mpesa_settings.test_mpesa_settings import get_test_account_balance_response
+ from erpnext.erpnext_integrations.doctype.mpesa_settings.test_mpesa_settings import (
+ get_test_account_balance_response,
+ )
response = frappe._dict(get_test_account_balance_response())
else:
response = frappe._dict(get_account_balance(payload))
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
index d4cb6b982bb..de81b821321 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
@@ -2,13 +2,20 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
-from json import dumps
-import frappe
+
import unittest
-from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_settings import process_balance_info, verify_transaction
+from json import dumps
+
+import frappe
+
from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
+from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_settings import (
+ process_balance_info,
+ verify_transaction,
+)
from erpnext.erpnext_integrations.utils import create_mode_of_payment
+
class TestMpesaSettings(unittest.TestCase):
def setUp(self):
# create payment gateway in setup
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
index 73f5927df40..d4cf56af6b2 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
@@ -2,12 +2,11 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
+import frappe
import plaid
import requests
-from plaid.errors import APIError, ItemError, InvalidRequestError
-
-import frappe
from frappe import _
+from plaid.errors import APIError, InvalidRequestError, ItemError
class PlaidConnector():
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
index eddcb3401f6..d2748c2faad 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
@@ -5,15 +5,16 @@
import json
import frappe
-from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
-from erpnext.erpnext_integrations.doctype.plaid_settings.plaid_connector import PlaidConnector
from frappe import _
from frappe.desk.doctype.tag.tag import add_tag
from frappe.model.document import Document
from frappe.utils import add_months, formatdate, getdate, today
-
from plaid.errors import ItemError
+from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
+from erpnext.erpnext_integrations.doctype.plaid_settings.plaid_connector import PlaidConnector
+
+
class PlaidSettings(Document):
@staticmethod
@frappe.whitelist()
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.js b/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.js
deleted file mode 100644
index dc91347336d..00000000000
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Plaid Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Plaid Settings
- () => frappe.tests.make('Plaid Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py
index e2243eabde0..32b5b8f2657 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py
@@ -6,11 +6,16 @@ import json
import unittest
import frappe
+from frappe.utils.response import json_handler
+
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
from erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings import (
- add_account_subtype, add_account_type, add_bank_accounts,
- new_bank_transaction, get_plaid_configuration)
-from frappe.utils.response import json_handler
+ add_account_subtype,
+ add_account_type,
+ add_bank_accounts,
+ get_plaid_configuration,
+ new_bank_transaction,
+)
class TestPlaidSettings(unittest.TestCase):
diff --git a/erpnext/erpnext_integrations/doctype/quickbooks_migrator/quickbooks_migrator.py b/erpnext/erpnext_integrations/doctype/quickbooks_migrator/quickbooks_migrator.py
index 866ea662788..39b9bb232e0 100644
--- a/erpnext/erpnext_integrations/doctype/quickbooks_migrator/quickbooks_migrator.py
+++ b/erpnext/erpnext_integrations/doctype/quickbooks_migrator/quickbooks_migrator.py
@@ -3,15 +3,19 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
+import json
+import traceback
+
import frappe
+import requests
from frappe import _
from frappe.model.document import Document
from requests_oauthlib import OAuth2Session
-import json
-import requests
-import traceback
+
from erpnext import encode_company_abbr
+
# QuickBooks requires a redirect URL, User will be redirect to this URL
# This will be a GET request
# Request parameters will have two parameters `code` and `realmId`
@@ -253,8 +257,9 @@ class QuickBooksMigrator(Document):
try:
# Assumes that exactly one fiscal year has been created so far
# Creates fiscal years till oldest ledger entry date is covered
- from frappe.utils.data import add_years, getdate
from itertools import chain
+
+ from frappe.utils.data import add_years, getdate
smallest_ledger_entry_date = getdate(min(entry["date"] for entry in chain(*self.gl_entries.values()) if entry["date"]))
oldest_fiscal_year = frappe.get_all("Fiscal Year",
fields=["year_start_date", "year_end_date"],
diff --git a/erpnext/erpnext_integrations/doctype/quickbooks_migrator/test_quickbooks_migrator.js b/erpnext/erpnext_integrations/doctype/quickbooks_migrator/test_quickbooks_migrator.js
deleted file mode 100644
index b71d7048076..00000000000
--- a/erpnext/erpnext_integrations/doctype/quickbooks_migrator/test_quickbooks_migrator.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: QuickBooks Migrator", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new QuickBooks Migrator
- () => frappe.tests.make('QuickBooks Migrator', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/erpnext_integrations/doctype/quickbooks_migrator/test_quickbooks_migrator.py b/erpnext/erpnext_integrations/doctype/quickbooks_migrator/test_quickbooks_migrator.py
index 6ce7c92ae8e..5604b40d140 100644
--- a/erpnext/erpnext_integrations/doctype/quickbooks_migrator/test_quickbooks_migrator.py
+++ b/erpnext/erpnext_integrations/doctype/quickbooks_migrator/test_quickbooks_migrator.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestQuickBooksMigrator(unittest.TestCase):
pass
diff --git a/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.py b/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.py
index a2b6af99b21..b000c831947 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.py
@@ -3,11 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
+
+import frappe
from frappe.model.document import Document
+
from erpnext.erpnext_integrations.utils import get_webhook_address
+
class ShopifyLog(Document):
pass
diff --git a/erpnext/erpnext_integrations/doctype/shopify_log/test_shopify_log.py b/erpnext/erpnext_integrations/doctype/shopify_log/test_shopify_log.py
index 5892e1d6c4e..53d37224452 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_log/test_shopify_log.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_log/test_shopify_log.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Shopify Log')
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
index 381c5e5dec4..8844148ee71 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
@@ -3,15 +3,19 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
+
+import frappe
from frappe import _
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.model.document import Document
from frappe.utils import get_request_session
from requests.exceptions import HTTPError
-from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
-from erpnext.erpnext_integrations.utils import get_webhook_address
+
from erpnext.erpnext_integrations.doctype.shopify_log.shopify_log import make_shopify_log
+from erpnext.erpnext_integrations.utils import get_webhook_address
+
class ShopifySettings(Document):
def validate(self):
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py
index 2af57f4c891..8b188516c22 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def create_customer(shopify_customer, shopify_settings):
import frappe.utils.nestedset
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py
index 16efb6caee1..86054634014 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py
@@ -1,9 +1,14 @@
from __future__ import unicode_literals
+
import frappe
from frappe import _
+from frappe.utils import cint, cstr, get_request_session
+
from erpnext import get_default_company
-from frappe.utils import cstr, cint, get_request_session
-from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings import get_shopify_url, get_header
+from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings import (
+ get_header,
+ get_shopify_url,
+)
shopify_variants_attr_list = ["option1", "option2", "option3"]
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py
index 6bec301b8e7..0e0fa6a7270 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py
@@ -2,14 +2,18 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
-import frappe
-import unittest, os, json
-from frappe.utils import cstr, cint
-from erpnext.erpnext_integrations.connectors.shopify_connection import create_order
-from erpnext.erpnext_integrations.doctype.shopify_settings.sync_product import make_item
-from erpnext.erpnext_integrations.doctype.shopify_settings.sync_customer import create_customer
+import json
+import os
+import unittest
+
+import frappe
from frappe.core.doctype.data_import.data_import import import_doc
+from frappe.utils import cint, cstr
+
+from erpnext.erpnext_integrations.connectors.shopify_connection import create_order
+from erpnext.erpnext_integrations.doctype.shopify_settings.sync_customer import create_customer
+from erpnext.erpnext_integrations.doctype.shopify_settings.sync_product import make_item
class ShopifySettings(unittest.TestCase):
diff --git a/erpnext/erpnext_integrations/doctype/shopify_tax_account/shopify_tax_account.py b/erpnext/erpnext_integrations/doctype/shopify_tax_account/shopify_tax_account.py
index 74c13c0f6cc..fc7e49b1715 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_tax_account/shopify_tax_account.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_tax_account/shopify_tax_account.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ShopifyTaxAccount(Document):
pass
diff --git a/erpnext/erpnext_integrations/doctype/shopify_webhook_detail/shopify_webhook_detail.py b/erpnext/erpnext_integrations/doctype/shopify_webhook_detail/shopify_webhook_detail.py
index e127989ce34..881f45b1be9 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_webhook_detail/shopify_webhook_detail.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_webhook_detail/shopify_webhook_detail.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ShopifyWebhookDetail(Document):
pass
diff --git a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py
index 907a22333b7..e1e7f62df4e 100644
--- a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py
+++ b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py
@@ -11,19 +11,19 @@ import traceback
import zipfile
from decimal import Decimal
-from bs4 import BeautifulSoup as bs
-
import frappe
-from erpnext import encode_company_abbr
-from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts
-from erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer import unset_existing_data
-
+from bs4 import BeautifulSoup as bs
from frappe import _
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
from frappe.model.document import Document
-from frappe.model.naming import getseries, revert_series_if_last
from frappe.utils.data import format_datetime
+from erpnext import encode_company_abbr
+from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts
+from erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer import (
+ unset_existing_data,
+)
+
PRIMARY_ACCOUNT = "Primary"
VOUCHER_CHUNK_SIZE = 500
@@ -266,7 +266,7 @@ class TallyMigration(Document):
self.is_master_data_processed = 1
- except:
+ except Exception:
self.publish("Process Master Data", _("Process Failed"), -1, 5)
self.log()
@@ -302,14 +302,14 @@ class TallyMigration(Document):
try:
party_doc = frappe.get_doc(party)
party_doc.insert()
- except:
+ except Exception:
self.log(party_doc)
addresses_file = frappe.get_doc("File", {"file_url": addresses_file_url})
for address in json.loads(addresses_file.get_content()):
try:
address_doc = frappe.get_doc(address)
address_doc.insert(ignore_mandatory=True)
- except:
+ except Exception:
self.log(address_doc)
def create_items_uoms(items_file_url, uoms_file_url):
@@ -319,7 +319,7 @@ class TallyMigration(Document):
try:
uom_doc = frappe.get_doc(uom)
uom_doc.insert()
- except:
+ except Exception:
self.log(uom_doc)
items_file = frappe.get_doc("File", {"file_url": items_file_url})
@@ -327,7 +327,7 @@ class TallyMigration(Document):
try:
item_doc = frappe.get_doc(item)
item_doc.insert()
- except:
+ except Exception:
self.log(item_doc)
try:
@@ -346,7 +346,7 @@ class TallyMigration(Document):
self.is_master_data_imported = 1
frappe.db.commit()
- except:
+ except Exception:
self.publish("Import Master Data", _("Process Failed"), -1, 5)
frappe.db.rollback()
self.log()
@@ -370,7 +370,7 @@ class TallyMigration(Document):
if processed_voucher:
vouchers.append(processed_voucher)
frappe.db.commit()
- except:
+ except Exception:
frappe.db.rollback()
self.log(voucher)
return vouchers
@@ -494,7 +494,7 @@ class TallyMigration(Document):
self.is_day_book_data_processed = 1
- except:
+ except Exception:
self.publish("Process Day Book Data", _("Process Failed"), -1, 5)
self.log()
@@ -564,7 +564,7 @@ class TallyMigration(Document):
is_last = True
frappe.enqueue_doc(self.doctype, self.name, "_import_vouchers", queue="long", timeout=3600, start=index+1, total=total, is_last=is_last)
- except:
+ except Exception:
self.log()
finally:
@@ -583,7 +583,7 @@ class TallyMigration(Document):
voucher_doc.submit()
self.publish("Importing Vouchers", _("{} of {}").format(index, total), index, total)
frappe.db.commit()
- except:
+ except Exception:
frappe.db.rollback()
self.log(voucher_doc)
diff --git a/erpnext/erpnext_integrations/doctype/tally_migration/test_tally_migration.js b/erpnext/erpnext_integrations/doctype/tally_migration/test_tally_migration.js
deleted file mode 100644
index 433c5e2cda8..00000000000
--- a/erpnext/erpnext_integrations/doctype/tally_migration/test_tally_migration.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Tally Migration", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Tally Migration
- () => frappe.tests.make('Tally Migration', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/erpnext_integrations/doctype/tally_migration/test_tally_migration.py b/erpnext/erpnext_integrations/doctype/tally_migration/test_tally_migration.py
index 9f67e55ca16..aae8f6d4db0 100644
--- a/erpnext/erpnext_integrations/doctype/tally_migration/test_tally_migration.py
+++ b/erpnext/erpnext_integrations/doctype/tally_migration/test_tally_migration.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestTallyMigration(unittest.TestCase):
pass
diff --git a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py
index 7f5f0f0e7a8..9dd481747ec 100644
--- a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py
+++ b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class TaxJarSettings(Document):
pass
diff --git a/erpnext/erpnext_integrations/doctype/taxjar_settings/test_taxjar_settings.py b/erpnext/erpnext_integrations/doctype/taxjar_settings/test_taxjar_settings.py
index 7cdfd009561..c871b05642b 100644
--- a/erpnext/erpnext_integrations/doctype/taxjar_settings/test_taxjar_settings.py
+++ b/erpnext/erpnext_integrations/doctype/taxjar_settings/test_taxjar_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestTaxJarSettings(unittest.TestCase):
pass
diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.js b/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.js
deleted file mode 100644
index ea06ab2dc4e..00000000000
--- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Woocommerce Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Woocommerce Settings
- () => frappe.tests.make('Woocommerce Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.py
index 458a23fae29..3d184584361 100644
--- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.py
+++ b/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestWoocommerceSettings(unittest.TestCase):
pass
diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
index 45f261007f8..2e15fab0d3f 100644
--- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
+++ b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
@@ -3,12 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils.nestedset import get_root_of
-from frappe.model.document import Document
-from six.moves.urllib.parse import urlparse
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+from frappe.model.document import Document
+from frappe.utils.nestedset import get_root_of
+from six.moves.urllib.parse import urlparse
+
class WoocommerceSettings(Document):
def validate(self):
diff --git a/erpnext/erpnext_integrations/stripe_integration.py b/erpnext/erpnext_integrations/stripe_integration.py
index 108b4c0dd81..f0315eb7eef 100644
--- a/erpnext/erpnext_integrations/stripe_integration.py
+++ b/erpnext/erpnext_integrations/stripe_integration.py
@@ -2,11 +2,11 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
import frappe
+import stripe
from frappe import _
from frappe.integrations.utils import create_request_log
-import stripe
+
def create_stripe_subscription(gateway_controller, data):
stripe_settings = frappe.get_doc("Stripe Settings", gateway_controller)
@@ -23,31 +23,38 @@ def create_stripe_subscription(gateway_controller, data):
except Exception:
frappe.log_error(frappe.get_traceback())
return{
- "redirect_to": frappe.redirect_to_message(_('Server Error'), _("It seems that there is an issue with the server's stripe configuration. In case of failure, the amount will get refunded to your account.")),
+ "redirect_to": frappe.redirect_to_message(
+ _('Server Error'),
+ _("It seems that there is an issue with the server's stripe configuration. In case of failure, the amount will get refunded to your account.")
+ ),
"status": 401
}
def create_subscription_on_stripe(stripe_settings):
- items = []
- for payment_plan in stripe_settings.payment_plans:
- plan = frappe.db.get_value("Subscription Plan", payment_plan.plan, "payment_plan_id")
- items.append({"plan": plan, "quantity": payment_plan.qty})
+ items = []
+ for payment_plan in stripe_settings.payment_plans:
+ plan = frappe.db.get_value("Subscription Plan", payment_plan.plan, "product_price_id")
+ items.append({"price": plan, "quantity": payment_plan.qty})
- try:
- customer = stripe.Customer.create(description=stripe_settings.data.payer_name, email=stripe_settings.data.payer_email, source=stripe_settings.data.stripe_token_id)
- subscription = stripe.Subscription.create(customer=customer, items=items)
+ try:
+ customer = stripe.Customer.create(
+ source=stripe_settings.data.stripe_token_id,
+ description=stripe_settings.data.payer_name,
+ email=stripe_settings.data.payer_email
+ )
- if subscription.status == "active":
- stripe_settings.integration_request.db_set('status', 'Completed', update_modified=False)
- stripe_settings.flags.status_changed_to = "Completed"
+ subscription = stripe.Subscription.create(customer=customer, items=items)
- else:
- stripe_settings.integration_request.db_set('status', 'Failed', update_modified=False)
- frappe.log_error('Subscription N°: ' + subscription.id, 'Stripe Payment not completed')
+ if subscription.status == "active":
+ stripe_settings.integration_request.db_set('status', 'Completed', update_modified=False)
+ stripe_settings.flags.status_changed_to = "Completed"
- except Exception:
+ else:
stripe_settings.integration_request.db_set('status', 'Failed', update_modified=False)
- frappe.log_error(frappe.get_traceback())
+ frappe.log_error('Subscription N°: ' + subscription.id, 'Stripe Payment not completed')
+ except Exception:
+ stripe_settings.integration_request.db_set('status', 'Failed', update_modified=False)
+ frappe.log_error(frappe.get_traceback())
- return stripe_settings.finalize_request()
+ return stripe_settings.finalize_request()
diff --git a/erpnext/erpnext_integrations/taxjar_integration.py b/erpnext/erpnext_integrations/taxjar_integration.py
index f960998c3c9..870a4ef54cc 100644
--- a/erpnext/erpnext_integrations/taxjar_integration.py
+++ b/erpnext/erpnext_integrations/taxjar_integration.py
@@ -1,11 +1,12 @@
import traceback
-import taxjar
-
import frappe
-from erpnext import get_default_company
+import taxjar
from frappe import _
from frappe.contacts.doctype.address.address import get_company_address
+from frappe.utils import cint
+
+from erpnext import get_default_company
TAX_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "tax_account_head")
SHIP_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "shipping_account_head")
@@ -14,6 +15,10 @@ TAXJAR_CALCULATE_TAX = frappe.db.get_single_value("TaxJar Settings", "taxjar_cal
SUPPORTED_COUNTRY_CODES = ["AT", "AU", "BE", "BG", "CA", "CY", "CZ", "DE", "DK", "EE", "ES", "FI",
"FR", "GB", "GR", "HR", "HU", "IE", "IT", "LT", "LU", "LV", "MT", "NL", "PL", "PT", "RO",
"SE", "SI", "SK", "US"]
+SUPPORTED_STATE_CODES = ['AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FL', 'GA', 'HI', 'ID', 'IL',
+ 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE',
+ 'NV', 'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC', 'SD',
+ 'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY']
def get_client():
@@ -27,7 +32,11 @@ def get_client():
api_url = taxjar.SANDBOX_API_URL
if api_key and api_url:
- return taxjar.Client(api_key=api_key, api_url=api_url)
+ client = taxjar.Client(api_key=api_key, api_url=api_url)
+ client.set_api_config('headers', {
+ 'x-api-version': '2020-08-07'
+ })
+ return client
def create_transaction(doc, method):
@@ -57,7 +66,10 @@ def create_transaction(doc, method):
tax_dict['amount'] = doc.total + tax_dict['shipping']
try:
- client.create_order(tax_dict)
+ if doc.is_return:
+ client.create_refund(tax_dict)
+ else:
+ client.create_order(tax_dict)
except taxjar.exceptions.TaxJarResponseError as err:
frappe.throw(_(sanitize_error_response(err)))
except Exception as ex:
@@ -89,13 +101,15 @@ def get_tax_data(doc):
to_country_code = frappe.db.get_value("Country", to_address.country, "code")
to_country_code = to_country_code.upper()
- if to_country_code not in SUPPORTED_COUNTRY_CODES:
- return
-
shipping = sum([tax.tax_amount for tax in doc.taxes if tax.account_head == SHIP_ACCOUNT_HEAD])
- if to_shipping_state is not None:
- to_shipping_state = get_iso_3166_2_state_code(to_address)
+ line_items = [get_line_item_dict(item) for item in doc.items]
+
+ if from_shipping_state not in SUPPORTED_STATE_CODES:
+ from_shipping_state = get_state_code(from_address, 'Company')
+
+ if to_shipping_state not in SUPPORTED_STATE_CODES:
+ to_shipping_state = get_state_code(to_address, 'Shipping')
tax_dict = {
'from_country': from_country_code,
@@ -109,11 +123,29 @@ def get_tax_data(doc):
'to_street': to_address.address_line1,
'to_state': to_shipping_state,
'shipping': shipping,
- 'amount': doc.net_total
+ 'amount': doc.net_total,
+ 'plugin': 'erpnext',
+ 'line_items': line_items
}
-
return tax_dict
+def get_state_code(address, location):
+ if address is not None:
+ state_code = get_iso_3166_2_state_code(address)
+ if state_code not in SUPPORTED_STATE_CODES:
+ frappe.throw(_("Please enter a valid State in the {0} Address").format(location))
+ else:
+ frappe.throw(_("Please enter a valid State in the {0} Address").format(location))
+
+ return state_code
+
+def get_line_item_dict(item):
+ return dict(
+ id = item.get('idx'),
+ quantity = item.get('qty'),
+ unit_price = item.get('rate'),
+ product_tax_code = item.get('product_tax_category')
+ )
def set_sales_tax(doc, method):
if not TAXJAR_CALCULATE_TAX:
@@ -122,17 +154,7 @@ def set_sales_tax(doc, method):
if not doc.items:
return
- # if the party is exempt from sales tax, then set all tax account heads to zero
- sales_tax_exempted = hasattr(doc, "exempt_from_sales_tax") and doc.exempt_from_sales_tax \
- or frappe.db.has_column("Customer", "exempt_from_sales_tax") and frappe.db.get_value("Customer", doc.customer, "exempt_from_sales_tax")
-
- if sales_tax_exempted:
- for tax in doc.taxes:
- if tax.account_head == TAX_ACCOUNT_HEAD:
- tax.tax_amount = 0
- break
-
- doc.run_method("calculate_taxes_and_totals")
+ if check_sales_tax_exemption(doc):
return
tax_dict = get_tax_data(doc)
@@ -143,7 +165,6 @@ def set_sales_tax(doc, method):
return
tax_data = validate_tax_request(tax_dict)
-
if tax_data is not None:
if not tax_data.amount_to_collect:
setattr(doc, "taxes", [tax for tax in doc.taxes if tax.account_head != TAX_ACCOUNT_HEAD])
@@ -163,9 +184,28 @@ def set_sales_tax(doc, method):
"account_head": TAX_ACCOUNT_HEAD,
"tax_amount": tax_data.amount_to_collect
})
+ # Assigning values to tax_collectable and taxable_amount fields in sales item table
+ for item in tax_data.breakdown.line_items:
+ doc.get('items')[cint(item.id)-1].tax_collectable = item.tax_collectable
+ doc.get('items')[cint(item.id)-1].taxable_amount = item.taxable_amount
doc.run_method("calculate_taxes_and_totals")
+def check_sales_tax_exemption(doc):
+ # if the party is exempt from sales tax, then set all tax account heads to zero
+ sales_tax_exempted = hasattr(doc, "exempt_from_sales_tax") and doc.exempt_from_sales_tax \
+ or frappe.db.has_column("Customer", "exempt_from_sales_tax") \
+ and frappe.db.get_value("Customer", doc.customer, "exempt_from_sales_tax")
+
+ if sales_tax_exempted:
+ for tax in doc.taxes:
+ if tax.account_head == TAX_ACCOUNT_HEAD:
+ tax.tax_amount = 0
+ break
+ doc.run_method("calculate_taxes_and_totals")
+ return True
+ else:
+ return False
def validate_tax_request(tax_dict):
"""Return the sales tax that should be collected for a given order."""
@@ -200,6 +240,8 @@ def get_shipping_address_details(doc):
if doc.shipping_address_name:
shipping_address = frappe.get_doc("Address", doc.shipping_address_name)
+ elif doc.customer_address:
+ shipping_address = frappe.get_doc("Address", doc.customer_address_name)
else:
shipping_address = get_company_address_details(doc)
diff --git a/erpnext/erpnext_integrations/utils.py b/erpnext/erpnext_integrations/utils.py
index caafc0821e1..bb5c0c2dd10 100644
--- a/erpnext/erpnext_integrations/utils.py
+++ b/erpnext/erpnext_integrations/utils.py
@@ -1,10 +1,16 @@
from __future__ import unicode_literals
+
+import base64
+import hashlib
+import hmac
+
import frappe
from frappe import _
-import base64, hashlib, hmac
from six.moves.urllib.parse import urlparse
+
from erpnext import get_default_company
+
def validate_webhooks_request(doctype, hmac_key, secret_key='secret'):
def innerfn(fn):
settings = frappe.get_doc(doctype)
diff --git a/erpnext/exceptions.py b/erpnext/exceptions.py
index 04291cd5bd1..9c6b13f8035 100644
--- a/erpnext/exceptions.py
+++ b/erpnext/exceptions.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
# accounts
class PartyFrozen(frappe.ValidationError): pass
class InvalidAccountCurrency(frappe.ValidationError): pass
diff --git a/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.py b/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.py
index eca7143e689..9c71ce86ac4 100644
--- a/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.py
+++ b/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.utils.dashboard import cache_source
+
@frappe.whitelist()
@cache_source
def get(chart_name = None, chart = None, no_cache = None, filters = None, from_date = None,
diff --git a/erpnext/healthcare/doctype/antibiotic/antibiotic.py b/erpnext/healthcare/doctype/antibiotic/antibiotic.py
index 8236c8ab73a..6a4b7648b96 100644
--- a/erpnext/healthcare/doctype/antibiotic/antibiotic.py
+++ b/erpnext/healthcare/doctype/antibiotic/antibiotic.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class Antibiotic(Document):
pass
diff --git a/erpnext/healthcare/doctype/antibiotic/test_antibiotic.js b/erpnext/healthcare/doctype/antibiotic/test_antibiotic.js
deleted file mode 100644
index b92103d7509..00000000000
--- a/erpnext/healthcare/doctype/antibiotic/test_antibiotic.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Antibiotic", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Antibiotic
- () => frappe.tests.make('Antibiotic', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/antibiotic/test_antibiotic.py b/erpnext/healthcare/doctype/antibiotic/test_antibiotic.py
index 6ac4f4f9fc0..b6ec79f7ff4 100644
--- a/erpnext/healthcare/doctype/antibiotic/test_antibiotic.py
+++ b/erpnext/healthcare/doctype/antibiotic/test_antibiotic.py
@@ -2,7 +2,9 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestAntibiotic(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type.py b/erpnext/healthcare/doctype/appointment_type/appointment_type.py
index 67a24f31e03..94d023f2c3d 100644
--- a/erpnext/healthcare/doctype/appointment_type/appointment_type.py
+++ b/erpnext/healthcare/doctype/appointment_type/appointment_type.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe.model.document import Document
+
import frappe
+from frappe.model.document import Document
+
class AppointmentType(Document):
def validate(self):
diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type_dashboard.py b/erpnext/healthcare/doctype/appointment_type/appointment_type_dashboard.py
index 845e4466c11..b9c6edbb19c 100644
--- a/erpnext/healthcare/doctype/appointment_type/appointment_type_dashboard.py
+++ b/erpnext/healthcare/doctype/appointment_type/appointment_type_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'appointment_type',
diff --git a/erpnext/healthcare/doctype/appointment_type/test_appointment_type.js b/erpnext/healthcare/doctype/appointment_type/test_appointment_type.js
deleted file mode 100644
index 93274e55c7b..00000000000
--- a/erpnext/healthcare/doctype/appointment_type/test_appointment_type.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Appointment Type", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Appointment Type
- () => frappe.tests.make('Appointment Type', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.py b/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.py
index b2e0e82bad0..026d5d79fd9 100644
--- a/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.py
+++ b/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class AppointmentTypeServiceItem(Document):
pass
diff --git a/erpnext/healthcare/doctype/body_part/body_part.py b/erpnext/healthcare/doctype/body_part/body_part.py
index 300493a52b6..77e8dd90a07 100644
--- a/erpnext/healthcare/doctype/body_part/body_part.py
+++ b/erpnext/healthcare/doctype/body_part/body_part.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class BodyPart(Document):
pass
diff --git a/erpnext/healthcare/doctype/body_part/test_body_part.py b/erpnext/healthcare/doctype/body_part/test_body_part.py
index cb3a61150ef..a81ba179bfe 100644
--- a/erpnext/healthcare/doctype/body_part/test_body_part.py
+++ b/erpnext/healthcare/doctype/body_part/test_body_part.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestBodyPart(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/body_part_link/body_part_link.py b/erpnext/healthcare/doctype/body_part_link/body_part_link.py
index 03715297692..07488f01177 100644
--- a/erpnext/healthcare/doctype/body_part_link/body_part_link.py
+++ b/erpnext/healthcare/doctype/body_part_link/body_part_link.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class BodyPartLink(Document):
pass
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
index cbf89ee3bde..df4c2ef9055 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
@@ -3,15 +3,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import flt, nowdate, nowtime, cstr
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import flt, nowdate, nowtime
+
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account
from erpnext.healthcare.doctype.lab_test.lab_test import create_sample_doc
-from erpnext.stock.stock_ledger import get_previous_sle
from erpnext.stock.get_item_details import get_item_details
-from frappe.model.mapper import get_mapped_doc
+from erpnext.stock.stock_ledger import get_previous_sle
+
class ClinicalProcedure(Document):
def validate(self):
diff --git a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.js b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.js
deleted file mode 100644
index 80ef3d55f2a..00000000000
--- a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Clinical Procedure", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Clinical Procedure
- () => frappe.tests.make('Clinical Procedure', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
index 0326e5e9da7..b5c3744204a 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
@@ -4,8 +4,13 @@
from __future__ import unicode_literals
import unittest
+
import frappe
-from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_healthcare_docs, create_clinical_procedure_template
+
+from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import (
+ create_clinical_procedure_template,
+ create_healthcare_docs,
+)
test_dependencies = ['Item']
diff --git a/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.py b/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.py
index d59e5175972..16c5369cfe5 100644
--- a/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.py
+++ b/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class ClinicalProcedureItem(Document):
pass
diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py
index 58194f10a8c..16e0969ae40 100644
--- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py
+++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py
@@ -3,11 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, json
+
+import json
+
+import frappe
from frappe import _
from frappe.model.document import Document
from frappe.model.rename_doc import rename_doc
+
class ClinicalProcedureTemplate(Document):
def validate(self):
self.enable_disable_item()
diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template_dashboard.py b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template_dashboard.py
index 9aab5216e1e..a69899d3ead 100644
--- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template_dashboard.py
+++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'procedure_template',
diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/test_clinical_procedure_template.js b/erpnext/healthcare/doctype/clinical_procedure_template/test_clinical_procedure_template.js
deleted file mode 100644
index 1dde8b5d867..00000000000
--- a/erpnext/healthcare/doctype/clinical_procedure_template/test_clinical_procedure_template.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Clinical Procedure Template", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Clinical Procedure Template
- () => frappe.tests.make('Clinical Procedure Template', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/test_clinical_procedure_template.py b/erpnext/healthcare/doctype/clinical_procedure_template/test_clinical_procedure_template.py
index 62e138b8ed2..f754c76341f 100644
--- a/erpnext/healthcare/doctype/clinical_procedure_template/test_clinical_procedure_template.py
+++ b/erpnext/healthcare/doctype/clinical_procedure_template/test_clinical_procedure_template.py
@@ -2,7 +2,9 @@
# Copyright (c) 2017, earthians and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestClinicalProcedureTemplate(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/codification_table/codification_table.py b/erpnext/healthcare/doctype/codification_table/codification_table.py
index ae29c03bbbd..232d92ca9df 100644
--- a/erpnext/healthcare/doctype/codification_table/codification_table.py
+++ b/erpnext/healthcare/doctype/codification_table/codification_table.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class CodificationTable(Document):
pass
diff --git a/erpnext/healthcare/doctype/complaint/complaint.py b/erpnext/healthcare/doctype/complaint/complaint.py
index 717f9dbb4ae..20e00f6b029 100644
--- a/erpnext/healthcare/doctype/complaint/complaint.py
+++ b/erpnext/healthcare/doctype/complaint/complaint.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class Complaint(Document):
pass
diff --git a/erpnext/healthcare/doctype/complaint/test_complaint.js b/erpnext/healthcare/doctype/complaint/test_complaint.js
deleted file mode 100644
index 9ff44d8da46..00000000000
--- a/erpnext/healthcare/doctype/complaint/test_complaint.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Complaint", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Complaint
- () => frappe.tests.make('Complaint', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/complaint/test_complaint.py b/erpnext/healthcare/doctype/complaint/test_complaint.py
index 2b9273a9675..d3e10692b03 100644
--- a/erpnext/healthcare/doctype/complaint/test_complaint.py
+++ b/erpnext/healthcare/doctype/complaint/test_complaint.py
@@ -2,7 +2,9 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestComplaint(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/descriptive_test_result/descriptive_test_result.py b/erpnext/healthcare/doctype/descriptive_test_result/descriptive_test_result.py
index 7ccf6b57aa5..c08604694ab 100644
--- a/erpnext/healthcare/doctype/descriptive_test_result/descriptive_test_result.py
+++ b/erpnext/healthcare/doctype/descriptive_test_result/descriptive_test_result.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class DescriptiveTestResult(Document):
pass
diff --git a/erpnext/healthcare/doctype/descriptive_test_template/descriptive_test_template.py b/erpnext/healthcare/doctype/descriptive_test_template/descriptive_test_template.py
index 281f32db7ff..84184fbcca5 100644
--- a/erpnext/healthcare/doctype/descriptive_test_template/descriptive_test_template.py
+++ b/erpnext/healthcare/doctype/descriptive_test_template/descriptive_test_template.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class DescriptiveTestTemplate(Document):
pass
diff --git a/erpnext/healthcare/doctype/diagnosis/diagnosis.py b/erpnext/healthcare/doctype/diagnosis/diagnosis.py
index f56e79062a5..05add1b5300 100644
--- a/erpnext/healthcare/doctype/diagnosis/diagnosis.py
+++ b/erpnext/healthcare/doctype/diagnosis/diagnosis.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class Diagnosis(Document):
pass
diff --git a/erpnext/healthcare/doctype/diagnosis/test_diagnosis.js b/erpnext/healthcare/doctype/diagnosis/test_diagnosis.js
deleted file mode 100644
index cacfef5b17d..00000000000
--- a/erpnext/healthcare/doctype/diagnosis/test_diagnosis.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Diagnosis", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Diagnosis
- () => frappe.tests.make('Diagnosis', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/dosage_form/dosage_form.py b/erpnext/healthcare/doctype/dosage_form/dosage_form.py
index 046af08094c..6b2d88b61b8 100644
--- a/erpnext/healthcare/doctype/dosage_form/dosage_form.py
+++ b/erpnext/healthcare/doctype/dosage_form/dosage_form.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class DosageForm(Document):
pass
diff --git a/erpnext/healthcare/doctype/dosage_form/test_dosage_form.js b/erpnext/healthcare/doctype/dosage_form/test_dosage_form.js
deleted file mode 100644
index ba54ab16faa..00000000000
--- a/erpnext/healthcare/doctype/dosage_form/test_dosage_form.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Dosage Form", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Dosage Form
- () => frappe.tests.make('Dosage Form', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/dosage_form/test_dosage_form.py b/erpnext/healthcare/doctype/dosage_form/test_dosage_form.py
index 81cfcf6f7de..0161b82ba3b 100644
--- a/erpnext/healthcare/doctype/dosage_form/test_dosage_form.py
+++ b/erpnext/healthcare/doctype/dosage_form/test_dosage_form.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestDosageForm(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/dosage_strength/dosage_strength.py b/erpnext/healthcare/doctype/dosage_strength/dosage_strength.py
index e36a0160cf3..9e74743a7c6 100644
--- a/erpnext/healthcare/doctype/dosage_strength/dosage_strength.py
+++ b/erpnext/healthcare/doctype/dosage_strength/dosage_strength.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class DosageStrength(Document):
pass
diff --git a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json
index d91e6bf9dc6..a65c56694e7 100644
--- a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json
+++ b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json
@@ -56,6 +56,7 @@
"reqd": 1
},
{
+ "allow_in_quick_entry": 1,
"fieldname": "dosage_form",
"fieldtype": "Link",
"ignore_user_permissions": 1,
@@ -109,7 +110,7 @@
],
"istable": 1,
"links": [],
- "modified": "2020-09-30 23:32:09.495288",
+ "modified": "2021-06-11 11:53:06.343704",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Drug Prescription",
diff --git a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.py b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.py
index 68a2dc5d3c3..744bdb03ef5 100755
--- a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.py
+++ b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class DrugPrescription(Document):
def get_quantity(self):
quantity = 0
diff --git a/erpnext/healthcare/doctype/exercise/exercise.py b/erpnext/healthcare/doctype/exercise/exercise.py
index efd89997fec..5d2b1f1a96d 100644
--- a/erpnext/healthcare/doctype/exercise/exercise.py
+++ b/erpnext/healthcare/doctype/exercise/exercise.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class Exercise(Document):
pass
diff --git a/erpnext/healthcare/doctype/exercise_difficulty_level/exercise_difficulty_level.py b/erpnext/healthcare/doctype/exercise_difficulty_level/exercise_difficulty_level.py
index 17e97b89609..bbb297275f9 100644
--- a/erpnext/healthcare/doctype/exercise_difficulty_level/exercise_difficulty_level.py
+++ b/erpnext/healthcare/doctype/exercise_difficulty_level/exercise_difficulty_level.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ExerciseDifficultyLevel(Document):
pass
diff --git a/erpnext/healthcare/doctype/exercise_difficulty_level/test_exercise_difficulty_level.py b/erpnext/healthcare/doctype/exercise_difficulty_level/test_exercise_difficulty_level.py
index 80ef3a7de89..dcaea08aba3 100644
--- a/erpnext/healthcare/doctype/exercise_difficulty_level/test_exercise_difficulty_level.py
+++ b/erpnext/healthcare/doctype/exercise_difficulty_level/test_exercise_difficulty_level.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestExerciseDifficultyLevel(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/exercise_type/exercise_type.py b/erpnext/healthcare/doctype/exercise_type/exercise_type.py
index ae44a2b77b5..48eb6ba2d81 100644
--- a/erpnext/healthcare/doctype/exercise_type/exercise_type.py
+++ b/erpnext/healthcare/doctype/exercise_type/exercise_type.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ExerciseType(Document):
def autoname(self):
if self.difficulty_level:
diff --git a/erpnext/healthcare/doctype/exercise_type/test_exercise_type.py b/erpnext/healthcare/doctype/exercise_type/test_exercise_type.py
index bf217e893a6..583aea911ae 100644
--- a/erpnext/healthcare/doctype/exercise_type/test_exercise_type.py
+++ b/erpnext/healthcare/doctype/exercise_type/test_exercise_type.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestExerciseType(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/exercise_type_step/exercise_type_step.py b/erpnext/healthcare/doctype/exercise_type_step/exercise_type_step.py
index 13d7e5732f6..412ef3225ed 100644
--- a/erpnext/healthcare/doctype/exercise_type_step/exercise_type_step.py
+++ b/erpnext/healthcare/doctype/exercise_type_step/exercise_type_step.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ExerciseTypeStep(Document):
pass
diff --git a/erpnext/healthcare/doctype/fee_validity/fee_validity.py b/erpnext/healthcare/doctype/fee_validity/fee_validity.py
index 59586e0c31b..aa30becd337 100644
--- a/erpnext/healthcare/doctype/fee_validity/fee_validity.py
+++ b/erpnext/healthcare/doctype/fee_validity/fee_validity.py
@@ -3,11 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe.model.document import Document
-import frappe
-from frappe.utils import getdate
+
import datetime
+import frappe
+from frappe.model.document import Document
+from frappe.utils import getdate
+
+
class FeeValidity(Document):
def validate(self):
self.update_status()
diff --git a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.js b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.js
deleted file mode 100644
index 0ebb97438ca..00000000000
--- a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Fee Validity", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Fee Validity
- () => frappe.tests.make('Fee Validity', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py
index 957f85211de..ce1947f5bad 100644
--- a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py
+++ b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py
@@ -3,11 +3,17 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import nowdate, add_days
-from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_healthcare_docs, create_appointment, create_healthcare_service_items
+
+import frappe
+from frappe.utils import add_days, nowdate
+
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
+from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import (
+ create_appointment,
+ create_healthcare_docs,
+ create_healthcare_service_items,
+)
test_dependencies = ["Company"]
diff --git a/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.py b/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.py
index c8192808320..c03978aad11 100644
--- a/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.py
+++ b/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class FeeValidityReference(Document):
pass
diff --git a/erpnext/healthcare/doctype/healthcare.py b/erpnext/healthcare/doctype/healthcare.py
index 6fd2015fa2e..f8e008e7d38 100644
--- a/erpnext/healthcare/doctype/healthcare.py
+++ b/erpnext/healthcare/doctype/healthcare.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+
def get_data():
return []
diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py
index 5da5a0657c6..4550e7ab4c2 100644
--- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py
+++ b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py
@@ -3,13 +3,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
from frappe import _
-from erpnext.accounts.party import validate_party_accounts
-from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
+from frappe.contacts.address_and_contact import (
+ delete_contact_and_address,
+ load_address_and_contact,
+)
+from frappe.model.document import Document
from frappe.model.naming import append_number_if_name_exists
-from frappe.desk.reportview import build_match_conditions, get_filters_cond
+
+from erpnext.accounts.party import validate_party_accounts
+
class HealthcarePractitioner(Document):
def onload(self):
diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner_dashboard.py b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner_dashboard.py
index bcee44430ac..8e0292e97c2 100644
--- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner_dashboard.py
+++ b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'heatmap': True,
diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/test_healthcare_practitioner.js b/erpnext/healthcare/doctype/healthcare_practitioner/test_healthcare_practitioner.js
deleted file mode 100644
index 75aa208ec16..00000000000
--- a/erpnext/healthcare/doctype/healthcare_practitioner/test_healthcare_practitioner.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Healthcare Practitioner", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Healthcare Practitioner
- () => frappe.tests.make('Healthcare Practitioner', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/test_healthcare_practitioner.py b/erpnext/healthcare/doctype/healthcare_practitioner/test_healthcare_practitioner.py
index de8201b1517..214bcd287aa 100644
--- a/erpnext/healthcare/doctype/healthcare_practitioner/test_healthcare_practitioner.py
+++ b/erpnext/healthcare/doctype/healthcare_practitioner/test_healthcare_practitioner.py
@@ -2,7 +2,9 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestHealthcarePractitioner(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/healthcare_schedule_time_slot/healthcare_schedule_time_slot.py b/erpnext/healthcare/doctype/healthcare_schedule_time_slot/healthcare_schedule_time_slot.py
index e58ea53c2cd..721da24adc5 100644
--- a/erpnext/healthcare/doctype/healthcare_schedule_time_slot/healthcare_schedule_time_slot.py
+++ b/erpnext/healthcare/doctype/healthcare_schedule_time_slot/healthcare_schedule_time_slot.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class HealthcareScheduleTimeSlot(Document):
pass
diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py
index 5e76ed7284f..550b9fbff27 100644
--- a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py
+++ b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py
@@ -4,11 +4,12 @@
from __future__ import unicode_literals
-from frappe.utils.nestedset import NestedSet
-from frappe.utils import cint, cstr
+import json
+
import frappe
from frappe import _
-import json
+from frappe.utils import cint, cstr
+from frappe.utils.nestedset import NestedSet
class HealthcareServiceUnit(NestedSet):
diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/test_healthcare_service_unit.js b/erpnext/healthcare/doctype/healthcare_service_unit/test_healthcare_service_unit.js
deleted file mode 100644
index a67a4117073..00000000000
--- a/erpnext/healthcare/doctype/healthcare_service_unit/test_healthcare_service_unit.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Healthcare Service Unit", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Healthcare Service Unit
- () => frappe.tests.make('Healthcare Service Unit', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/test_healthcare_service_unit.py b/erpnext/healthcare/doctype/healthcare_service_unit/test_healthcare_service_unit.py
index bced2fe1f63..84197e56c56 100644
--- a/erpnext/healthcare/doctype/healthcare_service_unit/test_healthcare_service_unit.py
+++ b/erpnext/healthcare/doctype/healthcare_service_unit/test_healthcare_service_unit.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestHealthcareServiceUnit(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py
index a318e506003..181cb529fc2 100644
--- a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py
+++ b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py
@@ -3,11 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.model.rename_doc import rename_doc
+
class HealthcareServiceUnitType(Document):
def validate(self):
if self.allow_appointments and self.inpatient_occupancy:
diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type_dashboard.py b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type_dashboard.py
index 0ac548b3ffd..7421ec3b89c 100644
--- a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type_dashboard.py
+++ b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'service_unit_type',
diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.js b/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.js
deleted file mode 100644
index 6db8f9e9c1a..00000000000
--- a/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Healthcare Service Unit Type", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Healthcare Service Unit Type
- () => frappe.tests.make('Healthcare Service Unit Type', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py b/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py
index 3ee3377b004..839e1d6a4db 100644
--- a/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py
+++ b/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py
@@ -2,9 +2,12 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
import frappe
+
class TestHealthcareServiceUnitType(unittest.TestCase):
def test_item_creation(self):
unit_type = get_unit_type()
diff --git a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.py b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.py
index a16fceb74dd..9ab88817661 100644
--- a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.py
+++ b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.py
@@ -3,11 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
+import json
+
import frappe
from frappe import _
-from frappe.model.document import Document
from frappe.core.doctype.sms_settings.sms_settings import send_sms
-import json
+from frappe.model.document import Document
+
class HealthcareSettings(Document):
def validate(self):
diff --git a/erpnext/healthcare/doctype/healthcare_settings/test_healthcare_settings.js b/erpnext/healthcare/doctype/healthcare_settings/test_healthcare_settings.js
deleted file mode 100644
index ca10925e598..00000000000
--- a/erpnext/healthcare/doctype/healthcare_settings/test_healthcare_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Healthcare Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Healthcare Settings
- () => frappe.tests.make('Healthcare Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/healthcare_settings/test_healthcare_settings.py b/erpnext/healthcare/doctype/healthcare_settings/test_healthcare_settings.py
index 1b620d5f5da..af2f2b4c4f5 100644
--- a/erpnext/healthcare/doctype/healthcare_settings/test_healthcare_settings.py
+++ b/erpnext/healthcare/doctype/healthcare_settings/test_healthcare_settings.py
@@ -2,7 +2,9 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestHealthcareSettings(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py
index 3a299eda262..b28e37a9c31 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import flt, get_link_to_form, getdate, nowtime
-from erpnext.stock.utils import get_latest_stock_qty
+from frappe.utils import flt, get_link_to_form
+
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account
+from erpnext.stock.utils import get_latest_stock_qty
+
class InpatientMedicationEntry(Document):
def validate(self):
diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry_dashboard.py b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry_dashboard.py
index a4bec45596f..ca9364d66a1 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry_dashboard.py
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'against_imoe',
diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py b/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py
index 0c463ddc029..dec3b7e0ead 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py
@@ -3,14 +3,32 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
from frappe.utils import add_days, getdate, now_datetime
-from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import create_patient, create_inpatient, get_healthcare_service_unit, mark_invoiced_inpatient_occupancy
-from erpnext.healthcare.doctype.inpatient_record.inpatient_record import admit_patient, discharge_patient, schedule_discharge
-from erpnext.healthcare.doctype.inpatient_medication_order.test_inpatient_medication_order import create_ipmo, create_ipme
-from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import get_drug_shortage_map, make_difference_stock_entry
+
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account
+from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import (
+ get_drug_shortage_map,
+ make_difference_stock_entry,
+)
+from erpnext.healthcare.doctype.inpatient_medication_order.test_inpatient_medication_order import (
+ create_ipme,
+ create_ipmo,
+)
+from erpnext.healthcare.doctype.inpatient_record.inpatient_record import (
+ admit_patient,
+ discharge_patient,
+ schedule_discharge,
+)
+from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import (
+ create_inpatient,
+ create_patient,
+ get_healthcare_service_unit,
+ mark_invoiced_inpatient_occupancy,
+)
+
class TestInpatientMedicationEntry(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry_detail/inpatient_medication_entry_detail.py b/erpnext/healthcare/doctype/inpatient_medication_entry_detail/inpatient_medication_entry_detail.py
index 644898d9edc..91734312d4a 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_entry_detail/inpatient_medication_entry_detail.py
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry_detail/inpatient_medication_entry_detail.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class InpatientMedicationEntryDetail(Document):
pass
diff --git a/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.py b/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.py
index b379e98fe13..2e6d73208f7 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.py
+++ b/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import cstr
+
from erpnext.healthcare.doctype.patient_encounter.patient_encounter import get_prescription_dates
+
class InpatientMedicationOrder(Document):
def validate(self):
self.validate_inpatient()
diff --git a/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py b/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py
index ec1a28034e3..14ea1205f41 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py
+++ b/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py
@@ -3,11 +3,23 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
from frappe.utils import add_days, getdate, now_datetime
-from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import create_patient, create_inpatient, get_healthcare_service_unit, mark_invoiced_inpatient_occupancy
-from erpnext.healthcare.doctype.inpatient_record.inpatient_record import admit_patient, discharge_patient, schedule_discharge
+
+from erpnext.healthcare.doctype.inpatient_record.inpatient_record import (
+ admit_patient,
+ discharge_patient,
+ schedule_discharge,
+)
+from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import (
+ create_inpatient,
+ create_patient,
+ get_healthcare_service_unit,
+ mark_invoiced_inpatient_occupancy,
+)
+
class TestInpatientMedicationOrder(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/healthcare/doctype/inpatient_medication_order_entry/inpatient_medication_order_entry.py b/erpnext/healthcare/doctype/inpatient_medication_order_entry/inpatient_medication_order_entry.py
index ebfe366346e..15800ad15f6 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_order_entry/inpatient_medication_order_entry.py
+++ b/erpnext/healthcare/doctype/inpatient_medication_order_entry/inpatient_medication_order_entry.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class InpatientMedicationOrderEntry(Document):
pass
diff --git a/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.py b/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.py
index 52de25b4571..c8f3296d0db 100644
--- a/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.py
+++ b/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class InpatientOccupancy(Document):
pass
diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py
index 2cdfa04d5c0..9cede8a2f69 100644
--- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py
+++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py
@@ -3,11 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, json
+
+import json
+
+import frappe
from frappe import _
-from frappe.utils import today, now_datetime, getdate, get_datetime, get_link_to_form
-from frappe.model.document import Document
from frappe.desk.reportview import get_match_cond
+from frappe.model.document import Document
+from frappe.utils import get_datetime, get_link_to_form, getdate, now_datetime, today
+
class InpatientRecord(Document):
def after_insert(self):
diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record_dashboard.py b/erpnext/healthcare/doctype/inpatient_record/inpatient_record_dashboard.py
index 92cc6103f45..0f4adce4edf 100644
--- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record_dashboard.py
+++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'inpatient_record',
diff --git a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.js b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.js
deleted file mode 100644
index 1ce9afa96d4..00000000000
--- a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Inpatient Record", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Inpatient Record
- () => frappe.tests.make('Inpatient Record', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py
index 9b5cd717a0c..a778890f4a2 100644
--- a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py
+++ b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py
@@ -3,14 +3,21 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
from frappe.utils import now_datetime, today
from frappe.utils.make_random import get_random
-from erpnext.healthcare.doctype.inpatient_record.inpatient_record import admit_patient, discharge_patient, schedule_discharge
+
+from erpnext.healthcare.doctype.inpatient_record.inpatient_record import (
+ admit_patient,
+ discharge_patient,
+ schedule_discharge,
+)
from erpnext.healthcare.doctype.lab_test.test_lab_test import create_patient_encounter
from erpnext.healthcare.utils import get_encounters_to_invoice
+
class TestInpatientRecord(unittest.TestCase):
def test_admit_and_discharge(self):
frappe.db.sql("""delete from `tabInpatient Record`""")
diff --git a/erpnext/healthcare/doctype/lab_prescription/lab_prescription.py b/erpnext/healthcare/doctype/lab_prescription/lab_prescription.py
index b788a0db7e7..a3f9aa24c48 100644
--- a/erpnext/healthcare/doctype/lab_prescription/lab_prescription.py
+++ b/erpnext/healthcare/doctype/lab_prescription/lab_prescription.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class LabPrescription(Document):
pass
diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.py b/erpnext/healthcare/doctype/lab_test/lab_test.py
index 74495a85910..7db497c24d7 100644
--- a/erpnext/healthcare/doctype/lab_test/lab_test.py
+++ b/erpnext/healthcare/doctype/lab_test/lab_test.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import getdate, cstr, get_link_to_form
+from frappe.utils import get_link_to_form, getdate
+
class LabTest(Document):
def validate(self):
@@ -48,7 +50,7 @@ class LabTest(Document):
if item.result_value and item.secondary_uom and item.conversion_factor:
try:
item.secondary_uom_result = float(item.result_value) * float(item.conversion_factor)
- except:
+ except Exception:
item.secondary_uom_result = ''
frappe.msgprint(_('Row #{0}: Result for Secondary UOM not calculated').format(item.idx), title = _('Warning'))
diff --git a/erpnext/healthcare/doctype/lab_test/test_lab_test.js b/erpnext/healthcare/doctype/lab_test/test_lab_test.js
deleted file mode 100644
index 57cb22b2699..00000000000
--- a/erpnext/healthcare/doctype/lab_test/test_lab_test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Lab Test", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Lab Test
- () => frappe.tests.make('Lab Test', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/lab_test/test_lab_test.py b/erpnext/healthcare/doctype/lab_test/test_lab_test.py
index c9f0029ed80..da10bd86bdf 100644
--- a/erpnext/healthcare/doctype/lab_test/test_lab_test.py
+++ b/erpnext/healthcare/doctype/lab_test/test_lab_test.py
@@ -2,13 +2,22 @@
# Copyright (c) 2015, ESS LLP and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
import frappe
from frappe.utils import getdate, nowtime
-from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_patient
+
+from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import (
+ get_income_account,
+ get_receivable_account,
+)
from erpnext.healthcare.doctype.lab_test.lab_test import create_multiple
-from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_account
-from erpnext.healthcare.doctype.patient_medical_record.test_patient_medical_record import create_lab_test_template as create_blood_test_template
+from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_patient
+from erpnext.healthcare.doctype.patient_medical_record.test_patient_medical_record import (
+ create_lab_test_template as create_blood_test_template,
+)
+
class TestLabTest(unittest.TestCase):
def test_lab_test_item(self):
diff --git a/erpnext/healthcare/doctype/lab_test_group_template/lab_test_group_template.py b/erpnext/healthcare/doctype/lab_test_group_template/lab_test_group_template.py
index 1e2cef4e18b..2e3c4093c7c 100644
--- a/erpnext/healthcare/doctype/lab_test_group_template/lab_test_group_template.py
+++ b/erpnext/healthcare/doctype/lab_test_group_template/lab_test_group_template.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class LabTestGroupTemplate(Document):
pass
diff --git a/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.py b/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.py
index 4c66b7276b6..3a765fe2436 100644
--- a/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.py
+++ b/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class LabTestSample(Document):
pass
diff --git a/erpnext/healthcare/doctype/lab_test_sample/test_lab_test_sample.js b/erpnext/healthcare/doctype/lab_test_sample/test_lab_test_sample.js
deleted file mode 100644
index ace60de752a..00000000000
--- a/erpnext/healthcare/doctype/lab_test_sample/test_lab_test_sample.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Lab Test Sample", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Lab Test Sample
- () => frappe.tests.make('Lab Test Sample', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/lab_test_sample/test_lab_test_sample.py b/erpnext/healthcare/doctype/lab_test_sample/test_lab_test_sample.py
index 2bc56bd3241..8896572d783 100644
--- a/erpnext/healthcare/doctype/lab_test_sample/test_lab_test_sample.py
+++ b/erpnext/healthcare/doctype/lab_test_sample/test_lab_test_sample.py
@@ -2,7 +2,9 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestLabTestSample(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py
index 543dee27ebc..a75c533f947 100644
--- a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py
+++ b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py
@@ -3,10 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, json
+
+import json
+
+import frappe
+from frappe import _
from frappe.model.document import Document
from frappe.model.rename_doc import rename_doc
-from frappe import _
+
class LabTestTemplate(Document):
def after_insert(self):
@@ -27,7 +31,7 @@ class LabTestTemplate(Document):
item_price = self.item_price_exists()
if not item_price:
if self.lab_test_rate and self.lab_test_rate > 0.0:
- price_list_name = frappe.db.get_value('Price List', {'selling': 1})
+ price_list_name = frappe.db.get_value('Selling Settings', None, 'selling_price_list') or frappe.db.get_value('Price List', {'selling': 1})
make_item_price(self.lab_test_code, price_list_name, self.lab_test_rate)
else:
frappe.db.set_value('Item Price', item_price, 'price_list_rate', self.lab_test_rate)
@@ -110,7 +114,7 @@ def create_item_from_template(doc):
# Insert item price
if doc.is_billable and doc.lab_test_rate != 0.0:
- price_list_name = frappe.db.get_value('Price List', {'selling': 1})
+ price_list_name = frappe.db.get_value('Selling Settings', None, 'selling_price_list') or frappe.db.get_value('Price List', {'selling': 1})
if doc.lab_test_rate:
make_item_price(item.name, price_list_name, doc.lab_test_rate)
else:
diff --git a/erpnext/healthcare/doctype/lab_test_template/lab_test_template_dashboard.py b/erpnext/healthcare/doctype/lab_test_template/lab_test_template_dashboard.py
index 94dfeea7a42..a4f9d4b714e 100644
--- a/erpnext/healthcare/doctype/lab_test_template/lab_test_template_dashboard.py
+++ b/erpnext/healthcare/doctype/lab_test_template/lab_test_template_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'template',
diff --git a/erpnext/healthcare/doctype/lab_test_template/test_lab_test_template.js b/erpnext/healthcare/doctype/lab_test_template/test_lab_test_template.js
deleted file mode 100644
index 7c2ec8c3483..00000000000
--- a/erpnext/healthcare/doctype/lab_test_template/test_lab_test_template.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Lab Test Template", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Lab Test Template
- () => frappe.tests.make('Lab Test Template', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/lab_test_template/test_lab_test_template.py b/erpnext/healthcare/doctype/lab_test_template/test_lab_test_template.py
index 4c9f55a839e..8d8ac647500 100644
--- a/erpnext/healthcare/doctype/lab_test_template/test_lab_test_template.py
+++ b/erpnext/healthcare/doctype/lab_test_template/test_lab_test_template.py
@@ -2,6 +2,7 @@
# Copyright (c) 2015, ESS and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
# test_records = frappe.get_test_records('Lab Test Template')
diff --git a/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.py b/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.py
index 7ce8d2d1c81..ce11c0ffce3 100644
--- a/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.py
+++ b/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class LabTestUOM(Document):
pass
diff --git a/erpnext/healthcare/doctype/lab_test_uom/test_lab_test_uom.js b/erpnext/healthcare/doctype/lab_test_uom/test_lab_test_uom.js
deleted file mode 100644
index 1328dda2826..00000000000
--- a/erpnext/healthcare/doctype/lab_test_uom/test_lab_test_uom.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Lab Test UOM", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Lab Test UOM
- () => frappe.tests.make('Lab Test UOM', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/lab_test_uom/test_lab_test_uom.py b/erpnext/healthcare/doctype/lab_test_uom/test_lab_test_uom.py
index 0b3f516497d..9fe2de51a6d 100644
--- a/erpnext/healthcare/doctype/lab_test_uom/test_lab_test_uom.py
+++ b/erpnext/healthcare/doctype/lab_test_uom/test_lab_test_uom.py
@@ -2,6 +2,7 @@
# Copyright (c) 2015, ESS and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
# test_records = frappe.get_test_records('Lab Test UOM')
diff --git a/erpnext/healthcare/doctype/medical_code/medical_code.py b/erpnext/healthcare/doctype/medical_code/medical_code.py
index 0deaac38ca3..4ed3d31e907 100644
--- a/erpnext/healthcare/doctype/medical_code/medical_code.py
+++ b/erpnext/healthcare/doctype/medical_code/medical_code.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class MedicalCode(Document):
def autoname(self):
self.name = self.medical_code_standard+" "+self.code
diff --git a/erpnext/healthcare/doctype/medical_code/test_medical_code.js b/erpnext/healthcare/doctype/medical_code/test_medical_code.js
deleted file mode 100644
index 8cc7c40025c..00000000000
--- a/erpnext/healthcare/doctype/medical_code/test_medical_code.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Medical Code", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Medical Code
- () => frappe.tests.make('Medical Code', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/medical_code/test_medical_code.py b/erpnext/healthcare/doctype/medical_code/test_medical_code.py
index b1e04027907..7584b050a65 100644
--- a/erpnext/healthcare/doctype/medical_code/test_medical_code.py
+++ b/erpnext/healthcare/doctype/medical_code/test_medical_code.py
@@ -2,7 +2,9 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestMedicalCode(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/medical_code_standard/medical_code_standard.py b/erpnext/healthcare/doctype/medical_code_standard/medical_code_standard.py
index 7b2731c1def..be0ea8922ed 100644
--- a/erpnext/healthcare/doctype/medical_code_standard/medical_code_standard.py
+++ b/erpnext/healthcare/doctype/medical_code_standard/medical_code_standard.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class MedicalCodeStandard(Document):
pass
diff --git a/erpnext/healthcare/doctype/medical_code_standard/test_medical_code_standard.js b/erpnext/healthcare/doctype/medical_code_standard/test_medical_code_standard.js
deleted file mode 100644
index 6ab6d531dfb..00000000000
--- a/erpnext/healthcare/doctype/medical_code_standard/test_medical_code_standard.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Medical Code Standard", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Medical Code Standard
- () => frappe.tests.make('Medical Code Standard', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/medical_code_standard/test_medical_code_standard.py b/erpnext/healthcare/doctype/medical_code_standard/test_medical_code_standard.py
index fde095d8098..3b046e360f3 100644
--- a/erpnext/healthcare/doctype/medical_code_standard/test_medical_code_standard.py
+++ b/erpnext/healthcare/doctype/medical_code_standard/test_medical_code_standard.py
@@ -2,7 +2,9 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestMedicalCodeStandard(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/medical_department/medical_department.py b/erpnext/healthcare/doctype/medical_department/medical_department.py
index 0f2d4fc5f91..7be5a1ade34 100644
--- a/erpnext/healthcare/doctype/medical_department/medical_department.py
+++ b/erpnext/healthcare/doctype/medical_department/medical_department.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class MedicalDepartment(Document):
pass
diff --git a/erpnext/healthcare/doctype/medical_department/test_medical_department.js b/erpnext/healthcare/doctype/medical_department/test_medical_department.js
deleted file mode 100644
index fdf49718dc8..00000000000
--- a/erpnext/healthcare/doctype/medical_department/test_medical_department.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Medical Department", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Medical Department
- () => frappe.tests.make('Medical Department', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/medical_department/test_medical_department.py b/erpnext/healthcare/doctype/medical_department/test_medical_department.py
index 543750a7e7d..6435a23e928 100644
--- a/erpnext/healthcare/doctype/medical_department/test_medical_department.py
+++ b/erpnext/healthcare/doctype/medical_department/test_medical_department.py
@@ -2,6 +2,7 @@
# Copyright (c) 2015, ESS LLP and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
# test_records = frappe.get_test_records('Medical Department')
diff --git a/erpnext/healthcare/doctype/normal_test_result/normal_test_result.py b/erpnext/healthcare/doctype/normal_test_result/normal_test_result.py
index 63abf0297e7..e72f7269fc3 100644
--- a/erpnext/healthcare/doctype/normal_test_result/normal_test_result.py
+++ b/erpnext/healthcare/doctype/normal_test_result/normal_test_result.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class NormalTestResult(Document):
pass
diff --git a/erpnext/healthcare/doctype/normal_test_template/normal_test_template.py b/erpnext/healthcare/doctype/normal_test_template/normal_test_template.py
index bc2c9914846..9df48559cde 100644
--- a/erpnext/healthcare/doctype/normal_test_template/normal_test_template.py
+++ b/erpnext/healthcare/doctype/normal_test_template/normal_test_template.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class NormalTestTemplate(Document):
pass
diff --git a/erpnext/healthcare/doctype/organism/organism.py b/erpnext/healthcare/doctype/organism/organism.py
index 1ead762c2fe..dfb9c0dd0d4 100644
--- a/erpnext/healthcare/doctype/organism/organism.py
+++ b/erpnext/healthcare/doctype/organism/organism.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class Organism(Document):
pass
diff --git a/erpnext/healthcare/doctype/organism/test_organism.js b/erpnext/healthcare/doctype/organism/test_organism.js
deleted file mode 100644
index d57e5536c69..00000000000
--- a/erpnext/healthcare/doctype/organism/test_organism.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Organism", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Organism
- () => frappe.tests.make('Organism', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/organism/test_organism.py b/erpnext/healthcare/doctype/organism/test_organism.py
index ecb96650e11..9d7ea0ba33d 100644
--- a/erpnext/healthcare/doctype/organism/test_organism.py
+++ b/erpnext/healthcare/doctype/organism/test_organism.py
@@ -2,7 +2,9 @@
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestOrganism(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/organism_test_item/organism_test_item.py b/erpnext/healthcare/doctype/organism_test_item/organism_test_item.py
index 019a55b396c..6bb8e8f4c07 100644
--- a/erpnext/healthcare/doctype/organism_test_item/organism_test_item.py
+++ b/erpnext/healthcare/doctype/organism_test_item/organism_test_item.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class OrganismTestItem(Document):
pass
diff --git a/erpnext/healthcare/doctype/organism_test_result/organism_test_result.py b/erpnext/healthcare/doctype/organism_test_result/organism_test_result.py
index 02393c27004..3428403e3c0 100644
--- a/erpnext/healthcare/doctype/organism_test_result/organism_test_result.py
+++ b/erpnext/healthcare/doctype/organism_test_result/organism_test_result.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class OrganismTestResult(Document):
pass
diff --git a/erpnext/healthcare/doctype/patient/patient.py b/erpnext/healthcare/doctype/patient/patient.py
index 4c3da82a1ca..961a8be3691 100644
--- a/erpnext/healthcare/doctype/patient/patient.py
+++ b/erpnext/healthcare/doctype/patient/patient.py
@@ -3,18 +3,25 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
+import dateutil
import frappe
from frappe import _
-from frappe.model.document import Document
-from frappe.utils import cint, cstr, getdate
-import dateutil
from frappe.contacts.address_and_contact import load_address_and_contact
from frappe.contacts.doctype.contact.contact import get_default_contact
+from frappe.model.document import Document
from frappe.model.naming import set_name_by_naming_series
+from frappe.utils import cint, cstr, getdate
from frappe.utils.nestedset import get_root_of
+
from erpnext import get_default_currency
-from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_account, send_registration_sms
from erpnext.accounts.party import get_dashboard_info
+from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import (
+ get_income_account,
+ get_receivable_account,
+ send_registration_sms,
+)
+
class Patient(Document):
def onload(self):
@@ -122,13 +129,19 @@ class Patient(Document):
return name
- def get_age(self):
- age_str = ''
- if self.dob:
- dob = getdate(self.dob)
- age = dateutil.relativedelta.relativedelta(getdate(), dob)
- age_str = f'{str(age.years)} {_("Years(s)")} {str(age.months)} {_("Month(s)")} {str(age.days)} {_("Day(s)")}'
+ @property
+ def age(self):
+ if not self.dob:
+ return
+ dob = getdate(self.dob)
+ age = dateutil.relativedelta.relativedelta(getdate(), dob)
+ return age
+ def get_age(self):
+ age = self.age
+ if not age:
+ return
+ age_str = str(age.years) + ' ' + _("Years(s)") + ' ' + str(age.months) + ' ' + _("Month(s)") + ' ' + str(age.days) + ' ' + _("Day(s)")
return age_str
@frappe.whitelist()
diff --git a/erpnext/healthcare/doctype/patient/patient_dashboard.py b/erpnext/healthcare/doctype/patient/patient_dashboard.py
index 7f7cfa8e5b9..a388b74f61a 100644
--- a/erpnext/healthcare/doctype/patient/patient_dashboard.py
+++ b/erpnext/healthcare/doctype/patient/patient_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'heatmap': True,
diff --git a/erpnext/healthcare/doctype/patient/test_patient.js b/erpnext/healthcare/doctype/patient/test_patient.js
deleted file mode 100644
index e1d9ecbd242..00000000000
--- a/erpnext/healthcare/doctype/patient/test_patient.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Patient", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially('Patient', [
- // insert a new Patient
- () => frappe.tests.make([
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/patient/test_patient.py b/erpnext/healthcare/doctype/patient/test_patient.py
index 9274b6f5e85..4b8c7326468 100644
--- a/erpnext/healthcare/doctype/patient/test_patient.py
+++ b/erpnext/healthcare/doctype/patient/test_patient.py
@@ -4,9 +4,12 @@
from __future__ import unicode_literals
import unittest
+
import frappe
+
from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_patient
+
class TestPatient(unittest.TestCase):
def test_customer_created(self):
frappe.db.sql("""delete from `tabPatient`""")
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
index f0d5af93416..dcbcda09d81 100755
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
@@ -3,17 +3,28 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-import json
-from frappe.utils import getdate, get_time, flt, get_link_to_form
-from frappe.model.mapper import get_mapped_doc
-from frappe import _
+
import datetime
+import json
+
+import frappe
+from frappe import _
from frappe.core.doctype.sms_settings.sms_settings import send_sms
+from frappe.model.document import Document
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import flt, get_link_to_form, get_time, getdate
+
+from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import (
+ get_income_account,
+ get_receivable_account,
+)
+from erpnext.healthcare.utils import (
+ check_fee_validity,
+ get_service_item_and_practitioner_charge,
+ manage_fee_validity,
+)
from erpnext.hr.doctype.employee.employee import is_holiday
-from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_account
-from erpnext.healthcare.utils import check_fee_validity, get_service_item_and_practitioner_charge, manage_fee_validity
+
class MaximumCapacityError(frappe.ValidationError):
pass
@@ -100,7 +111,9 @@ class PatientAppointment(Document):
def validate_service_unit(self):
if self.inpatient_record and self.service_unit:
- from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import get_current_healthcare_service_unit
+ from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import (
+ get_current_healthcare_service_unit,
+ )
is_inpatient_occupancy_unit = frappe.db.get_value('Healthcare Service Unit', self.service_unit,
'inpatient_occupancy')
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py
index 085c4f6cbf8..43c63c96e6d 100644
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'appointment',
diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.js
deleted file mode 100644
index 71fc1778455..00000000000
--- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Patient Appointment", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Patient Appointment
- () => frappe.tests.make('Patient Appointment', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
index d0db3226326..d9c2fbfb3a7 100644
--- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
@@ -2,12 +2,19 @@
# Copyright (c) 2015, ESS LLP and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
import frappe
-from erpnext.healthcare.doctype.patient_appointment.patient_appointment import update_status, make_encounter, check_payment_fields_reqd, check_is_new_patient
-from frappe.utils import nowdate, add_days, now_datetime
-from frappe.utils.make_random import get_random
+from frappe.utils import add_days, now_datetime, nowdate
+
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
+from erpnext.healthcare.doctype.patient_appointment.patient_appointment import (
+ check_is_new_patient,
+ check_payment_fields_reqd,
+ make_encounter,
+ update_status,
+)
class TestPatientAppointment(unittest.TestCase):
@@ -131,9 +138,16 @@ class TestPatientAppointment(unittest.TestCase):
self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'status'), 'Cancelled')
def test_appointment_booking_for_admission_service_unit(self):
- from erpnext.healthcare.doctype.inpatient_record.inpatient_record import admit_patient, discharge_patient, schedule_discharge
- from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import \
- create_inpatient, get_healthcare_service_unit, mark_invoiced_inpatient_occupancy
+ from erpnext.healthcare.doctype.inpatient_record.inpatient_record import (
+ admit_patient,
+ discharge_patient,
+ schedule_discharge,
+ )
+ from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import (
+ create_inpatient,
+ get_healthcare_service_unit,
+ mark_invoiced_inpatient_occupancy,
+ )
frappe.db.sql("""delete from `tabInpatient Record`""")
patient, practitioner = create_healthcare_docs()
@@ -157,9 +171,16 @@ class TestPatientAppointment(unittest.TestCase):
discharge_patient(ip_record1, now_datetime())
def test_invalid_healthcare_service_unit_validation(self):
- from erpnext.healthcare.doctype.inpatient_record.inpatient_record import admit_patient, discharge_patient, schedule_discharge
- from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import \
- create_inpatient, get_healthcare_service_unit, mark_invoiced_inpatient_occupancy
+ from erpnext.healthcare.doctype.inpatient_record.inpatient_record import (
+ admit_patient,
+ discharge_patient,
+ schedule_discharge,
+ )
+ from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import (
+ create_inpatient,
+ get_healthcare_service_unit,
+ mark_invoiced_inpatient_occupancy,
+ )
frappe.db.sql("""delete from `tabInpatient Record`""")
patient, practitioner = create_healthcare_docs()
@@ -238,7 +259,10 @@ class TestPatientAppointment(unittest.TestCase):
self.assertRaises(OverlapError, appointment.save)
def test_service_unit_capacity(self):
- from erpnext.healthcare.doctype.patient_appointment.patient_appointment import MaximumCapacityError, OverlapError
+ from erpnext.healthcare.doctype.patient_appointment.patient_appointment import (
+ MaximumCapacityError,
+ OverlapError,
+ )
practitioner = create_practitioner()
capacity = 3
overlap_service_unit_type = create_service_unit_type(id=10, allow_appointments=1, overlap_appointments=1)
diff --git a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py b/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py
index 7bad20dffdc..90cb30035d4 100644
--- a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py
+++ b/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
+
class PatientAssessment(Document):
def validate(self):
self.set_total_score()
diff --git a/erpnext/healthcare/doctype/patient_assessment/test_patient_assessment.py b/erpnext/healthcare/doctype/patient_assessment/test_patient_assessment.py
index 3fda8550f6c..0ffbd1f5049 100644
--- a/erpnext/healthcare/doctype/patient_assessment/test_patient_assessment.py
+++ b/erpnext/healthcare/doctype/patient_assessment/test_patient_assessment.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestPatientAssessment(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.py b/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.py
index 0519599ac0c..4da679b8892 100644
--- a/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.py
+++ b/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class PatientAssessmentDetail(Document):
pass
diff --git a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.py b/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.py
index b8e00747171..783c5378481 100644
--- a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.py
+++ b/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class PatientAssessmentParameter(Document):
pass
diff --git a/erpnext/healthcare/doctype/patient_assessment_parameter/test_patient_assessment_parameter.py b/erpnext/healthcare/doctype/patient_assessment_parameter/test_patient_assessment_parameter.py
index e722f9905ec..f06fffb1ef4 100644
--- a/erpnext/healthcare/doctype/patient_assessment_parameter/test_patient_assessment_parameter.py
+++ b/erpnext/healthcare/doctype/patient_assessment_parameter/test_patient_assessment_parameter.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestPatientAssessmentParameter(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.py b/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.py
index 40da7630132..4686e9e2617 100644
--- a/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.py
+++ b/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class PatientAssessmentSheet(Document):
pass
diff --git a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.py b/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.py
index 083cab5d017..e0d8fca37f7 100644
--- a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.py
+++ b/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class PatientAssessmentTemplate(Document):
pass
diff --git a/erpnext/healthcare/doctype/patient_assessment_template/test_patient_assessment_template.py b/erpnext/healthcare/doctype/patient_assessment_template/test_patient_assessment_template.py
index 86dbd5438cd..7d639cb6af4 100644
--- a/erpnext/healthcare/doctype/patient_assessment_template/test_patient_assessment_template.py
+++ b/erpnext/healthcare/doctype/patient_assessment_template/test_patient_assessment_template.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestPatientAssessmentTemplate(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
index 5b950a8809e..9da9a6c13a2 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
@@ -185,7 +185,42 @@ frappe.ui.form.on('Patient Encounter', {
};
frm.set_value(values);
}
- }
+ },
+
+ get_applicable_treatment_plans: function(frm) {
+ frappe.call({
+ method: 'get_applicable_treatment_plans',
+ doc: frm.doc,
+ args: {'encounter': frm.doc},
+ freeze: true,
+ freeze_message: __('Fetching Treatment Plans'),
+ callback: function() {
+ new frappe.ui.form.MultiSelectDialog({
+ doctype: "Treatment Plan Template",
+ target: this.cur_frm,
+ setters: {
+ medical_department: "",
+ },
+ action(selections) {
+ frappe.call({
+ method: 'set_treatment_plans',
+ doc: frm.doc,
+ args: selections,
+ }).then(() => {
+ frm.refresh_field('drug_prescription');
+ frm.refresh_field('procedure_prescription');
+ frm.refresh_field('lab_test_prescription');
+ frm.refresh_field('therapies');
+ });
+ cur_dialog.hide();
+ }
+ });
+
+
+ }
+ });
+ },
+
});
var schedule_inpatient = function(frm) {
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json
index b646ff9ebe6..994597dca7c 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json
@@ -31,6 +31,7 @@
"sb_symptoms",
"symptoms",
"symptoms_in_print",
+ "get_applicable_treatment_plans",
"physical_examination",
"diagnosis",
"diagnosis_in_print",
@@ -324,11 +325,17 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.patient",
+ "fieldname": "get_applicable_treatment_plans",
+ "fieldtype": "Button",
+ "label": "Get Applicable Treatment Plans"
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-11-30 10:39:00.783119",
+ "modified": "2021-07-27 11:39:12.347704",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Patient Encounter",
@@ -358,4 +365,4 @@
"title_field": "title",
"track_changes": 1,
"track_seen": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
index 2b3029efdeb..2daa6c145c8 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
@@ -3,12 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import cstr, getdate, add_days
-from frappe import _
from frappe.model.mapper import get_mapped_doc
+from frappe.utils import add_days, getdate
+
class PatientEncounter(Document):
def validate(self):
@@ -33,6 +34,85 @@ class PatientEncounter(Document):
self.title = _('{0} with {1}').format(self.patient_name or self.patient,
self.practitioner_name or self.practitioner)[:100]
+ @frappe.whitelist()
+ @staticmethod
+ def get_applicable_treatment_plans(encounter):
+ patient = frappe.get_doc('Patient', encounter['patient'])
+
+ plan_filters = {}
+ plan_filters['name'] = ['in', []]
+
+ age = patient.age
+ if age:
+ plan_filters['patient_age_from'] = ['<=', age.years]
+ plan_filters['patient_age_to'] = ['>=', age.years]
+
+ gender = patient.sex
+ if gender:
+ plan_filters['gender'] = ['in', [gender, None]]
+
+ diagnosis = encounter.get('diagnosis')
+ if diagnosis:
+ diagnosis = [_diagnosis['diagnosis'] for _diagnosis in encounter['diagnosis']]
+ filters = [
+ ['diagnosis', 'in', diagnosis],
+ ['parenttype', '=', 'Treatment Plan Template'],
+ ]
+ diagnosis = frappe.get_list('Patient Encounter Diagnosis', filters=filters, fields='*')
+ plan_names = [_diagnosis['parent'] for _diagnosis in diagnosis]
+ plan_filters['name'][1].extend(plan_names)
+
+ symptoms = encounter.get('symptoms')
+ if symptoms:
+ symptoms = [symptom['complaint'] for symptom in encounter['symptoms']]
+ filters = [
+ ['complaint', 'in', symptoms],
+ ['parenttype', '=', 'Treatment Plan Template'],
+ ]
+ symptoms = frappe.get_list('Patient Encounter Symptom', filters=filters, fields='*')
+ plan_names = [symptom['parent'] for symptom in symptoms]
+ plan_filters['name'][1].extend(plan_names)
+
+ if not plan_filters['name'][1]:
+ plan_filters.pop('name')
+
+ plans = frappe.get_list('Treatment Plan Template', fields='*', filters=plan_filters)
+
+ return plans
+
+ @frappe.whitelist()
+ def set_treatment_plans(self, treatment_plans=None):
+ for treatment_plan in treatment_plans:
+ self.set_treatment_plan(treatment_plan)
+
+ def set_treatment_plan(self, plan):
+ plan_items = frappe.get_list('Treatment Plan Template Item', filters={'parent': plan}, fields='*')
+ for plan_item in plan_items:
+ self.set_treatment_plan_item(plan_item)
+
+ drugs = frappe.get_list('Drug Prescription', filters={'parent': plan}, fields='*')
+ for drug in drugs:
+ self.append('drug_prescription', drug)
+
+ self.save()
+
+ def set_treatment_plan_item(self, plan_item):
+ if plan_item.type == 'Clinical Procedure Template':
+ self.append('procedure_prescription', {
+ 'procedure': plan_item.template
+ })
+
+ if plan_item.type == 'Lab Test Template':
+ self.append('lab_test_prescription', {
+ 'lab_test_code': plan_item.template
+ })
+
+ if plan_item.type == 'Therapy Type':
+ self.append('therapies', {
+ 'therapy_type': plan_item.template
+ })
+
+
@frappe.whitelist()
def make_ip_medication_order(source_name, target_doc=None):
def set_missing_values(source, target):
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py b/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py
index 39e54f5b35c..3b64d988715 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'encounter',
diff --git a/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.js b/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.js
deleted file mode 100644
index 1baabf7eef7..00000000000
--- a/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Patient Encounter", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Patient Encounter
- () => frappe.tests.make('Patient Encounter', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py b/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py
index f5df152050f..fa643a31d8e 100644
--- a/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py
+++ b/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py
@@ -2,7 +2,86 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+import frappe
+
+from erpnext.healthcare.doctype.patient_encounter.patient_encounter import PatientEncounter
+
+
class TestPatientEncounter(unittest.TestCase):
- pass
+ def setUp(self):
+ try:
+ gender_m = frappe.get_doc({
+ 'doctype': 'Gender',
+ 'gender': 'MALE'
+ }).insert()
+ gender_f = frappe.get_doc({
+ 'doctype': 'Gender',
+ 'gender': 'FEMALE'
+ }).insert()
+ except frappe.exceptions.DuplicateEntryError:
+ gender_m = frappe.get_doc({
+ 'doctype': 'Gender',
+ 'gender': 'MALE'
+ })
+ gender_f = frappe.get_doc({
+ 'doctype': 'Gender',
+ 'gender': 'FEMALE'
+ })
+
+ self.patient_male = frappe.get_doc({
+ 'doctype': 'Patient',
+ 'first_name': 'John',
+ 'sex': gender_m.gender,
+ }).insert()
+ self.patient_female = frappe.get_doc({
+ 'doctype': 'Patient',
+ 'first_name': 'Curie',
+ 'sex': gender_f.gender,
+ }).insert()
+ self.practitioner = frappe.get_doc({
+ 'doctype': 'Healthcare Practitioner',
+ 'first_name': 'Doc',
+ 'sex': 'MALE',
+ }).insert()
+ try:
+ self.care_plan_male = frappe.get_doc({
+ 'doctype': 'Treatment Plan Template',
+ 'template_name': 'test plan - m',
+ 'gender': gender_m.gender,
+ }).insert()
+ self.care_plan_female = frappe.get_doc({
+ 'doctype': 'Treatment Plan Template',
+ 'template_name': 'test plan - f',
+ 'gender': gender_f.gender,
+ }).insert()
+ except frappe.exceptions.DuplicateEntryError:
+ self.care_plan_male = frappe.get_doc({
+ 'doctype': 'Treatment Plan Template',
+ 'template_name': 'test plan - m',
+ 'gender': gender_m.gender,
+ })
+ self.care_plan_female = frappe.get_doc({
+ 'doctype': 'Treatment Plan Template',
+ 'template_name': 'test plan - f',
+ 'gender': gender_f.gender,
+ })
+
+ def test_treatment_plan_template_filter(self):
+ encounter = frappe.get_doc({
+ 'doctype': 'Patient Encounter',
+ 'patient': self.patient_male.name,
+ 'practitioner': self.practitioner.name,
+ }).insert()
+ plans = PatientEncounter.get_applicable_treatment_plans(encounter.as_dict())
+ self.assertEqual(plans[0]['name'], self.care_plan_male.template_name)
+
+ encounter = frappe.get_doc({
+ 'doctype': 'Patient Encounter',
+ 'patient': self.patient_female.name,
+ 'practitioner': self.practitioner.name,
+ }).insert()
+ plans = PatientEncounter.get_applicable_treatment_plans(encounter.as_dict())
+ self.assertEqual(plans[0]['name'], self.care_plan_female.template_name)
diff --git a/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.py b/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.py
index 34b0cf8a580..e4d2069a50e 100644
--- a/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.py
+++ b/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class PatientEncounterDiagnosis(Document):
pass
diff --git a/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.py b/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.py
index bdb7bb218eb..47f2a2be7e9 100644
--- a/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.py
+++ b/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class PatientEncounterSymptom(Document):
pass
diff --git a/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.py b/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.py
index f0a1f929f45..34e15dc46a2 100644
--- a/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.py
+++ b/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class PatientHistoryCustomDocumentType(Document):
pass
diff --git a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
index 9e0d3c3e278..b763591d3ac 100644
--- a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
+++ b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
@@ -3,13 +3,17 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
+
+import frappe
from frappe import _
-from frappe.utils import cstr, cint
from frappe.model.document import Document
+from frappe.utils import cint, cstr
+
from erpnext.healthcare.page.patient_history.patient_history import get_patient_history_doctypes
+
class PatientHistorySettings(Document):
def validate(self):
self.validate_submittable_doctypes()
diff --git a/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py b/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py
index 9169ea642b9..c37a2adc368 100644
--- a/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py
+++ b/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py
@@ -3,12 +3,15 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
-import unittest
import json
+import unittest
+
+import frappe
from frappe.utils import getdate, strip_html
+
from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_patient
+
class TestPatientHistorySettings(unittest.TestCase):
def setUp(self):
dt = create_custom_doctype()
diff --git a/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.py b/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.py
index 2d94911855a..b7dd09bc10c 100644
--- a/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.py
+++ b/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class PatientHistoryStandardDocumentType(Document):
pass
diff --git a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.py b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.py
index 35e42bd6bd5..ac2cffa3e89 100644
--- a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.py
+++ b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class PatientMedicalRecord(Document):
def after_insert(self):
if self.reference_doctype == "Patient Medical Record" :
diff --git a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.js b/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.js
deleted file mode 100644
index 66dda09e256..00000000000
--- a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Patient Medical Record", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Patient Medical Record
- () => frappe.tests.make('Patient Medical Record', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py b/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py
index 5b7d8d62c83..099146c7ee7 100644
--- a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py
+++ b/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py
@@ -2,11 +2,20 @@
# Copyright (c) 2015, ESS LLP and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
import frappe
from frappe.utils import nowdate
-from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_encounter, create_healthcare_docs, create_appointment, create_medical_department
+
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
+from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import (
+ create_appointment,
+ create_encounter,
+ create_healthcare_docs,
+ create_medical_department,
+)
+
class TestPatientMedicalRecord(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/healthcare/doctype/patient_relation/patient_relation.py b/erpnext/healthcare/doctype/patient_relation/patient_relation.py
index 150b96200d0..17bc20940d6 100644
--- a/erpnext/healthcare/doctype/patient_relation/patient_relation.py
+++ b/erpnext/healthcare/doctype/patient_relation/patient_relation.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class PatientRelation(Document):
pass
diff --git a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.py b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.py
index 8bd0937948b..7fa31e5fb67 100644
--- a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.py
+++ b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class PractitionerSchedule(Document):
def autoname(self):
self.name = self.schedule_name
diff --git a/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.js b/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.js
deleted file mode 100644
index 32dac2c6526..00000000000
--- a/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Practitioner Schedule", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Practitioner Schedule
- () => frappe.tests.make('Practitioner Schedule', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.py b/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.py
index 52638cb618e..1ecaa47248a 100644
--- a/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.py
+++ b/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.py
@@ -2,7 +2,9 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestPractitionerSchedule(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.py b/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.py
index c18a4406cab..4eba1fbf6b4 100644
--- a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.py
+++ b/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class PractitionerServiceUnitSchedule(Document):
pass
diff --git a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.py b/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.py
index dea263dca09..19f9b70bb61 100644
--- a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.py
+++ b/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class PrescriptionDosage(Document):
pass
diff --git a/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.js b/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.js
deleted file mode 100644
index 009614ff5dd..00000000000
--- a/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Prescription Dosage", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Prescription Dosage
- () => frappe.tests.make('Prescription Dosage', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.py b/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.py
index e61a4188966..cabfd35e23d 100644
--- a/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.py
+++ b/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.py
@@ -2,7 +2,9 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestPrescriptionDosage(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.py b/erpnext/healthcare/doctype/prescription_duration/prescription_duration.py
index 96ddf8dafe8..988276da748 100644
--- a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.py
+++ b/erpnext/healthcare/doctype/prescription_duration/prescription_duration.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
from frappe.utils import cstr
+
class PrescriptionDuration(Document):
def autoname(self):
self.name = " ".join(filter(None,
diff --git a/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.js b/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.js
deleted file mode 100644
index 4971e79198c..00000000000
--- a/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Prescription Duration", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Prescription Duration
- () => frappe.tests.make('Prescription Duration', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.py b/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.py
index fe5524c5aa7..197bb3e7fb9 100644
--- a/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.py
+++ b/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.py
@@ -2,7 +2,9 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestPrescriptionDuration(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.py b/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.py
index 62ea9f1a400..f4d29fa6a30 100644
--- a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.py
+++ b/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class ProcedurePrescription(Document):
pass
diff --git a/erpnext/healthcare/doctype/sample_collection/sample_collection.py b/erpnext/healthcare/doctype/sample_collection/sample_collection.py
index 461f8095076..7de6ac08ca1 100644
--- a/erpnext/healthcare/doctype/sample_collection/sample_collection.py
+++ b/erpnext/healthcare/doctype/sample_collection/sample_collection.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
+from frappe import _
from frappe.model.document import Document
from frappe.utils import flt
-from frappe import _
+
class SampleCollection(Document):
def validate(self):
diff --git a/erpnext/healthcare/doctype/sample_collection/test_sample_collection.js b/erpnext/healthcare/doctype/sample_collection/test_sample_collection.js
deleted file mode 100644
index 2b4aed756bf..00000000000
--- a/erpnext/healthcare/doctype/sample_collection/test_sample_collection.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Sample Collection", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Sample Collection
- () => frappe.tests.make('Sample Collection', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/sensitivity/sensitivity.py b/erpnext/healthcare/doctype/sensitivity/sensitivity.py
index bf7c36b9d28..f61781d3f86 100644
--- a/erpnext/healthcare/doctype/sensitivity/sensitivity.py
+++ b/erpnext/healthcare/doctype/sensitivity/sensitivity.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class Sensitivity(Document):
pass
diff --git a/erpnext/healthcare/doctype/sensitivity/test_sensitivity.js b/erpnext/healthcare/doctype/sensitivity/test_sensitivity.js
deleted file mode 100644
index c2cf406f96d..00000000000
--- a/erpnext/healthcare/doctype/sensitivity/test_sensitivity.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Sensitivity", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Sensitivity
- () => frappe.tests.make('Sensitivity', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/sensitivity/test_sensitivity.py b/erpnext/healthcare/doctype/sensitivity/test_sensitivity.py
index 1616d2decbb..c772c72faf0 100644
--- a/erpnext/healthcare/doctype/sensitivity/test_sensitivity.py
+++ b/erpnext/healthcare/doctype/sensitivity/test_sensitivity.py
@@ -2,6 +2,7 @@
# Copyright (c) 2015, ESS and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
# test_records = frappe.get_test_records('Sensitivity')
diff --git a/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.py b/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.py
index 64f1e6ca255..53f7acc4af0 100644
--- a/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.py
+++ b/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class SensitivityTestResult(Document):
pass
diff --git a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
index 983fba9f5ff..4f96f6a7066 100644
--- a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
+++ b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
@@ -3,13 +3,23 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import getdate, flt, nowdate
+
+import frappe
+from frappe.utils import flt, getdate, nowdate
+
+from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import (
+ create_appointment,
+ create_healthcare_docs,
+ create_medical_department,
+ create_patient,
+)
+from erpnext.healthcare.doctype.therapy_plan.therapy_plan import (
+ make_sales_invoice,
+ make_therapy_session,
+)
from erpnext.healthcare.doctype.therapy_type.test_therapy_type import create_therapy_type
-from erpnext.healthcare.doctype.therapy_plan.therapy_plan import make_therapy_session, make_sales_invoice
-from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import \
- create_healthcare_docs, create_patient, create_appointment, create_medical_department
+
class TestTherapyPlan(unittest.TestCase):
def test_creation_on_encounter_submission(self):
@@ -31,7 +41,7 @@ class TestTherapyPlan(unittest.TestCase):
self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed')
patient, practitioner = create_healthcare_docs()
- appointment = create_appointment(patient, practitioner, nowdate())
+ appointment = create_appointment(patient, practitioner, nowdate())
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company', appointment.name)
session = frappe.get_doc(session)
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
index e2096604344..6d63f391895 100644
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
+++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
from frappe.utils import flt, today
+
class TherapyPlan(Document):
def validate(self):
self.set_totals()
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py b/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py
index 6526acda153..25c8df1d6b7 100644
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py
+++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'therapy_plan',
diff --git a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.py b/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.py
index 44211f32e3a..1842fc2197b 100644
--- a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.py
+++ b/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class TherapyPlanDetail(Document):
pass
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py b/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py
index 33ee29db7d7..cd3d5686bc0 100644
--- a/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py
+++ b/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestTherapyPlanTemplate(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py
index 635d4beb8df..f5512be207f 100644
--- a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py
+++ b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py
@@ -3,11 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
from frappe.utils import cint, flt
+
from erpnext.healthcare.doctype.therapy_type.therapy_type import make_item_price
+
class TherapyPlanTemplate(Document):
def after_insert(self):
self.create_item_from_template()
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py
index c748fbfcb7c..def5c482d15 100644
--- a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py
+++ b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'therapy_plan_template',
diff --git a/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py b/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py
index 7b979fe9fc8..104c1bf28bd 100644
--- a/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py
+++ b/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class TherapyPlanTemplateDetail(Document):
pass
diff --git a/erpnext/healthcare/doctype/therapy_session/test_therapy_session.py b/erpnext/healthcare/doctype/therapy_session/test_therapy_session.py
index 75bb8df1963..e4afacf3f0a 100644
--- a/erpnext/healthcare/doctype/therapy_session/test_therapy_session.py
+++ b/erpnext/healthcare/doctype/therapy_session/test_therapy_session.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestTherapySession(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.py b/erpnext/healthcare/doctype/therapy_session/therapy_session.py
index 51f267f9496..915e6e42f4c 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.py
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.py
@@ -3,14 +3,20 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import datetime
-from frappe.model.document import Document
-from frappe.utils import get_time, flt
-from frappe.model.mapper import get_mapped_doc
+
+import frappe
from frappe import _
-from frappe.utils import cstr, getdate, get_link_to_form
-from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_account
+from frappe.model.document import Document
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import flt, get_link_to_form, get_time, getdate
+
+from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import (
+ get_income_account,
+ get_receivable_account,
+)
+
class TherapySession(Document):
def validate(self):
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session_dashboard.py b/erpnext/healthcare/doctype/therapy_session/therapy_session_dashboard.py
index 9de7e293238..b8a37820ba0 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session_dashboard.py
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'therapy_session',
diff --git a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py b/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
index 80fc83fd6ce..23d542236b8 100644
--- a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
+++ b/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
@@ -3,9 +3,11 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
+
class TestTherapyType(unittest.TestCase):
def test_therapy_type_item(self):
therapy_type = create_therapy_type()
diff --git a/erpnext/healthcare/doctype/therapy_type/therapy_type.py b/erpnext/healthcare/doctype/therapy_type/therapy_type.py
index 3f6a36a9686..3517ef2c5ad 100644
--- a/erpnext/healthcare/doctype/therapy_type/therapy_type.py
+++ b/erpnext/healthcare/doctype/therapy_type/therapy_type.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
+
+import frappe
from frappe import _
-from frappe.utils import cint
from frappe.model.document import Document
from frappe.model.rename_doc import rename_doc
+from frappe.utils import cint
+
class TherapyType(Document):
def validate(self):
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/__init__.py b/erpnext/healthcare/doctype/treatment_plan_template/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/test_records.json b/erpnext/healthcare/doctype/treatment_plan_template/test_records.json
new file mode 100644
index 00000000000..d661b4304f6
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template/test_records.json
@@ -0,0 +1,7 @@
+[
+ {
+ "doctype": "Treatment Plan Template",
+ "template_name": "Chemo",
+ "patient_age_from": 21
+ }
+]
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/test_treatment_plan_template.py b/erpnext/healthcare/doctype/treatment_plan_template/test_treatment_plan_template.py
new file mode 100644
index 00000000000..b8a1dd77869
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template/test_treatment_plan_template.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+import unittest
+
+
+class TestTreatmentPlanTemplate(unittest.TestCase):
+ pass
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.js b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.js
new file mode 100644
index 00000000000..986c3cb6e42
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.js
@@ -0,0 +1,14 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Treatment Plan Template', {
+ refresh: function (frm) {
+ frm.set_query('type', 'items', function () {
+ return {
+ filters: {
+ 'name': ['in', ['Lab Test Template', 'Clinical Procedure Template', 'Therapy Type']],
+ }
+ };
+ });
+ },
+});
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.json b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.json
new file mode 100644
index 00000000000..85a312fb174
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.json
@@ -0,0 +1,189 @@
+{
+ "actions": [],
+ "autoname": "field:template_name",
+ "creation": "2021-06-10 10:14:17.901273",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "section_break_1",
+ "template_name",
+ "description",
+ "practitioners",
+ "disabled",
+ "column_break_1",
+ "medical_department",
+ "goal",
+ "order_group",
+ "section_break_8",
+ "patient_age_from",
+ "complaints",
+ "gender",
+ "column_break_12",
+ "patient_age_to",
+ "diagnosis",
+ "plan_items_section",
+ "items",
+ "drugs"
+ ],
+ "fields": [
+ {
+ "fieldname": "section_break_1",
+ "fieldtype": "Section Break",
+ "label": "Plan Details"
+ },
+ {
+ "fieldname": "medical_department",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Medical Department",
+ "options": "Medical Department"
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Description"
+ },
+ {
+ "fieldname": "goal",
+ "fieldtype": "Small Text",
+ "label": "Goal"
+ },
+ {
+ "fieldname": "practitioners",
+ "fieldtype": "Table MultiSelect",
+ "label": "Practitioners",
+ "options": "Treatment Plan Template Practitioner"
+ },
+ {
+ "fieldname": "order_group",
+ "fieldtype": "Link",
+ "label": "Order Group",
+ "options": "Patient Encounter",
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_8",
+ "fieldtype": "Section Break",
+ "label": "Plan Conditions"
+ },
+ {
+ "fieldname": "template_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Template Name",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "patient_age_from",
+ "fieldtype": "Int",
+ "label": "Patient Age From",
+ "non_negative": 1
+ },
+ {
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "patient_age_to",
+ "fieldtype": "Int",
+ "label": "Patient Age To",
+ "non_negative": 1
+ },
+ {
+ "fieldname": "gender",
+ "fieldtype": "Link",
+ "label": "Gender",
+ "options": "Gender"
+ },
+ {
+ "fieldname": "complaints",
+ "fieldtype": "Table MultiSelect",
+ "label": "Complaints",
+ "options": "Patient Encounter Symptom"
+ },
+ {
+ "fieldname": "diagnosis",
+ "fieldtype": "Table MultiSelect",
+ "label": "Diagnosis",
+ "options": "Patient Encounter Diagnosis"
+ },
+ {
+ "fieldname": "plan_items_section",
+ "fieldtype": "Section Break",
+ "label": "Plan Items"
+ },
+ {
+ "fieldname": "items",
+ "fieldtype": "Table",
+ "label": "Items",
+ "options": "Treatment Plan Template Item"
+ },
+ {
+ "fieldname": "drugs",
+ "fieldtype": "Table",
+ "label": "Drugs",
+ "options": "Drug Prescription"
+ },
+ {
+ "default": "0",
+ "fieldname": "disabled",
+ "fieldtype": "Check",
+ "label": "Disabled"
+ },
+ {
+ "fieldname": "column_break_1",
+ "fieldtype": "Column Break"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-08-18 02:41:58.354296",
+ "modified_by": "Administrator",
+ "module": "Healthcare",
+ "name": "Treatment Plan Template",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Physician",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Healthcare Administrator",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "template_name",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.py b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.py
new file mode 100644
index 00000000000..dbe0e9ae5f4
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.py
@@ -0,0 +1,20 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+from frappe.model.document import Document
+
+
+class TreatmentPlanTemplate(Document):
+ def validate(self):
+ self.validate_age()
+
+ def validate_age(self):
+ if self.patient_age_from and self.patient_age_from < 0:
+ frappe.throw(_('Patient Age From cannot be less than 0'))
+ if self.patient_age_to and self.patient_age_to < 0:
+ frappe.throw(_('Patient Age To cannot be less than 0'))
+ if self.patient_age_to and self.patient_age_from and \
+ self.patient_age_to < self.patient_age_from:
+ frappe.throw(_('Patient Age To cannot be less than Patient Age From'))
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template_list.js b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template_list.js
new file mode 100644
index 00000000000..7ab31dff791
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template_list.js
@@ -0,0 +1,10 @@
+frappe.listview_settings['Treatment Plan Template'] = {
+ get_indicator: function(doc) {
+ var colors = {
+ 1: 'gray',
+ 0: 'blue',
+ };
+ let label = doc.disabled == 1 ? 'Disabled' : 'Enabled';
+ return [__(label), colors[doc.disabled], 'disable,=,' + doc.disabled];
+ }
+};
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_item/__init__.py b/erpnext/healthcare/doctype/treatment_plan_template_item/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.json b/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.json
new file mode 100644
index 00000000000..20a9d6793a5
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.json
@@ -0,0 +1,55 @@
+{
+ "actions": [],
+ "creation": "2021-06-10 11:47:29.194795",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "type",
+ "template",
+ "qty",
+ "instructions"
+ ],
+ "fields": [
+ {
+ "fieldname": "type",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Type",
+ "options": "DocType",
+ "reqd": 1
+ },
+ {
+ "fieldname": "template",
+ "fieldtype": "Dynamic Link",
+ "in_list_view": 1,
+ "label": "Template",
+ "options": "type",
+ "reqd": 1
+ },
+ {
+ "default": "1",
+ "fieldname": "qty",
+ "fieldtype": "Int",
+ "label": "Qty"
+ },
+ {
+ "fieldname": "instructions",
+ "fieldtype": "Small Text",
+ "in_list_view": 1,
+ "label": "Instructions"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-08-17 11:19:03.515441",
+ "modified_by": "Administrator",
+ "module": "Healthcare",
+ "name": "Treatment Plan Template Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.py b/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.py
new file mode 100644
index 00000000000..8b8d89f07f3
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class TreatmentPlanTemplateItem(Document):
+ pass
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_practitioner/__init__.py b/erpnext/healthcare/doctype/treatment_plan_template_practitioner/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.json b/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.json
new file mode 100644
index 00000000000..04da387f7b8
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.json
@@ -0,0 +1,32 @@
+{
+ "actions": [],
+ "creation": "2021-06-10 10:37:56.669416",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "practitioner"
+ ],
+ "fields": [
+ {
+ "fieldname": "practitioner",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Practitioner",
+ "options": "Healthcare Practitioner",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-06-11 16:05:06.733299",
+ "modified_by": "Administrator",
+ "module": "Healthcare",
+ "name": "Treatment Plan Template Practitioner",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.py b/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.py
new file mode 100644
index 00000000000..c2d08bcc1ab
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class TreatmentPlanTemplatePractitioner(Document):
+ pass
diff --git a/erpnext/healthcare/doctype/vital_signs/test_vital_signs.js b/erpnext/healthcare/doctype/vital_signs/test_vital_signs.js
deleted file mode 100644
index f4ab4466be4..00000000000
--- a/erpnext/healthcare/doctype/vital_signs/test_vital_signs.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Vital Signs", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Vital Signs
- () => frappe.tests.make('Vital Signs', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/vital_signs/test_vital_signs.py b/erpnext/healthcare/doctype/vital_signs/test_vital_signs.py
index 5d3e00740f9..22b52fb4822 100644
--- a/erpnext/healthcare/doctype/vital_signs/test_vital_signs.py
+++ b/erpnext/healthcare/doctype/vital_signs/test_vital_signs.py
@@ -2,6 +2,7 @@
# Copyright (c) 2015, ESS LLP and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
# test_records = frappe.get_test_records('Vital Signs')
diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.py b/erpnext/healthcare/doctype/vital_signs/vital_signs.py
index 4bb3940ae0f..29dbeb470dd 100644
--- a/erpnext/healthcare/doctype/vital_signs/vital_signs.py
+++ b/erpnext/healthcare/doctype/vital_signs/vital_signs.py
@@ -3,10 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
-from frappe.utils import cstr
from frappe import _
+from frappe.model.document import Document
+
class VitalSigns(Document):
def validate(self):
diff --git a/erpnext/healthcare/page/patient_history/patient_history.py b/erpnext/healthcare/page/patient_history/patient_history.py
index 4cdfd64a697..77d8846f373 100644
--- a/erpnext/healthcare/page/patient_history/patient_history.py
+++ b/erpnext/healthcare/page/patient_history/patient_history.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
+
+import frappe
from frappe.utils import cint
-from erpnext.healthcare.utils import render_docs_as_html
+
@frappe.whitelist()
def get_feed(name, document_types=None, date_range=None, start=0, page_length=20):
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.py b/erpnext/healthcare/page/patient_progress/patient_progress.py
index 46bfb3db5d4..c17f10574a9 100644
--- a/erpnext/healthcare/page/patient_progress/patient_progress.py
+++ b/erpnext/healthcare/page/patient_progress/patient_progress.py
@@ -1,8 +1,10 @@
-import frappe
-from datetime import datetime
-from frappe import _
-from frappe.utils import getdate, get_timespan_date_range
import json
+from datetime import datetime
+
+import frappe
+from frappe import _
+from frappe.utils import get_timespan_date_range, getdate
+
@frappe.whitelist()
def get_therapy_sessions_count(patient):
diff --git a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py
index 28b60bdcc92..2e809fb66b0 100644
--- a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py
+++ b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py
@@ -2,8 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import get_current_healthcare_service_unit
+
+from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import (
+ get_current_healthcare_service_unit,
+)
+
def execute(filters=None):
columns = get_columns()
diff --git a/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py b/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py
index 0a538fdff0d..7c4b326c8e5 100644
--- a/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py
+++ b/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py
@@ -2,14 +2,32 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import unittest
-import frappe
+
import datetime
+import unittest
+
+import frappe
from frappe.utils import getdate, now_datetime
-from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import create_patient, create_inpatient, get_healthcare_service_unit, mark_invoiced_inpatient_occupancy
-from erpnext.healthcare.doctype.inpatient_record.inpatient_record import admit_patient, discharge_patient, schedule_discharge
-from erpnext.healthcare.doctype.inpatient_medication_order.test_inpatient_medication_order import create_ipmo, create_ipme
-from erpnext.healthcare.report.inpatient_medication_orders.inpatient_medication_orders import execute
+
+from erpnext.healthcare.doctype.inpatient_medication_order.test_inpatient_medication_order import (
+ create_ipme,
+ create_ipmo,
+)
+from erpnext.healthcare.doctype.inpatient_record.inpatient_record import (
+ admit_patient,
+ discharge_patient,
+ schedule_discharge,
+)
+from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import (
+ create_inpatient,
+ create_patient,
+ get_healthcare_service_unit,
+ mark_invoiced_inpatient_occupancy,
+)
+from erpnext.healthcare.report.inpatient_medication_orders.inpatient_medication_orders import (
+ execute,
+)
+
class TestInpatientMedicationOrders(unittest.TestCase):
@classmethod
diff --git a/erpnext/healthcare/report/lab_test_report/lab_test_report.py b/erpnext/healthcare/report/lab_test_report/lab_test_report.py
index ba4ca4172dc..e2a53bb1e46 100644
--- a/erpnext/healthcare/report/lab_test_report/lab_test_report.py
+++ b/erpnext/healthcare/report/lab_test_report/lab_test_report.py
@@ -2,8 +2,10 @@
# License: See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import msgprint, _
+from frappe import _, msgprint
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py
index 9a4840acfea..1afb5da1fb4 100644
--- a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py
+++ b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py
@@ -2,12 +2,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import getdate, flt, add_to_date, add_days
-from frappe import _ , scrub
+from frappe import _, scrub
+from frappe.utils import add_days, add_to_date, flt, getdate
from six import iteritems
+
from erpnext.accounts.utils import get_fiscal_year
+
def execute(filters=None):
return Analytics(filters).run()
@@ -26,7 +29,7 @@ class Analytics(object):
return self.columns, self.data, None, self.chart
def get_period_date_ranges(self):
- from dateutil.relativedelta import relativedelta, MO
+ from dateutil.relativedelta import MO, relativedelta
from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date)
increment = {
diff --git a/erpnext/healthcare/setup.py b/erpnext/healthcare/setup.py
index 891272ddf81..167f24399cd 100644
--- a/erpnext/healthcare/setup.py
+++ b/erpnext/healthcare/setup.py
@@ -1,9 +1,11 @@
from __future__ import unicode_literals
-import frappe
+import frappe
from frappe import _
+
from erpnext.setup.utils import insert_record
+
def setup_healthcare():
if frappe.db.exists('Medical Department', 'Cardiology'):
# already setup
diff --git a/erpnext/healthcare/utils.py b/erpnext/healthcare/utils.py
index 7c80bdb73ce..cae3008ca82 100644
--- a/erpnext/healthcare/utils.py
+++ b/erpnext/healthcare/utils.py
@@ -3,16 +3,20 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import math
-import frappe
+
import json
+import math
+
+import frappe
from frappe import _
+from frappe.utils import cstr, rounded, time_diff_in_hours
from frappe.utils.formatters import format_value
-from frappe.utils import time_diff_in_hours, rounded, cstr
-from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_income_account
+
from erpnext.healthcare.doctype.fee_validity.fee_validity import create_fee_validity
+from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_income_account
from erpnext.healthcare.doctype.lab_test.lab_test import create_multiple
+
@frappe.whitelist()
def get_healthcare_services_to_invoice(patient, company):
patient = frappe.get_doc('Patient', patient)
@@ -339,7 +343,9 @@ def get_service_item_and_practitioner_charge(doc):
def get_appointment_type_service_item(appointment_type, department, is_inpatient):
- from erpnext.healthcare.doctype.appointment_type.appointment_type import get_service_item_based_on_department
+ from erpnext.healthcare.doctype.appointment_type.appointment_type import (
+ get_service_item_based_on_department,
+ )
item_list = get_service_item_based_on_department(appointment_type, department)
service_item = None
diff --git a/erpnext/healthcare/web_form/lab_test/lab_test.py b/erpnext/healthcare/web_form/lab_test/lab_test.py
index 5a8c8a421cd..ec08985b191 100644
--- a/erpnext/healthcare/web_form/lab_test/lab_test.py
+++ b/erpnext/healthcare/web_form/lab_test/lab_test.py
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
import frappe
+
def get_context(context):
context.read_only = 1
diff --git a/erpnext/healthcare/web_form/patient_appointments/patient_appointments.py b/erpnext/healthcare/web_form/patient_appointments/patient_appointments.py
index 09bcb42b579..80c12fd2144 100644
--- a/erpnext/healthcare/web_form/patient_appointments/patient_appointments.py
+++ b/erpnext/healthcare/web_form/patient_appointments/patient_appointments.py
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
import frappe
+
def get_context(context):
context.read_only = 1
diff --git a/erpnext/healthcare/web_form/patient_registration/patient_registration.py b/erpnext/healthcare/web_form/patient_registration/patient_registration.py
index 1bc4d1874c8..f57de916dd1 100644
--- a/erpnext/healthcare/web_form/patient_registration/patient_registration.py
+++ b/erpnext/healthcare/web_form/patient_registration/patient_registration.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+
def get_context(context):
# do your magic here
pass
diff --git a/erpnext/healthcare/web_form/prescription/prescription.py b/erpnext/healthcare/web_form/prescription/prescription.py
index efdeaa906ae..f6f273ad580 100644
--- a/erpnext/healthcare/web_form/prescription/prescription.py
+++ b/erpnext/healthcare/web_form/prescription/prescription.py
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
import frappe
+
def get_context(context):
context.read_only = 1
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 2385b7cbade..7790061ce06 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
from frappe import _
app_name = "erpnext"
@@ -51,15 +52,15 @@ additional_print_settings = "erpnext.controllers.print_settings.get_print_settin
on_session_creation = [
"erpnext.portal.utils.create_customer_or_supplier",
- "erpnext.shopping_cart.utils.set_cart_count"
+ "erpnext.e_commerce.shopping_cart.utils.set_cart_count"
]
-on_logout = "erpnext.shopping_cart.utils.clear_cart_count"
+on_logout = "erpnext.e_commerce.shopping_cart.utils.clear_cart_count"
treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Group', 'Sales Person', 'Territory', 'Assessment Group', 'Department']
# website
-update_website_context = ["erpnext.shopping_cart.utils.update_website_context", "erpnext.education.doctype.education_settings.education_settings.update_website_context"]
-my_account_context = "erpnext.shopping_cart.utils.update_my_account_context"
+update_website_context = ["erpnext.e_commerce.shopping_cart.utils.update_website_context", "erpnext.education.doctype.education_settings.education_settings.update_website_context"]
+my_account_context = "erpnext.e_commerce.shopping_cart.utils.update_my_account_context"
calendars = ["Task", "Work Order", "Leave Application", "Sales Order", "Holiday List", "Course Schedule"]
@@ -75,7 +76,7 @@ domains = {
'Services': 'erpnext.domains.services',
}
-website_generators = ["Item Group", "Item", "BOM", "Sales Partner",
+website_generators = ["Item Group", "Website Item", "BOM", "Sales Partner",
"Job Opening", "Student Admission"]
website_context = {
@@ -243,11 +244,13 @@ doc_events = {
"on_update": ["erpnext.hr.doctype.employee.employee.update_user_permissions",
"erpnext.portal.utils.set_default_role"]
},
- "Sales Taxes and Charges Template": {
- "on_update": "erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings.validate_cart_settings"
+ "Communication": {
+ "on_update": [
+ "erpnext.support.doctype.issue.issue.set_first_response_time"
+ ]
},
- "Website Settings": {
- "validate": "erpnext.portal.doctype.products_settings.products_settings.home_page_is_products"
+ "Sales Taxes and Charges Template": {
+ "on_update": "erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings.validate_cart_settings"
},
"Tax Category": {
"validate": "erpnext.regional.india.utils.validate_tax_category"
@@ -278,6 +281,7 @@ doc_events = {
]
},
"Payment Entry": {
+ "validate": "erpnext.regional.india.utils.update_place_of_supply",
"on_submit": ["erpnext.regional.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.update_payment_req_status", "erpnext.accounts.doctype.dunning.dunning.resolve_dunning"],
"on_trash": "erpnext.regional.check_deletion_permission"
},
@@ -308,6 +312,9 @@ doc_events = {
},
"Company": {
"on_trash": "erpnext.regional.india.utils.delete_gst_settings_for_company"
+ },
+ "Integration Request": {
+ "validate": "erpnext.accounts.doctype.payment_request.payment_request.validate_payment"
}
}
diff --git a/erpnext/hotels/doctype/hotel_room/hotel_room.py b/erpnext/hotels/doctype/hotel_room/hotel_room.py
index 6a2fc02574f..93a62c98e79 100644
--- a/erpnext/hotels/doctype/hotel_room/hotel_room.py
+++ b/erpnext/hotels/doctype/hotel_room/hotel_room.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class HotelRoom(Document):
def validate(self):
if not self.capacity:
diff --git a/erpnext/hotels/doctype/hotel_room/test_hotel_room.js b/erpnext/hotels/doctype/hotel_room/test_hotel_room.js
deleted file mode 100644
index 8b2b83330f3..00000000000
--- a/erpnext/hotels/doctype/hotel_room/test_hotel_room.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Hotel Room", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Hotel Room
- () => frappe.tests.make('Hotel Room', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hotels/doctype/hotel_room/test_hotel_room.py b/erpnext/hotels/doctype/hotel_room/test_hotel_room.py
index e307b5ac37a..4fedbd42a92 100644
--- a/erpnext/hotels/doctype/hotel_room/test_hotel_room.py
+++ b/erpnext/hotels/doctype/hotel_room/test_hotel_room.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
test_dependencies = ["Hotel Room Package"]
test_records = [
dict(doctype="Hotel Room", name="1001",
diff --git a/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py b/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py
index 69da007fc6b..982b3ef911d 100644
--- a/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py
+++ b/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class HotelRoomAmenity(Document):
pass
diff --git a/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py b/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py
index 8a62eea8fa1..1864081842d 100644
--- a/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py
+++ b/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class HotelRoomPackage(Document):
def validate(self):
if not self.item:
diff --git a/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.js b/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.js
deleted file mode 100644
index f1ebad41d41..00000000000
--- a/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Hotel Room Package", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Hotel Room Package
- () => frappe.tests.make('Hotel Room Package', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py b/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py
index ebf7f2b7e9f..fe5d79dcc32 100644
--- a/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py
+++ b/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
test_records = [
dict(doctype='Item', item_code='Breakfast',
item_group='Products', is_stock_item=0),
diff --git a/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py b/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py
index 8eee0f24c5c..5797fef30db 100644
--- a/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py
+++ b/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class HotelRoomPricing(Document):
pass
diff --git a/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.js b/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.js
deleted file mode 100644
index ba0d1fd3e96..00000000000
--- a/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Hotel Room Pricing", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Hotel Room Pricing
- () => frappe.tests.make('Hotel Room Pricing', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py b/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py
index b73fd44cd5e..72030c69397 100644
--- a/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py
+++ b/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
test_dependencies = ["Hotel Room Package"]
test_records = [
dict(doctype="Hotel Room Pricing", enabled=1,
diff --git a/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py b/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py
index 6bf01bf941b..4a344df8485 100644
--- a/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py
+++ b/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class HotelRoomPricingItem(Document):
pass
diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py
index 9ae9fcfaf83..f594ac709ec 100644
--- a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py
+++ b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class HotelRoomPricingPackage(Document):
pass
diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.js b/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.js
deleted file mode 100644
index 73a561c408c..00000000000
--- a/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Hotel Room Pricing Package", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Hotel Room Pricing Package
- () => frappe.tests.make('Hotel Room Pricing Package', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py b/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py
index fec1c86ad02..ea258ccb75d 100644
--- a/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py
+++ b/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestHotelRoomPricingPackage(unittest.TestCase):
pass
diff --git a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py
index a8ebe8610ec..4944862284a 100644
--- a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py
+++ b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py
@@ -3,10 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, json
-from frappe.model.document import Document
+
+import json
+
+import frappe
from frappe import _
-from frappe.utils import date_diff, add_days, flt
+from frappe.model.document import Document
+from frappe.utils import add_days, date_diff, flt
+
class HotelRoomUnavailableError(frappe.ValidationError): pass
class HotelRoomPricingNotSetError(frappe.ValidationError): pass
diff --git a/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.js b/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.js
deleted file mode 100644
index 2897139359b..00000000000
--- a/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Hotel Room Reservation", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Hotel Room Reservation
- () => frappe.tests.make('Hotel Room Reservation', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py b/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py
index d4979968e61..e03005cf042 100644
--- a/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py
+++ b/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py
@@ -3,9 +3,15 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from erpnext.hotels.doctype.hotel_room_reservation.hotel_room_reservation import HotelRoomPricingNotSetError, HotelRoomUnavailableError
+
+import frappe
+
+from erpnext.hotels.doctype.hotel_room_reservation.hotel_room_reservation import (
+ HotelRoomPricingNotSetError,
+ HotelRoomUnavailableError,
+)
+
test_dependencies = ["Hotel Room Package", "Hotel Room Pricing", "Hotel Room"]
class TestHotelRoomReservation(unittest.TestCase):
diff --git a/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py b/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py
index 3406faea0e6..0cf854722e1 100644
--- a/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py
+++ b/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class HotelRoomReservationItem(Document):
pass
diff --git a/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.py b/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.py
index 1fc1303f393..610cf181c1d 100644
--- a/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.py
+++ b/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class HotelRoomType(Document):
pass
diff --git a/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.js b/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.js
deleted file mode 100644
index e2dd5780e3c..00000000000
--- a/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Hotel Room Type", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Hotel Room Type
- () => frappe.tests.make('Hotel Room Type', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py b/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py
index 3b243e95669..6dba7b7407b 100644
--- a/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py
+++ b/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestHotelRoomType(unittest.TestCase):
pass
diff --git a/erpnext/hotels/doctype/hotel_settings/hotel_settings.py b/erpnext/hotels/doctype/hotel_settings/hotel_settings.py
index d78bca149df..f8f8fe964da 100644
--- a/erpnext/hotels/doctype/hotel_settings/hotel_settings.py
+++ b/erpnext/hotels/doctype/hotel_settings/hotel_settings.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class HotelSettings(Document):
pass
diff --git a/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.js b/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.js
deleted file mode 100644
index bc0b7f8341d..00000000000
--- a/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Hotel Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Hotel Settings
- () => frappe.tests.make('Hotel Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py b/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py
index a081acc0e08..5cf58b994e1 100644
--- a/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py
+++ b/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestHotelSettings(unittest.TestCase):
pass
diff --git a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py
index 259edb9c06d..f02baebdf6f 100644
--- a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py
+++ b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py
@@ -2,12 +2,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import add_days, date_diff
from erpnext.hotels.doctype.hotel_room_reservation.hotel_room_reservation import get_rooms_booked
+
def execute(filters=None):
columns = get_columns(filters)
data = get_data(filters)
diff --git a/erpnext/hr/doctype/appointment_letter/appointment_letter.py b/erpnext/hr/doctype/appointment_letter/appointment_letter.py
index 85b82c50145..b9a8ec63017 100644
--- a/erpnext/hr/doctype/appointment_letter/appointment_letter.py
+++ b/erpnext/hr/doctype/appointment_letter/appointment_letter.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class AppointmentLetter(Document):
pass
diff --git a/erpnext/hr/doctype/appointment_letter/test_appointment_letter.py b/erpnext/hr/doctype/appointment_letter/test_appointment_letter.py
index b9ce9819c5a..88637b9fe93 100644
--- a/erpnext/hr/doctype/appointment_letter/test_appointment_letter.py
+++ b/erpnext/hr/doctype/appointment_letter/test_appointment_letter.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestAppointmentLetter(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/appointment_letter_content/appointment_letter_content.py b/erpnext/hr/doctype/appointment_letter_content/appointment_letter_content.py
index a1a49e536b6..f4db456af38 100644
--- a/erpnext/hr/doctype/appointment_letter_content/appointment_letter_content.py
+++ b/erpnext/hr/doctype/appointment_letter_content/appointment_letter_content.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class AppointmentLettercontent(Document):
pass
diff --git a/erpnext/hr/doctype/appointment_letter_template/appointment_letter_template.py b/erpnext/hr/doctype/appointment_letter_template/appointment_letter_template.py
index c23881f8007..acb5c1f6924 100644
--- a/erpnext/hr/doctype/appointment_letter_template/appointment_letter_template.py
+++ b/erpnext/hr/doctype/appointment_letter_template/appointment_letter_template.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class AppointmentLetterTemplate(Document):
pass
diff --git a/erpnext/hr/doctype/appointment_letter_template/test_appointment_letter_template.py b/erpnext/hr/doctype/appointment_letter_template/test_appointment_letter_template.py
index 3d061ac8e93..46dd3e12727 100644
--- a/erpnext/hr/doctype/appointment_letter_template/test_appointment_letter_template.py
+++ b/erpnext/hr/doctype/appointment_letter_template/test_appointment_letter_template.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestAppointmentLetterTemplate(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/appraisal/appraisal.py b/erpnext/hr/doctype/appraisal/appraisal.py
index c2ed4579844..96a4ffa524a 100644
--- a/erpnext/hr/doctype/appraisal/appraisal.py
+++ b/erpnext/hr/doctype/appraisal/appraisal.py
@@ -2,15 +2,16 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from frappe.model.mapper import get_mapped_doc
from frappe.utils import flt, getdate
-from frappe import _
-from frappe.model.mapper import get_mapped_doc
-from frappe.model.document import Document
from erpnext.hr.utils import set_employee_name, validate_active_employee
+
class Appraisal(Document):
def validate(self):
if not self.status:
diff --git a/erpnext/hr/doctype/appraisal/test_appraisal.py b/erpnext/hr/doctype/appraisal/test_appraisal.py
index f70dc481c80..cf2bd7c2427 100644
--- a/erpnext/hr/doctype/appraisal/test_appraisal.py
+++ b/erpnext/hr/doctype/appraisal/test_appraisal.py
@@ -2,7 +2,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Appraisal')
diff --git a/erpnext/hr/doctype/appraisal_goal/appraisal_goal.py b/erpnext/hr/doctype/appraisal_goal/appraisal_goal.py
index 11d9f3944d5..d9789a028bd 100644
--- a/erpnext/hr/doctype/appraisal_goal/appraisal_goal.py
+++ b/erpnext/hr/doctype/appraisal_goal/appraisal_goal.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class AppraisalGoal(Document):
pass
diff --git a/erpnext/hr/doctype/appraisal_template/appraisal_template.py b/erpnext/hr/doctype/appraisal_template/appraisal_template.py
index d0dfad4be31..d10a0de3bce 100644
--- a/erpnext/hr/doctype/appraisal_template/appraisal_template.py
+++ b/erpnext/hr/doctype/appraisal_template/appraisal_template.py
@@ -2,11 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import cint, flt
-from frappe import _
+import frappe
+from frappe import _
from frappe.model.document import Document
+from frappe.utils import cint, flt
+
class AppraisalTemplate(Document):
def validate(self):
diff --git a/erpnext/hr/doctype/appraisal_template/appraisal_template_dashboard.py b/erpnext/hr/doctype/appraisal_template/appraisal_template_dashboard.py
index 392b370e6c3..b8d04944edb 100644
--- a/erpnext/hr/doctype/appraisal_template/appraisal_template_dashboard.py
+++ b/erpnext/hr/doctype/appraisal_template/appraisal_template_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/hr/doctype/appraisal_template/test_appraisal_template.py b/erpnext/hr/doctype/appraisal_template/test_appraisal_template.py
index e3029d980a0..a814ec8d5b2 100644
--- a/erpnext/hr/doctype/appraisal_template/test_appraisal_template.py
+++ b/erpnext/hr/doctype/appraisal_template/test_appraisal_template.py
@@ -2,7 +2,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Appraisal Template')
diff --git a/erpnext/hr/doctype/appraisal_template_goal/appraisal_template_goal.py b/erpnext/hr/doctype/appraisal_template_goal/appraisal_template_goal.py
index b3c5704fa53..1b15fbd51e1 100644
--- a/erpnext/hr/doctype/appraisal_template_goal/appraisal_template_goal.py
+++ b/erpnext/hr/doctype/appraisal_template_goal/appraisal_template_goal.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class AppraisalTemplateGoal(Document):
pass
diff --git a/erpnext/hr/doctype/attendance/attendance.py b/erpnext/hr/doctype/attendance/attendance.py
index c1a7c8f88a5..002f9bbcac2 100644
--- a/erpnext/hr/doctype/attendance/attendance.py
+++ b/erpnext/hr/doctype/attendance/attendance.py
@@ -2,14 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import getdate, nowdate
+import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import cstr, get_datetime, formatdate
+from frappe.utils import cstr, formatdate, get_datetime, getdate, nowdate
+
from erpnext.hr.utils import validate_active_employee
+
class Attendance(Document):
def validate(self):
from erpnext.controllers.status_updater import validate_status
@@ -134,7 +135,6 @@ def mark_attendance(employee, attendance_date, status, shift=None, leave_type=No
@frappe.whitelist()
def mark_bulk_attendance(data):
import json
- from pprint import pprint
if isinstance(data, str):
data = json.loads(data)
data = frappe._dict(data)
diff --git a/erpnext/hr/doctype/attendance/attendance_dashboard.py b/erpnext/hr/doctype/attendance/attendance_dashboard.py
index 5dd9403674e..bbe67dfcc8f 100644
--- a/erpnext/hr/doctype/attendance/attendance_dashboard.py
+++ b/erpnext/hr/doctype/attendance/attendance_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/hr/doctype/attendance/test_attendance.py b/erpnext/hr/doctype/attendance/test_attendance.py
index 838b704c5a5..ab443774212 100644
--- a/erpnext/hr/doctype/attendance/test_attendance.py
+++ b/erpnext/hr/doctype/attendance/test_attendance.py
@@ -2,8 +2,9 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
from frappe.utils import nowdate
test_records = frappe.get_test_records('Attendance')
diff --git a/erpnext/hr/doctype/attendance_request/attendance_request.py b/erpnext/hr/doctype/attendance_request/attendance_request.py
index 7f88fed73a2..1e7429656d2 100644
--- a/erpnext/hr/doctype/attendance_request/attendance_request.py
+++ b/erpnext/hr/doctype/attendance_request/attendance_request.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import date_diff, add_days, getdate
+from frappe.utils import add_days, date_diff, getdate
+
from erpnext.hr.doctype.employee.employee import is_holiday
-from erpnext.hr.utils import validate_dates, validate_active_employee
+from erpnext.hr.utils import validate_active_employee, validate_dates
+
class AttendanceRequest(Document):
def validate(self):
diff --git a/erpnext/hr/doctype/attendance_request/attendance_request_dashboard.py b/erpnext/hr/doctype/attendance_request/attendance_request_dashboard.py
index 2d3eb000119..8feb6f2f23e 100644
--- a/erpnext/hr/doctype/attendance_request/attendance_request_dashboard.py
+++ b/erpnext/hr/doctype/attendance_request/attendance_request_dashboard.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+
def get_data():
return {
'fieldname': 'attendance_request',
diff --git a/erpnext/hr/doctype/attendance_request/test_attendance_request.js b/erpnext/hr/doctype/attendance_request/test_attendance_request.js
deleted file mode 100644
index d40ec61b086..00000000000
--- a/erpnext/hr/doctype/attendance_request/test_attendance_request.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Attendance Request", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Attendance Request
- () => frappe.tests.make('Attendance Request', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/attendance_request/test_attendance_request.py b/erpnext/hr/doctype/attendance_request/test_attendance_request.py
index 9e668aa72fb..a9db74cbf75 100644
--- a/erpnext/hr/doctype/attendance_request/test_attendance_request.py
+++ b/erpnext/hr/doctype/attendance_request/test_attendance_request.py
@@ -3,11 +3,12 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import nowdate
from datetime import date
+import frappe
+from frappe.utils import nowdate
+
test_dependencies = ["Employee"]
class TestAttendanceRequest(unittest.TestCase):
diff --git a/erpnext/hr/doctype/branch/branch.py b/erpnext/hr/doctype/branch/branch.py
index a847c8e2174..c770dc34090 100644
--- a/erpnext/hr/doctype/branch/branch.py
+++ b/erpnext/hr/doctype/branch/branch.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class Branch(Document):
pass
diff --git a/erpnext/hr/doctype/branch/test_branch.js b/erpnext/hr/doctype/branch/test_branch.js
deleted file mode 100644
index 82a6ae103ee..00000000000
--- a/erpnext/hr/doctype/branch/test_branch.js
+++ /dev/null
@@ -1,23 +0,0 @@
-QUnit.module('hr');
-
-QUnit.test("Test: Branch [HR]", function (assert) {
- assert.expect(1);
- let done = assert.async();
-
- frappe.run_serially([
- // test branch creation
- () => frappe.set_route("List", "Branch", "List"),
- () => frappe.new_doc("Branch"),
- () => frappe.timeout(1),
- () => frappe.quick_entry.dialog.$wrapper.find('.edit-full').click(),
- () => frappe.timeout(1),
- () => cur_frm.set_value("branch", "Test Branch"),
-
- // save form
- () => cur_frm.save(),
- () => frappe.timeout(1),
- () => assert.equal("Test Branch", cur_frm.doc.branch,
- 'name of branch correctly saved'),
- () => done()
- ]);
-});
diff --git a/erpnext/hr/doctype/branch/test_branch.py b/erpnext/hr/doctype/branch/test_branch.py
index 807698ba0a2..7bf9b395308 100644
--- a/erpnext/hr/doctype/branch/test_branch.py
+++ b/erpnext/hr/doctype/branch/test_branch.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Branch')
diff --git a/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py b/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py
index 3db81654a65..f24483bf827 100644
--- a/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py
+++ b/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py
@@ -3,12 +3,21 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import date_diff, add_days, getdate, cint, format_date
from frappe.model.document import Document
-from erpnext.hr.utils import validate_dates, validate_overlap, get_leave_period, validate_active_employee, \
- create_additional_leave_ledger_entry, get_holiday_dates_for_employee
+from frappe.utils import add_days, cint, date_diff, format_date, getdate
+
+from erpnext.hr.utils import (
+ create_additional_leave_ledger_entry,
+ get_holiday_dates_for_employee,
+ get_leave_period,
+ validate_active_employee,
+ validate_dates,
+ validate_overlap,
+)
+
class CompensatoryLeaveRequest(Document):
diff --git a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.js b/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.js
deleted file mode 100644
index bebcaac400e..00000000000
--- a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Compensatory Leave Request", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Compensatory Leave Request
- () => frappe.tests.make('Compensatory Leave Request', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py b/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py
index 3b99c57051a..95bdd514ef3 100644
--- a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py
+++ b/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py
@@ -3,12 +3,14 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import today, add_months, add_days
+
+import frappe
+from frappe.utils import add_days, add_months, today
+
from erpnext.hr.doctype.attendance_request.test_attendance_request import get_employee
-from erpnext.hr.doctype.leave_period.test_leave_period import create_leave_period
from erpnext.hr.doctype.leave_application.leave_application import get_leave_balance_on
+from erpnext.hr.doctype.leave_period.test_leave_period import create_leave_period
test_dependencies = ["Employee"]
diff --git a/erpnext/hr/doctype/daily_work_summary/daily_work_summary.py b/erpnext/hr/doctype/daily_work_summary/daily_work_summary.py
index 1cc23812f75..92cf6aac851 100644
--- a/erpnext/hr/doctype/daily_work_summary/daily_work_summary.py
+++ b/erpnext/hr/doctype/daily_work_summary/daily_work_summary.py
@@ -3,11 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
-from frappe import _
from email_reply_parser import EmailReplyParser
-from erpnext.hr.doctype.employee.employee import is_holiday
+from frappe import _
+from frappe.model.document import Document
from frappe.utils import global_date_format
from six import string_types
@@ -82,7 +82,7 @@ class DailyWorkSummary(Document):
crop=True
)
d.image = thumbnail_image
- except:
+ except Exception:
d.image = original_image
if d.sender in did_not_reply:
diff --git a/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.js b/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.js
deleted file mode 100644
index 15335171473..00000000000
--- a/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Daily Work Summary", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Daily Work Summary
- () => frappe.tests.make('Daily Work Summary', [
- // values to be set
- { key: 'value' }
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.py b/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.py
index 38684799763..bed12e31eaa 100644
--- a/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.py
+++ b/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.py
@@ -4,8 +4,9 @@
from __future__ import unicode_literals
import os
-import frappe
import unittest
+
+import frappe
import frappe.utils
# test_records = frappe.get_test_records('Daily Work Summary')
@@ -64,8 +65,7 @@ class TestDailyWorkSummary(unittest.TestCase):
filters=dict(email=('!=', 'test@example.com')))
self.setup_groups(hour)
- from erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group \
- import trigger_emails
+ from erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group import trigger_emails
trigger_emails()
# check if emails are created
diff --git a/erpnext/hr/doctype/daily_work_summary_group/daily_work_summary_group.py b/erpnext/hr/doctype/daily_work_summary_group/daily_work_summary_group.py
index ece331aa718..152b1a9c7c5 100644
--- a/erpnext/hr/doctype/daily_work_summary_group/daily_work_summary_group.py
+++ b/erpnext/hr/doctype/daily_work_summary_group/daily_work_summary_group.py
@@ -3,13 +3,16 @@
# # For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
import frappe.utils
from frappe import _
+from frappe.model.document import Document
+
from erpnext.hr.doctype.daily_work_summary.daily_work_summary import get_user_emails_from_group
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
+
class DailyWorkSummaryGroup(Document):
def validate(self):
if self.users:
diff --git a/erpnext/hr/doctype/daily_work_summary_group_user/daily_work_summary_group_user.py b/erpnext/hr/doctype/daily_work_summary_group_user/daily_work_summary_group_user.py
index eefcc0c3a65..d69a7fbf987 100644
--- a/erpnext/hr/doctype/daily_work_summary_group_user/daily_work_summary_group_user.py
+++ b/erpnext/hr/doctype/daily_work_summary_group_user/daily_work_summary_group_user.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class DailyWorkSummaryGroupUser(Document):
pass
diff --git a/erpnext/hr/doctype/department/department.py b/erpnext/hr/doctype/department/department.py
index 539a360269f..b4771b3fed0 100644
--- a/erpnext/hr/doctype/department/department.py
+++ b/erpnext/hr/doctype/department/department.py
@@ -2,10 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.utils.nestedset import NestedSet, get_root_of
+
from erpnext.utilities.transaction_base import delete_events
-from frappe.model.document import Document
+
class Department(NestedSet):
nsm_parent_field = 'parent_department'
diff --git a/erpnext/hr/doctype/department/test_department.js b/erpnext/hr/doctype/department/test_department.js
deleted file mode 100644
index e73779c97c6..00000000000
--- a/erpnext/hr/doctype/department/test_department.js
+++ /dev/null
@@ -1,23 +0,0 @@
-QUnit.module('hr');
-
-QUnit.test("Test: Department [HR]", function (assert) {
- assert.expect(1);
- let done = assert.async();
-
- frappe.run_serially([
- // test department creation
- () => frappe.set_route("List", "Department", "List"),
- () => frappe.new_doc("Department"),
- () => frappe.timeout(1),
- () => frappe.quick_entry.dialog.$wrapper.find('.edit-full').click(),
- () => frappe.timeout(1),
- () => cur_frm.set_value("department_name", "Test Department"),
- () => cur_frm.set_value("leave_block_list", "Test Leave block list"),
- // save form
- () => cur_frm.save(),
- () => frappe.timeout(1),
- () => assert.equal("Test Department", cur_frm.doc.department_name,
- 'name of department correctly saved'),
- () => done()
- ]);
-});
diff --git a/erpnext/hr/doctype/department/test_department.py b/erpnext/hr/doctype/department/test_department.py
index e4f6645ee42..2fb3b95ef43 100644
--- a/erpnext/hr/doctype/department/test_department.py
+++ b/erpnext/hr/doctype/department/test_department.py
@@ -1,9 +1,11 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import unittest
+import frappe
+
test_ignore = ["Leave Block List"]
class TestDepartment(unittest.TestCase):
def test_remove_department_data(self):
diff --git a/erpnext/hr/doctype/department_approver/department_approver.py b/erpnext/hr/doctype/department_approver/department_approver.py
index d337959d534..113ea1887fc 100644
--- a/erpnext/hr/doctype/department_approver/department_approver.py
+++ b/erpnext/hr/doctype/department_approver/department_approver.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
class DepartmentApprover(Document):
pass
diff --git a/erpnext/hr/doctype/designation/designation.py b/erpnext/hr/doctype/designation/designation.py
index a3f84aab5f0..0291a992cd9 100644
--- a/erpnext/hr/doctype/designation/designation.py
+++ b/erpnext/hr/doctype/designation/designation.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class Designation(Document):
pass
diff --git a/erpnext/hr/doctype/designation/test_designation.js b/erpnext/hr/doctype/designation/test_designation.js
deleted file mode 100644
index 00adf8293f7..00000000000
--- a/erpnext/hr/doctype/designation/test_designation.js
+++ /dev/null
@@ -1,23 +0,0 @@
-QUnit.module('hr');
-
-QUnit.test("Test: Designation [HR]", function (assert) {
- assert.expect(1);
- let done = assert.async();
-
- frappe.run_serially([
- // test designation creation
- () => frappe.set_route("List", "Designation", "List"),
- () => frappe.new_doc("Designation"),
- () => frappe.timeout(1),
- () => frappe.quick_entry.dialog.$wrapper.find('.edit-full').click(),
- () => frappe.timeout(1),
- () => cur_frm.set_value("designation_name", "Test Designation"),
- () => cur_frm.set_value("description", "This designation is just for testing."),
- // save form
- () => cur_frm.save(),
- () => frappe.timeout(1),
- () => assert.equal("Test Designation", cur_frm.doc.designation_name,
- 'name of designation correctly saved'),
- () => done()
- ]);
-});
diff --git a/erpnext/hr/doctype/designation/test_designation.py b/erpnext/hr/doctype/designation/test_designation.py
index 2778862a1c2..33aa2433cee 100644
--- a/erpnext/hr/doctype/designation/test_designation.py
+++ b/erpnext/hr/doctype/designation/test_designation.py
@@ -2,8 +2,8 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
# test_records = frappe.get_test_records('Designation')
def create_designation(**args):
diff --git a/erpnext/hr/doctype/designation_skill/designation_skill.py b/erpnext/hr/doctype/designation_skill/designation_skill.py
index c37d21f454e..2074dc9df51 100644
--- a/erpnext/hr/doctype/designation_skill/designation_skill.py
+++ b/erpnext/hr/doctype/designation_skill/designation_skill.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class DesignationSkill(Document):
pass
diff --git a/erpnext/hr/doctype/driver/driver.py b/erpnext/hr/doctype/driver/driver.py
index 2cd22cd5480..5c428b57fc9 100644
--- a/erpnext/hr/doctype/driver/driver.py
+++ b/erpnext/hr/doctype/driver/driver.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class Driver(Document):
pass
diff --git a/erpnext/hr/doctype/driver/test_driver.js b/erpnext/hr/doctype/driver/test_driver.js
deleted file mode 100644
index ff9f61e66a6..00000000000
--- a/erpnext/hr/doctype/driver/test_driver.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Driver", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Driver
- () => frappe.tests.make('Driver', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/driver/test_driver.py b/erpnext/hr/doctype/driver/test_driver.py
index 4bc4a8fd57b..fa3623745ba 100644
--- a/erpnext/hr/doctype/driver/test_driver.py
+++ b/erpnext/hr/doctype/driver/test_driver.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestDriver(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/driving_license_category/driving_license_category.py b/erpnext/hr/doctype/driving_license_category/driving_license_category.py
index 33ba138e27c..63ac4184bd9 100644
--- a/erpnext/hr/doctype/driving_license_category/driving_license_category.py
+++ b/erpnext/hr/doctype/driving_license_category/driving_license_category.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class DrivingLicenseCategory(Document):
pass
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 643f3da2ff7..79e8f6140aa 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -1,15 +1,21 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import frappe
-
-from frappe.utils import getdate, validate_email_address, today, add_years, cstr
+from frappe import _, scrub, throw
from frappe.model.naming import set_name_by_naming_series
-from frappe import throw, _, scrub
-from frappe.permissions import add_user_permission, remove_user_permission, \
- set_user_permission_if_allowed, has_permission, get_doc_permissions
-from erpnext.utilities.transaction_base import delete_events
+from frappe.permissions import (
+ add_user_permission,
+ get_doc_permissions,
+ has_permission,
+ remove_user_permission,
+ set_user_permission_if_allowed,
+)
+from frappe.utils import add_years, cstr, getdate, today, validate_email_address
from frappe.utils.nestedset import NestedSet
+from erpnext.utilities.transaction_base import delete_events
+
+
class EmployeeUserDisabledError(frappe.ValidationError):
pass
class InactiveEmployeeStatusError(frappe.ValidationError):
diff --git a/erpnext/hr/doctype/employee/employee_dashboard.py b/erpnext/hr/doctype/employee/employee_dashboard.py
index e853bee69f2..ce307be60e8 100644
--- a/erpnext/hr/doctype/employee/employee_dashboard.py
+++ b/erpnext/hr/doctype/employee/employee_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'heatmap': True,
diff --git a/erpnext/hr/doctype/employee/employee_reminders.py b/erpnext/hr/doctype/employee/employee_reminders.py
index 2155c027a9b..ba086dc0602 100644
--- a/erpnext/hr/doctype/employee/employee_reminders.py
+++ b/erpnext/hr/doctype/employee/employee_reminders.py
@@ -3,15 +3,17 @@
import frappe
from frappe import _
-from frappe.utils import comma_sep, getdate, today, add_months, add_days
+from frappe.utils import add_days, add_months, comma_sep, getdate, today
+
from erpnext.hr.doctype.employee.employee import get_all_employee_emails, get_employee_email
from erpnext.hr.utils import get_holidays_for_employee
+
# -----------------
# HOLIDAY REMINDERS
# -----------------
def send_reminders_in_advance_weekly():
- to_send_in_advance = int(frappe.db.get_single_value("HR Settings", "send_holiday_reminders") or 1)
+ to_send_in_advance = int(frappe.db.get_single_value("HR Settings", "send_holiday_reminders"))
frequency = frappe.db.get_single_value("HR Settings", "frequency")
if not (to_send_in_advance and frequency == "Weekly"):
return
@@ -19,7 +21,7 @@ def send_reminders_in_advance_weekly():
send_advance_holiday_reminders("Weekly")
def send_reminders_in_advance_monthly():
- to_send_in_advance = int(frappe.db.get_single_value("HR Settings", "send_holiday_reminders") or 1)
+ to_send_in_advance = int(frappe.db.get_single_value("HR Settings", "send_holiday_reminders"))
frequency = frappe.db.get_single_value("HR Settings", "frequency")
if not (to_send_in_advance and frequency == "Monthly"):
return
@@ -77,7 +79,7 @@ def send_holidays_reminder_in_advance(employee, holidays):
# ------------------
def send_birthday_reminders():
"""Send Employee birthday reminders if no 'Stop Birthday Reminders' is not set."""
- to_send = int(frappe.db.get_single_value("HR Settings", "send_birthday_reminders") or 1)
+ to_send = int(frappe.db.get_single_value("HR Settings", "send_birthday_reminders"))
if not to_send:
return
diff --git a/erpnext/hr/doctype/employee/test_employee.py b/erpnext/hr/doctype/employee/test_employee.py
index 5feb6de8f2b..8d6dfa2c1d2 100644
--- a/erpnext/hr/doctype/employee/test_employee.py
+++ b/erpnext/hr/doctype/employee/test_employee.py
@@ -1,10 +1,12 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-import frappe
-import erpnext
import unittest
+
+import frappe
import frappe.utils
+
+import erpnext
from erpnext.hr.doctype.employee.employee import InactiveEmployeeStatusError
test_records = frappe.get_test_records('Employee')
@@ -23,9 +25,9 @@ class TestEmployee(unittest.TestCase):
self.assertRaises(InactiveEmployeeStatusError, employee1_doc.save)
def test_employee_status_inactive(self):
- from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
- from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_holiday_list
+ from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
+ from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
employee = make_employee("test_employee_status@company.com")
employee_doc = frappe.get_doc("Employee", employee)
diff --git a/erpnext/hr/doctype/employee/test_employee_reminders.py b/erpnext/hr/doctype/employee/test_employee_reminders.py
index 7e560f512d1..52c00982443 100644
--- a/erpnext/hr/doctype/employee/test_employee_reminders.py
+++ b/erpnext/hr/doctype/employee/test_employee_reminders.py
@@ -1,11 +1,12 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-import frappe
import unittest
-
-from frappe.utils import getdate
from datetime import timedelta
+
+import frappe
+from frappe.utils import getdate
+
from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.hr.doctype.hr_settings.hr_settings import set_proceed_with_frequency_change
@@ -18,7 +19,7 @@ class TestEmployeeReminders(unittest.TestCase):
# Create a test holiday list
test_holiday_dates = cls.get_test_holiday_dates()
test_holiday_list = make_holiday_list(
- 'TestHolidayRemindersList',
+ 'TestHolidayRemindersList',
holiday_dates=[
{'holiday_date': test_holiday_dates[0], 'description': 'test holiday1'},
{'holiday_date': test_holiday_dates[1], 'description': 'test holiday2'},
@@ -49,8 +50,8 @@ class TestEmployeeReminders(unittest.TestCase):
def get_test_holiday_dates(cls):
today_date = getdate()
return [
- today_date,
- today_date-timedelta(days=4),
+ today_date,
+ today_date-timedelta(days=4),
today_date-timedelta(days=3),
today_date+timedelta(days=1),
today_date+timedelta(days=3),
@@ -63,7 +64,7 @@ class TestEmployeeReminders(unittest.TestCase):
def test_is_holiday(self):
from erpnext.hr.doctype.employee.employee import is_holiday
-
+
self.assertTrue(is_holiday(self.test_employee.name))
self.assertTrue(is_holiday(self.test_employee.name, date=self.test_holiday_dates[1]))
self.assertFalse(is_holiday(self.test_employee.name, date=getdate()-timedelta(days=1)))
@@ -84,7 +85,10 @@ class TestEmployeeReminders(unittest.TestCase):
employee.company = "_Test Company"
employee.save()
- from erpnext.hr.doctype.employee.employee_reminders import get_employees_who_are_born_today, send_birthday_reminders
+ from erpnext.hr.doctype.employee.employee_reminders import (
+ get_employees_who_are_born_today,
+ send_birthday_reminders,
+ )
employees_born_today = get_employees_who_are_born_today()
self.assertTrue(employees_born_today.get("_Test Company"))
@@ -105,7 +109,10 @@ class TestEmployeeReminders(unittest.TestCase):
employee.company = "_Test Company"
employee.save()
- from erpnext.hr.doctype.employee.employee_reminders import get_employees_having_an_event_today, send_work_anniversary_reminders
+ from erpnext.hr.doctype.employee.employee_reminders import (
+ get_employees_having_an_event_today,
+ send_work_anniversary_reminders,
+ )
employees_having_work_anniversary = get_employees_having_an_event_today('work_anniversary')
self.assertTrue(employees_having_work_anniversary.get("_Test Company"))
@@ -118,10 +125,10 @@ class TestEmployeeReminders(unittest.TestCase):
email_queue = frappe.db.sql("""select * from `tabEmail Queue`""", as_dict=True)
self.assertTrue("Subject: Work Anniversary Reminder" in email_queue[0].message)
-
+
def test_send_holidays_reminder_in_advance(self):
- from erpnext.hr.utils import get_holidays_for_employee
from erpnext.hr.doctype.employee.employee_reminders import send_holidays_reminder_in_advance
+ from erpnext.hr.utils import get_holidays_for_employee
# Get HR settings and enable advance holiday reminders
hr_settings = frappe.get_doc("HR Settings", "HR Settings")
@@ -133,10 +140,10 @@ class TestEmployeeReminders(unittest.TestCase):
holidays = get_holidays_for_employee(
self.test_employee.get('name'),
getdate(), getdate() + timedelta(days=3),
- only_non_weekly=True,
+ only_non_weekly=True,
raise_exception=False
)
-
+
send_holidays_reminder_in_advance(
self.test_employee.get('name'),
holidays
@@ -147,6 +154,7 @@ class TestEmployeeReminders(unittest.TestCase):
def test_advance_holiday_reminders_monthly(self):
from erpnext.hr.doctype.employee.employee_reminders import send_reminders_in_advance_monthly
+
# Get HR settings and enable advance holiday reminders
hr_settings = frappe.get_doc("HR Settings", "HR Settings")
hr_settings.send_holiday_reminders = 1
@@ -158,9 +166,10 @@ class TestEmployeeReminders(unittest.TestCase):
email_queue = frappe.db.sql("""select * from `tabEmail Queue`""", as_dict=True)
self.assertTrue(len(email_queue) > 0)
-
+
def test_advance_holiday_reminders_weekly(self):
from erpnext.hr.doctype.employee.employee_reminders import send_reminders_in_advance_weekly
+
# Get HR settings and enable advance holiday reminders
hr_settings = frappe.get_doc("HR Settings", "HR Settings")
hr_settings.send_holiday_reminders = 1
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py
index cbb3cc813b4..87d42d34e39 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.py
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.py
@@ -3,13 +3,17 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+
+import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import flt, nowdate
+
+import erpnext
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
from erpnext.hr.utils import validate_active_employee
+
class EmployeeAdvanceOverPayment(frappe.ValidationError):
pass
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py b/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py
index 2f493e2d4e6..17d5bd27a6e 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py
+++ b/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/hr/doctype/employee_advance/test_employee_advance.js b/erpnext/hr/doctype/employee_advance/test_employee_advance.js
deleted file mode 100644
index 1b9ec6f6d0c..00000000000
--- a/erpnext/hr/doctype/employee_advance/test_employee_advance.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Advance", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Advance
- () => frappe.tests.make('Employee Advance', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/employee_advance/test_employee_advance.py b/erpnext/hr/doctype/employee_advance/test_employee_advance.py
index 100968bb7aa..f8e5f535cb5 100644
--- a/erpnext/hr/doctype/employee_advance/test_employee_advance.py
+++ b/erpnext/hr/doctype/employee_advance/test_employee_advance.py
@@ -3,12 +3,18 @@
# See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
import unittest
+
+import frappe
from frappe.utils import nowdate
-from erpnext.hr.doctype.employee_advance.employee_advance import make_bank_entry
-from erpnext.hr.doctype.employee_advance.employee_advance import EmployeeAdvanceOverPayment
+
+import erpnext
from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.hr.doctype.employee_advance.employee_advance import (
+ EmployeeAdvanceOverPayment,
+ make_bank_entry,
+)
+
class TestEmployeeAdvance(unittest.TestCase):
def test_paid_amount_and_status(self):
diff --git a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py
index 16c1a32b9b5..7c751a47a6b 100644
--- a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py
+++ b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
+
+import frappe
from frappe.model.document import Document
from frappe.utils import getdate
diff --git a/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.py b/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.py
index 496f1653ba0..48c85f48aa2 100644
--- a/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.py
+++ b/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class EmployeeBoardingActivity(Document):
pass
diff --git a/erpnext/hr/doctype/employee_checkin/employee_checkin.py b/erpnext/hr/doctype/employee_checkin/employee_checkin.py
index 6c0cd4f963b..1ae9b1fa829 100644
--- a/erpnext/hr/doctype/employee_checkin/employee_checkin.py
+++ b/erpnext/hr/doctype/employee_checkin/employee_checkin.py
@@ -3,14 +3,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import now, cint, get_datetime
-from frappe.model.document import Document
-from frappe import _
-from erpnext.hr.doctype.shift_assignment.shift_assignment import get_actual_start_end_datetime_of_shift
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from frappe.utils import cint, get_datetime
+
+from erpnext.hr.doctype.shift_assignment.shift_assignment import (
+ get_actual_start_end_datetime_of_shift,
+)
from erpnext.hr.utils import validate_active_employee
+
class EmployeeCheckin(Document):
def validate(self):
validate_active_employee(self.employee)
diff --git a/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py b/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py
index 7ba511f08d5..71c6498dd7c 100644
--- a/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py
+++ b/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py
@@ -3,13 +3,19 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import now_datetime, nowdate, to_timedelta
import unittest
from datetime import timedelta
-from erpnext.hr.doctype.employee_checkin.employee_checkin import add_log_based_on_employee_field, mark_attendance_and_link_log, calculate_working_hours
+import frappe
+from frappe.utils import now_datetime, nowdate
+
from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.hr.doctype.employee_checkin.employee_checkin import (
+ add_log_based_on_employee_field,
+ calculate_working_hours,
+ mark_attendance_and_link_log,
+)
+
class TestEmployeeCheckin(unittest.TestCase):
def test_add_log_based_on_employee_field(self):
diff --git a/erpnext/hr/doctype/employee_education/employee_education.py b/erpnext/hr/doctype/employee_education/employee_education.py
index f0a76172b2c..cadf5d64594 100644
--- a/erpnext/hr/doctype/employee_education/employee_education.py
+++ b/erpnext/hr/doctype/employee_education/employee_education.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class EmployeeEducation(Document):
pass
diff --git a/erpnext/hr/doctype/employee_external_work_history/employee_external_work_history.py b/erpnext/hr/doctype/employee_external_work_history/employee_external_work_history.py
index 517ef57be85..4d0e8d9b74a 100644
--- a/erpnext/hr/doctype/employee_external_work_history/employee_external_work_history.py
+++ b/erpnext/hr/doctype/employee_external_work_history/employee_external_work_history.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class EmployeeExternalWorkHistory(Document):
pass
diff --git a/erpnext/hr/doctype/employee_grade/employee_grade.py b/erpnext/hr/doctype/employee_grade/employee_grade.py
index 42a9f161359..b097038b5c2 100644
--- a/erpnext/hr/doctype/employee_grade/employee_grade.py
+++ b/erpnext/hr/doctype/employee_grade/employee_grade.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class EmployeeGrade(Document):
pass
diff --git a/erpnext/hr/doctype/employee_grade/employee_grade_dashboard.py b/erpnext/hr/doctype/employee_grade/employee_grade_dashboard.py
index df679104185..92d9fa082c9 100644
--- a/erpnext/hr/doctype/employee_grade/employee_grade_dashboard.py
+++ b/erpnext/hr/doctype/employee_grade/employee_grade_dashboard.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+
def get_data():
return {
'transactions': [
diff --git a/erpnext/hr/doctype/employee_grade/test_employee_grade.js b/erpnext/hr/doctype/employee_grade/test_employee_grade.js
deleted file mode 100644
index d684fb2ad1b..00000000000
--- a/erpnext/hr/doctype/employee_grade/test_employee_grade.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Grade", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Grade
- () => frappe.tests.make('Employee Grade', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/employee_grade/test_employee_grade.py b/erpnext/hr/doctype/employee_grade/test_employee_grade.py
index 93058cf1083..cd4fcb5aeb4 100644
--- a/erpnext/hr/doctype/employee_grade/test_employee_grade.py
+++ b/erpnext/hr/doctype/employee_grade/test_employee_grade.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestEmployeeGrade(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/employee_grievance/employee_grievance.py b/erpnext/hr/doctype/employee_grievance/employee_grievance.py
index 17055829efb..fd9a33b3771 100644
--- a/erpnext/hr/doctype/employee_grievance/employee_grievance.py
+++ b/erpnext/hr/doctype/employee_grievance/employee_grievance.py
@@ -5,6 +5,7 @@ import frappe
from frappe import _, bold
from frappe.model.document import Document
+
class EmployeeGrievance(Document):
def on_submit(self):
if self.status not in ["Invalid", "Resolved"]:
diff --git a/erpnext/hr/doctype/employee_grievance/test_employee_grievance.py b/erpnext/hr/doctype/employee_grievance/test_employee_grievance.py
index ed897ee1032..e2d0002aa62 100644
--- a/erpnext/hr/doctype/employee_grievance/test_employee_grievance.py
+++ b/erpnext/hr/doctype/employee_grievance/test_employee_grievance.py
@@ -1,10 +1,14 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
-import frappe
import unittest
+
+import frappe
from frappe.utils import today
+
from erpnext.hr.doctype.employee.test_employee import make_employee
+
+
class TestEmployeeGrievance(unittest.TestCase):
def test_create_employee_grievance(self):
create_employee_grievance()
diff --git a/erpnext/hr/doctype/employee_group/employee_group.py b/erpnext/hr/doctype/employee_group/employee_group.py
index 3025877b8e1..b2fe5eb3ad6 100644
--- a/erpnext/hr/doctype/employee_group/employee_group.py
+++ b/erpnext/hr/doctype/employee_group/employee_group.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class EmployeeGroup(Document):
pass
diff --git a/erpnext/hr/doctype/employee_group/test_employee_group.py b/erpnext/hr/doctype/employee_group/test_employee_group.py
index 26a61c407b2..053e840740a 100644
--- a/erpnext/hr/doctype/employee_group/test_employee_group.py
+++ b/erpnext/hr/doctype/employee_group/test_employee_group.py
@@ -2,10 +2,14 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
-import frappe
+
import unittest
+
+import frappe
+
from erpnext.hr.doctype.employee.test_employee import make_employee
+
class TestEmployeeGroup(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/employee_group_table/employee_group_table.py b/erpnext/hr/doctype/employee_group_table/employee_group_table.py
index 816611d018d..d9407a96fa6 100644
--- a/erpnext/hr/doctype/employee_group_table/employee_group_table.py
+++ b/erpnext/hr/doctype/employee_group_table/employee_group_table.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class EmployeeGroupTable(Document):
pass
diff --git a/erpnext/hr/doctype/employee_health_insurance/employee_health_insurance.py b/erpnext/hr/doctype/employee_health_insurance/employee_health_insurance.py
index abc01ef8d4b..4f2d1a07653 100644
--- a/erpnext/hr/doctype/employee_health_insurance/employee_health_insurance.py
+++ b/erpnext/hr/doctype/employee_health_insurance/employee_health_insurance.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class EmployeeHealthInsurance(Document):
pass
diff --git a/erpnext/hr/doctype/employee_health_insurance/test_employee_health_insurance.js b/erpnext/hr/doctype/employee_health_insurance/test_employee_health_insurance.js
deleted file mode 100644
index 245cb32971f..00000000000
--- a/erpnext/hr/doctype/employee_health_insurance/test_employee_health_insurance.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Health Insurance", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Health Insurance
- () => frappe.tests.make('Employee Health Insurance', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/employee_health_insurance/test_employee_health_insurance.py b/erpnext/hr/doctype/employee_health_insurance/test_employee_health_insurance.py
index f0787f52d20..38e3ee316bb 100644
--- a/erpnext/hr/doctype/employee_health_insurance/test_employee_health_insurance.py
+++ b/erpnext/hr/doctype/employee_health_insurance/test_employee_health_insurance.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestEmployeeHealthInsurance(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/employee_internal_work_history/employee_internal_work_history.py b/erpnext/hr/doctype/employee_internal_work_history/employee_internal_work_history.py
index 2f385a8113e..6076abb3468 100644
--- a/erpnext/hr/doctype/employee_internal_work_history/employee_internal_work_history.py
+++ b/erpnext/hr/doctype/employee_internal_work_history/employee_internal_work_history.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class EmployeeInternalWorkHistory(Document):
pass
diff --git a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py
index 0cb50475bf8..7421e17ca84 100644
--- a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py
+++ b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py
@@ -3,11 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from erpnext.hr.utils import EmployeeBoardingController
from frappe.model.mapper import get_mapped_doc
+from erpnext.hr.utils import EmployeeBoardingController
+
+
class IncompleteTaskError(frappe.ValidationError): pass
class EmployeeOnboarding(EmployeeBoardingController):
diff --git a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.js b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.js
deleted file mode 100644
index d15cef77dca..00000000000
--- a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Onboarding", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Onboarding
- () => frappe.tests.make('Employee Onboarding', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
index 336e13c9b77..33cad7b7e9b 100644
--- a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
+++ b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
@@ -3,13 +3,18 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
from frappe.utils import nowdate
-from erpnext.hr.doctype.employee_onboarding.employee_onboarding import make_employee
-from erpnext.hr.doctype.employee_onboarding.employee_onboarding import IncompleteTaskError
+
+from erpnext.hr.doctype.employee_onboarding.employee_onboarding import (
+ IncompleteTaskError,
+ make_employee,
+)
from erpnext.hr.doctype.job_offer.test_job_offer import create_job_offer
+
class TestEmployeeOnboarding(unittest.TestCase):
def test_employee_onboarding_incomplete_task(self):
if frappe.db.exists('Employee Onboarding', {'employee_name': 'Test Researcher'}):
diff --git a/erpnext/hr/doctype/employee_onboarding_activity/employee_onboarding_activity.py b/erpnext/hr/doctype/employee_onboarding_activity/employee_onboarding_activity.py
index d1706318191..526c2c9cde6 100644
--- a/erpnext/hr/doctype/employee_onboarding_activity/employee_onboarding_activity.py
+++ b/erpnext/hr/doctype/employee_onboarding_activity/employee_onboarding_activity.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class EmployeeOnboardingActivity(Document):
pass
diff --git a/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.py b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.py
index 6f1c3167315..a46b3cdda39 100644
--- a/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.py
+++ b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class EmployeeOnboardingTemplate(Document):
pass
diff --git a/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template_dashboard.py b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template_dashboard.py
index ab0eb2f5dce..1d2e8ae18db 100644
--- a/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template_dashboard.py
+++ b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.js b/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.js
deleted file mode 100644
index 10912edb6ac..00000000000
--- a/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Onboarding Template", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Onboarding Template
- () => frappe.tests.make('Employee Onboarding Template', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.py b/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.py
index f4b5b883428..92a328b71ef 100644
--- a/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.py
+++ b/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestEmployeeOnboardingTemplate(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/employee_promotion/employee_promotion.py b/erpnext/hr/doctype/employee_promotion/employee_promotion.py
index a3a61834c8c..164d48b8952 100644
--- a/erpnext/hr/doctype/employee_promotion/employee_promotion.py
+++ b/erpnext/hr/doctype/employee_promotion/employee_promotion.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import getdate
+
from erpnext.hr.utils import update_employee, validate_active_employee
+
class EmployeePromotion(Document):
def validate(self):
validate_active_employee(self.employee)
diff --git a/erpnext/hr/doctype/employee_promotion/test_employee_promotion.js b/erpnext/hr/doctype/employee_promotion/test_employee_promotion.js
deleted file mode 100644
index 5f0a5baf818..00000000000
--- a/erpnext/hr/doctype/employee_promotion/test_employee_promotion.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Promotion", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Promotion
- () => frappe.tests.make('Employee Promotion', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/employee_promotion/test_employee_promotion.py b/erpnext/hr/doctype/employee_promotion/test_employee_promotion.py
index 9e7d3186b88..39af6ff7cc7 100644
--- a/erpnext/hr/doctype/employee_promotion/test_employee_promotion.py
+++ b/erpnext/hr/doctype/employee_promotion/test_employee_promotion.py
@@ -3,11 +3,14 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import getdate, add_days
+
+import frappe
+from frappe.utils import add_days, getdate
+
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_employee
+
class TestEmployeePromotion(unittest.TestCase):
def setUp(self):
self.employee = make_employee("employee@promotions.com")
diff --git a/erpnext/hr/doctype/employee_property_history/employee_property_history.py b/erpnext/hr/doctype/employee_property_history/employee_property_history.py
index fb67852d164..9e2549284fb 100644
--- a/erpnext/hr/doctype/employee_property_history/employee_property_history.py
+++ b/erpnext/hr/doctype/employee_property_history/employee_property_history.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class EmployeePropertyHistory(Document):
pass
diff --git a/erpnext/hr/doctype/employee_referral/employee_referral.py b/erpnext/hr/doctype/employee_referral/employee_referral.py
index 547a95e3bdf..5cb5bb5fd3a 100644
--- a/erpnext/hr/doctype/employee_referral/employee_referral.py
+++ b/erpnext/hr/doctype/employee_referral/employee_referral.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import get_link_to_form
from frappe.model.document import Document
+from frappe.utils import get_link_to_form
+
from erpnext.hr.utils import validate_active_employee
+
class EmployeeReferral(Document):
def validate(self):
validate_active_employee(self.referrer)
@@ -56,6 +59,7 @@ def create_job_applicant(source_name, target_doc=None):
@frappe.whitelist()
def create_additional_salary(doc):
import json
+
from six import string_types
if isinstance(doc, string_types):
diff --git a/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py b/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py
index caca2961a1a..85d6c2089b8 100644
--- a/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py
+++ b/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+
def get_data():
return {
'fieldname': 'employee_referral',
diff --git a/erpnext/hr/doctype/employee_referral/test_employee_referral.py b/erpnext/hr/doctype/employee_referral/test_employee_referral.py
index 599f3262240..d0ee2fcdea7 100644
--- a/erpnext/hr/doctype/employee_referral/test_employee_referral.py
+++ b/erpnext/hr/doctype/employee_referral/test_employee_referral.py
@@ -3,12 +3,18 @@
# See license.txt
from __future__ import unicode_literals
+import unittest
+
import frappe
from frappe.utils import today
+
from erpnext.hr.doctype.designation.test_designation import create_designation
-from erpnext.hr.doctype.employee_referral.employee_referral import create_job_applicant, create_additional_salary
from erpnext.hr.doctype.employee.test_employee import make_employee
-import unittest
+from erpnext.hr.doctype.employee_referral.employee_referral import (
+ create_additional_salary,
+ create_job_applicant,
+)
+
class TestEmployeeReferral(unittest.TestCase):
def test_workflow_and_status_sync(self):
diff --git a/erpnext/hr/doctype/employee_separation/employee_separation.py b/erpnext/hr/doctype/employee_separation/employee_separation.py
index b64668157b0..140115bcf0f 100644
--- a/erpnext/hr/doctype/employee_separation/employee_separation.py
+++ b/erpnext/hr/doctype/employee_separation/employee_separation.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from erpnext.hr.utils import EmployeeBoardingController
+
class EmployeeSeparation(EmployeeBoardingController):
def validate(self):
super(EmployeeSeparation, self).validate()
diff --git a/erpnext/hr/doctype/employee_separation/test_employee_separation.js b/erpnext/hr/doctype/employee_separation/test_employee_separation.js
deleted file mode 100644
index d6c635951f7..00000000000
--- a/erpnext/hr/doctype/employee_separation/test_employee_separation.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Separation", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Separation
- () => frappe.tests.make('Employee Separation', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/employee_separation/test_employee_separation.py b/erpnext/hr/doctype/employee_separation/test_employee_separation.py
index 0b72efa1378..0489e71305b 100644
--- a/erpnext/hr/doctype/employee_separation/test_employee_separation.py
+++ b/erpnext/hr/doctype/employee_separation/test_employee_separation.py
@@ -3,9 +3,10 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
test_dependencies = ["Employee Onboarding"]
class TestEmployeeSeparation(unittest.TestCase):
diff --git a/erpnext/hr/doctype/employee_separation_template/employee_separation_template.py b/erpnext/hr/doctype/employee_separation_template/employee_separation_template.py
index 0508fc462e2..7a263dcac10 100644
--- a/erpnext/hr/doctype/employee_separation_template/employee_separation_template.py
+++ b/erpnext/hr/doctype/employee_separation_template/employee_separation_template.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class EmployeeSeparationTemplate(Document):
pass
diff --git a/erpnext/hr/doctype/employee_separation_template/employee_separation_template_dashboard.py b/erpnext/hr/doctype/employee_separation_template/employee_separation_template_dashboard.py
index 75f985cec39..970ba26d794 100644
--- a/erpnext/hr/doctype/employee_separation_template/employee_separation_template_dashboard.py
+++ b/erpnext/hr/doctype/employee_separation_template/employee_separation_template_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.js b/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.js
deleted file mode 100644
index 66fd4508046..00000000000
--- a/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Separation Template", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Separation Template
- () => frappe.tests.make('Employee Separation Template', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.py b/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.py
index 3fd3d398bd1..4c91a791038 100644
--- a/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.py
+++ b/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestEmployeeSeparationTemplate(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/employee_skill/employee_skill.py b/erpnext/hr/doctype/employee_skill/employee_skill.py
index ac05fba624b..6f860c6c599 100644
--- a/erpnext/hr/doctype/employee_skill/employee_skill.py
+++ b/erpnext/hr/doctype/employee_skill/employee_skill.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class EmployeeSkill(Document):
pass
diff --git a/erpnext/hr/doctype/employee_skill_map/employee_skill_map.py b/erpnext/hr/doctype/employee_skill_map/employee_skill_map.py
index 073f02fa258..d93c22f2ab8 100644
--- a/erpnext/hr/doctype/employee_skill_map/employee_skill_map.py
+++ b/erpnext/hr/doctype/employee_skill_map/employee_skill_map.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class EmployeeSkillMap(Document):
pass
diff --git a/erpnext/hr/doctype/employee_training/employee_training.py b/erpnext/hr/doctype/employee_training/employee_training.py
index 810796d66cf..068116a77f6 100644
--- a/erpnext/hr/doctype/employee_training/employee_training.py
+++ b/erpnext/hr/doctype/employee_training/employee_training.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class EmployeeTraining(Document):
pass
diff --git a/erpnext/hr/doctype/employee_transfer/employee_transfer.py b/erpnext/hr/doctype/employee_transfer/employee_transfer.py
index c2007747fb3..b1f66098f0d 100644
--- a/erpnext/hr/doctype/employee_transfer/employee_transfer.py
+++ b/erpnext/hr/doctype/employee_transfer/employee_transfer.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import getdate
+
from erpnext.hr.utils import update_employee
+
class EmployeeTransfer(Document):
def before_submit(self):
if getdate(self.transfer_date) > getdate():
diff --git a/erpnext/hr/doctype/employee_transfer/test_employee_transfer.js b/erpnext/hr/doctype/employee_transfer/test_employee_transfer.js
deleted file mode 100644
index 05a3e1a5738..00000000000
--- a/erpnext/hr/doctype/employee_transfer/test_employee_transfer.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Transfer", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Transfer
- () => frappe.tests.make('Employee Transfer', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/employee_transfer/test_employee_transfer.py b/erpnext/hr/doctype/employee_transfer/test_employee_transfer.py
index 93fc7a27056..ad2f3ade054 100644
--- a/erpnext/hr/doctype/employee_transfer/test_employee_transfer.py
+++ b/erpnext/hr/doctype/employee_transfer/test_employee_transfer.py
@@ -3,11 +3,14 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import getdate, add_days
+
+import frappe
+from frappe.utils import add_days, getdate
+
from erpnext.hr.doctype.employee.test_employee import make_employee
+
class TestEmployeeTransfer(unittest.TestCase):
def setUp(self):
make_employee("employee2@transfers.com")
diff --git a/erpnext/hr/doctype/employee_transfer_property/employee_transfer_property.py b/erpnext/hr/doctype/employee_transfer_property/employee_transfer_property.py
index 1a665dc1008..f67fd7c6564 100644
--- a/erpnext/hr/doctype/employee_transfer_property/employee_transfer_property.py
+++ b/erpnext/hr/doctype/employee_transfer_property/employee_transfer_property.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class EmployeeTransferProperty(Document):
pass
diff --git a/erpnext/hr/doctype/employee_transfer_property/test_employee_transfer_property.js b/erpnext/hr/doctype/employee_transfer_property/test_employee_transfer_property.js
deleted file mode 100644
index 00a334a63d7..00000000000
--- a/erpnext/hr/doctype/employee_transfer_property/test_employee_transfer_property.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Transfer Property", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Transfer Property
- () => frappe.tests.make('Employee Transfer Property', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/employee_transfer_property/test_employee_transfer_property.py b/erpnext/hr/doctype/employee_transfer_property/test_employee_transfer_property.py
index 39c20a6f716..287dac66f10 100644
--- a/erpnext/hr/doctype/employee_transfer_property/test_employee_transfer_property.py
+++ b/erpnext/hr/doctype/employee_transfer_property/test_employee_transfer_property.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestEmployeeTransferProperty(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/employment_type/employment_type.py b/erpnext/hr/doctype/employment_type/employment_type.py
index 00aa6bb9bc4..e2a55570fd9 100644
--- a/erpnext/hr/doctype/employment_type/employment_type.py
+++ b/erpnext/hr/doctype/employment_type/employment_type.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class EmploymentType(Document):
pass
diff --git a/erpnext/hr/doctype/employment_type/test_employment_type.py b/erpnext/hr/doctype/employment_type/test_employment_type.py
index 0297ffa01a3..2ba4e8c1a46 100644
--- a/erpnext/hr/doctype/employment_type/test_employment_type.py
+++ b/erpnext/hr/doctype/employment_type/test_employment_type.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Employment Type')
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index 95e2806aedc..d785db7872c 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -2,17 +2,17 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+
+import frappe
from frappe import _
-from frappe.utils import get_fullname, flt, cstr, get_link_to_form
-from frappe.model.document import Document
-from erpnext.hr.utils import set_employee_name, share_doc_with_approver, validate_active_employee
-from erpnext.accounts.party import get_party_account
-from erpnext.accounts.general_ledger import make_gl_entries
+from frappe.utils import cstr, flt, get_link_to_form
+
+import erpnext
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
+from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.controllers.accounts_controller import AccountsController
-from frappe.utils.csvutils import getlink
-from erpnext.accounts.utils import get_account_currency
+from erpnext.hr.utils import set_employee_name, share_doc_with_approver, validate_active_employee
+
class InvalidExpenseApproverError(frappe.ValidationError): pass
class ExpenseApproverIdentityError(frappe.ValidationError): pass
@@ -77,7 +77,7 @@ class ExpenseClaim(AccountsController):
self.make_gl_entries()
if self.is_paid:
- update_reimbursed_amount(self)
+ update_reimbursed_amount(self, self.grand_total)
self.set_status(update=True)
self.update_claimed_amount_in_employee_advance()
@@ -89,7 +89,7 @@ class ExpenseClaim(AccountsController):
self.make_gl_entries(cancel=True)
if self.is_paid:
- update_reimbursed_amount(self)
+ update_reimbursed_amount(self, -1 * self.grand_total)
self.update_claimed_amount_in_employee_advance()
@@ -270,20 +270,10 @@ class ExpenseClaim(AccountsController):
if not expense.default_account or not validate:
expense.default_account = get_expense_claim_account(expense.expense_type, self.company)["account"]
-def update_reimbursed_amount(doc, jv=None):
+def update_reimbursed_amount(doc, amount):
- condition = ""
-
- if jv:
- condition += "and voucher_no = '{0}'".format(jv)
-
- amt = frappe.db.sql("""select ifnull(sum(debit_in_account_currency), 0) - ifnull(sum(credit_in_account_currency), 0)as amt
- from `tabGL Entry` where against_voucher_type = 'Expense Claim' and against_voucher = %s
- and party = %s {condition}""".format(condition=condition), #nosec
- (doc.name, doc.employee) ,as_dict=1)[0].amt
-
- doc.total_amount_reimbursed = amt
- frappe.db.set_value("Expense Claim", doc.name , "total_amount_reimbursed", amt)
+ doc.total_amount_reimbursed += amount
+ frappe.db.set_value("Expense Claim", doc.name , "total_amount_reimbursed", doc.total_amount_reimbursed)
doc.set_status()
frappe.db.set_value("Expense Claim", doc.name , "status", doc.status)
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim_dashboard.py b/erpnext/hr/doctype/expense_claim/expense_claim_dashboard.py
index fe973507019..a5682dc1e95 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim_dashboard.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'reference_name',
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
index c2bd1e9f9f1..e54c1457244 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
@@ -2,12 +2,14 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import random_string, nowdate
-from erpnext.hr.doctype.expense_claim.expense_claim import make_bank_entry
+
+import frappe
+from frappe.utils import flt, nowdate, random_string
+
from erpnext.accounts.doctype.account.test_account import create_account
from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.hr.doctype.expense_claim.expense_claim import make_bank_entry
test_records = frappe.get_test_records('Expense Claim')
test_dependencies = ['Employee']
@@ -138,6 +140,31 @@ class TestExpenseClaim(unittest.TestCase):
expense_claim.submit()
frappe.set_user("Administrator")
+ def test_multiple_payment_entries_against_expense(self):
+ # Creating expense claim
+ payable_account = get_payable_account("_Test Company")
+ expense_claim = make_expense_claim(payable_account, 5500, 5500, "_Test Company", "Travel Expenses - _TC")
+ expense_claim.save()
+ expense_claim.submit()
+
+ # Payment entry 1: paying 500
+ make_payment_entry(expense_claim, payable_account,500)
+ outstanding_amount, total_amount_reimbursed = get_outstanding_and_total_reimbursed_amounts(expense_claim)
+ self.assertEqual(outstanding_amount, 5000)
+ self.assertEqual(total_amount_reimbursed, 500)
+
+ # Payment entry 1: paying 2000
+ make_payment_entry(expense_claim, payable_account,2000)
+ outstanding_amount, total_amount_reimbursed = get_outstanding_and_total_reimbursed_amounts(expense_claim)
+ self.assertEqual(outstanding_amount, 3000)
+ self.assertEqual(total_amount_reimbursed, 2500)
+
+ # Payment entry 1: paying 3000
+ make_payment_entry(expense_claim, payable_account,3000)
+ outstanding_amount, total_amount_reimbursed = get_outstanding_and_total_reimbursed_amounts(expense_claim)
+ self.assertEqual(outstanding_amount, 0)
+ self.assertEqual(total_amount_reimbursed, 5500)
+
def get_payable_account(company):
return frappe.get_cached_value('Company', company, 'default_payable_account')
@@ -191,3 +218,23 @@ def make_expense_claim(payable_account, amount, sanctioned_amount, company, acco
return expense_claim
expense_claim.submit()
return expense_claim
+
+def get_outstanding_and_total_reimbursed_amounts(expense_claim):
+ outstanding_amount = flt(frappe.db.get_value("Expense Claim", expense_claim.name, "total_sanctioned_amount")) - \
+ flt(frappe.db.get_value("Expense Claim", expense_claim.name, "total_amount_reimbursed"))
+ total_amount_reimbursed = flt(frappe.db.get_value("Expense Claim", expense_claim.name, "total_amount_reimbursed"))
+
+ return outstanding_amount,total_amount_reimbursed
+
+def make_payment_entry(expense_claim, payable_account, amt):
+ from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
+
+ pe = get_payment_entry("Expense Claim", expense_claim.name, bank_account="_Test Bank USD - _TC", bank_amount=amt)
+ pe.reference_no = "1"
+ pe.reference_date = nowdate()
+ pe.source_exchange_rate = 1
+ pe.paid_to = payable_account
+ pe.references[0].allocated_amount = amt
+ pe.insert()
+ pe.submit()
+
diff --git a/erpnext/hr/doctype/expense_claim_account/expense_claim_account.py b/erpnext/hr/doctype/expense_claim_account/expense_claim_account.py
index f34633cf58b..a982002ebb4 100644
--- a/erpnext/hr/doctype/expense_claim_account/expense_claim_account.py
+++ b/erpnext/hr/doctype/expense_claim_account/expense_claim_account.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ExpenseClaimAccount(Document):
pass
diff --git a/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.py b/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.py
index c4e7b026e3b..5607f41d917 100644
--- a/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.py
+++ b/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ExpenseClaimAdvance(Document):
pass
diff --git a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.py b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.py
index 5d48990c5ce..019e9f4dfe2 100644
--- a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.py
+++ b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class ExpenseClaimDetail(Document):
pass
diff --git a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py
index a637a540213..101461c54b1 100644
--- a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py
+++ b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py
@@ -2,10 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
class ExpenseClaimType(Document):
def validate(self):
self.validate_accounts()
diff --git a/erpnext/hr/doctype/expense_claim_type/test_expense_claim_type.py b/erpnext/hr/doctype/expense_claim_type/test_expense_claim_type.py
index 1d894308d3a..f0c900e6ef0 100644
--- a/erpnext/hr/doctype/expense_claim_type/test_expense_claim_type.py
+++ b/erpnext/hr/doctype/expense_claim_type/test_expense_claim_type.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Expense Claim Type')
diff --git a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.py b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.py
index 4103bef1ffe..596e8c719a4 100644
--- a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.py
+++ b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ExpenseTaxesandCharges(Document):
pass
diff --git a/erpnext/hr/doctype/grievance_type/grievance_type.py b/erpnext/hr/doctype/grievance_type/grievance_type.py
index 618cf0a0318..5d8d41cb73d 100644
--- a/erpnext/hr/doctype/grievance_type/grievance_type.py
+++ b/erpnext/hr/doctype/grievance_type/grievance_type.py
@@ -4,5 +4,6 @@
# import frappe
from frappe.model.document import Document
+
class GrievanceType(Document):
pass
diff --git a/erpnext/hr/doctype/grievance_type/test_grievance_type.py b/erpnext/hr/doctype/grievance_type/test_grievance_type.py
index a02a34d41fa..481f4e58a79 100644
--- a/erpnext/hr/doctype/grievance_type/test_grievance_type.py
+++ b/erpnext/hr/doctype/grievance_type/test_grievance_type.py
@@ -4,5 +4,6 @@
# import frappe
import unittest
+
class TestGrievanceType(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/holiday/holiday.py b/erpnext/hr/doctype/holiday/holiday.py
index 78a95b9b741..fbfe7563aa2 100644
--- a/erpnext/hr/doctype/holiday/holiday.py
+++ b/erpnext/hr/doctype/holiday/holiday.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class Holiday(Document):
pass
diff --git a/erpnext/hr/doctype/holiday_list/holiday_list.py b/erpnext/hr/doctype/holiday_list/holiday_list.py
index 8af8cea605d..8d91ac2ddd7 100644
--- a/erpnext/hr/doctype/holiday_list/holiday_list.py
+++ b/erpnext/hr/doctype/holiday_list/holiday_list.py
@@ -3,11 +3,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import json
-from frappe.utils import cint, getdate, formatdate, today
-from frappe import throw, _
+
+import frappe
+from frappe import _, throw
from frappe.model.document import Document
+from frappe.utils import cint, formatdate, getdate, today
+
class OverlapError(frappe.ValidationError): pass
@@ -44,9 +47,10 @@ class HolidayList(Document):
def get_weekly_off_date_list(self, start_date, end_date):
start_date, end_date = getdate(start_date), getdate(end_date)
- from dateutil import relativedelta
- from datetime import timedelta
import calendar
+ from datetime import timedelta
+
+ from dateutil import relativedelta
date_list = []
existing_date_list = []
diff --git a/erpnext/hr/doctype/holiday_list/holiday_list_dashboard.py b/erpnext/hr/doctype/holiday_list/holiday_list_dashboard.py
index 05641c7dc26..bbba36af875 100644
--- a/erpnext/hr/doctype/holiday_list/holiday_list_dashboard.py
+++ b/erpnext/hr/doctype/holiday_list/holiday_list_dashboard.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+
def get_data():
return {
'fieldname': 'holiday_list',
diff --git a/erpnext/hr/doctype/holiday_list/test_holiday_list.py b/erpnext/hr/doctype/holiday_list/test_holiday_list.py
index 64bed6637bd..27131932db4 100644
--- a/erpnext/hr/doctype/holiday_list/test_holiday_list.py
+++ b/erpnext/hr/doctype/holiday_list/test_holiday_list.py
@@ -2,11 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import getdate
from datetime import timedelta
+import frappe
+from frappe.utils import getdate
+
class TestHolidayList(unittest.TestCase):
def test_holiday_list(self):
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.py b/erpnext/hr/doctype/hr_settings/hr_settings.py
index a47409363c7..c295bcbc0d9 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.py
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.py
@@ -4,7 +4,6 @@
# For license information, please see license.txt
import frappe
-
from frappe.model.document import Document
from frappe.utils import format_date
diff --git a/erpnext/hr/doctype/hr_settings/test_hr_settings.js b/erpnext/hr/doctype/hr_settings/test_hr_settings.js
deleted file mode 100644
index f32640ba5c6..00000000000
--- a/erpnext/hr/doctype/hr_settings/test_hr_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: HR Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new HR Settings
- () => frappe.tests.make('HR Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/hr_settings/test_hr_settings.py b/erpnext/hr/doctype/hr_settings/test_hr_settings.py
index b0b07b0c0b3..69a060a90f9 100644
--- a/erpnext/hr/doctype/hr_settings/test_hr_settings.py
+++ b/erpnext/hr/doctype/hr_settings/test_hr_settings.py
@@ -3,11 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from erpnext.hr.doctype.employee.test_employee import make_employee
-from frappe.utils import now_datetime
-from datetime import timedelta
+
class TestHRSettings(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/identification_document_type/identification_document_type.py b/erpnext/hr/doctype/identification_document_type/identification_document_type.py
index d9d81d2fa8f..862cd374fb4 100644
--- a/erpnext/hr/doctype/identification_document_type/identification_document_type.py
+++ b/erpnext/hr/doctype/identification_document_type/identification_document_type.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class IdentificationDocumentType(Document):
pass
diff --git a/erpnext/hr/doctype/identification_document_type/test_identification_document_type.js b/erpnext/hr/doctype/identification_document_type/test_identification_document_type.js
deleted file mode 100644
index 65879098e87..00000000000
--- a/erpnext/hr/doctype/identification_document_type/test_identification_document_type.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Identification Document Type", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Identification Document Type
- () => frappe.tests.make('Identification Document Type', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/identification_document_type/test_identification_document_type.py b/erpnext/hr/doctype/identification_document_type/test_identification_document_type.py
index 1265afaf457..87f302450db 100644
--- a/erpnext/hr/doctype/identification_document_type/test_identification_document_type.py
+++ b/erpnext/hr/doctype/identification_document_type/test_identification_document_type.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestIdentificationDocumentType(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/interest/interest.py b/erpnext/hr/doctype/interest/interest.py
index 2a9c19c09d8..1b8f49f9585 100644
--- a/erpnext/hr/doctype/interest/interest.py
+++ b/erpnext/hr/doctype/interest/interest.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class Interest(Document):
pass
diff --git a/erpnext/hr/doctype/interest/test_interest.py b/erpnext/hr/doctype/interest/test_interest.py
index a7fe83bccc8..f3727bee0b0 100644
--- a/erpnext/hr/doctype/interest/test_interest.py
+++ b/erpnext/hr/doctype/interest/test_interest.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Interest')
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.py b/erpnext/hr/doctype/job_applicant/job_applicant.py
index 14aeb03a87e..6971e5b4fef 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant.py
+++ b/erpnext/hr/doctype/job_applicant/job_applicant.py
@@ -4,11 +4,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe.model.document import Document
+
import frappe
from frappe import _
+from frappe.model.document import Document
from frappe.utils import comma_and, validate_email_address
+
class DuplicationError(frappe.ValidationError): pass
class JobApplicant(Document):
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py b/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py
index ed97978a8ad..c0059431cfc 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py
+++ b/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/hr/doctype/job_applicant/test_job_applicant.py b/erpnext/hr/doctype/job_applicant/test_job_applicant.py
index 872834230e6..e583e25eae0 100644
--- a/erpnext/hr/doctype/job_applicant/test_job_applicant.py
+++ b/erpnext/hr/doctype/job_applicant/test_job_applicant.py
@@ -3,9 +3,10 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
# test_records = frappe.get_test_records('Job Applicant')
class TestJobApplicant(unittest.TestCase):
diff --git a/erpnext/hr/doctype/job_applicant_source/job_applicant_source.py b/erpnext/hr/doctype/job_applicant_source/job_applicant_source.py
index 5f543d285cf..9139584aa5c 100644
--- a/erpnext/hr/doctype/job_applicant_source/job_applicant_source.py
+++ b/erpnext/hr/doctype/job_applicant_source/job_applicant_source.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class JobApplicantSource(Document):
pass
diff --git a/erpnext/hr/doctype/job_applicant_source/test_job_applicant_source.js b/erpnext/hr/doctype/job_applicant_source/test_job_applicant_source.js
deleted file mode 100644
index c093928f321..00000000000
--- a/erpnext/hr/doctype/job_applicant_source/test_job_applicant_source.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Job Applicant Source", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Job Applicant Source
- () => frappe.tests.make('Job Applicant Source', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/job_applicant_source/test_job_applicant_source.py b/erpnext/hr/doctype/job_applicant_source/test_job_applicant_source.py
index f318df20f7c..0c29124560b 100644
--- a/erpnext/hr/doctype/job_applicant_source/test_job_applicant_source.py
+++ b/erpnext/hr/doctype/job_applicant_source/test_job_applicant_source.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestJobApplicantSource(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/job_offer/job_offer.py b/erpnext/hr/doctype/job_offer/job_offer.py
index 7e650f76917..07a7809891d 100644
--- a/erpnext/hr/doctype/job_offer/job_offer.py
+++ b/erpnext/hr/doctype/job_offer/job_offer.py
@@ -2,13 +2,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import cint
+from frappe import _
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
-from frappe import _
+from frappe.utils import cint
from frappe.utils.data import get_link_to_form
+
class JobOffer(Document):
def onload(self):
employee = frappe.db.get_value("Employee", {"job_applicant": self.job_applicant}, "name") or ""
diff --git a/erpnext/hr/doctype/job_offer/test_job_offer.py b/erpnext/hr/doctype/job_offer/test_job_offer.py
index edb21321fcc..3f3eca17e62 100644
--- a/erpnext/hr/doctype/job_offer/test_job_offer.py
+++ b/erpnext/hr/doctype/job_offer/test_job_offer.py
@@ -2,11 +2,13 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import nowdate, add_days
-from erpnext.hr.doctype.job_applicant.test_job_applicant import create_job_applicant
+
+import frappe
+from frappe.utils import add_days, nowdate
+
from erpnext.hr.doctype.designation.test_designation import create_designation
+from erpnext.hr.doctype.job_applicant.test_job_applicant import create_job_applicant
from erpnext.hr.doctype.staffing_plan.test_staffing_plan import make_company
# test_records = frappe.get_test_records('Job Offer')
diff --git a/erpnext/hr/doctype/job_offer_term/job_offer_term.py b/erpnext/hr/doctype/job_offer_term/job_offer_term.py
index 6dbe6757a70..573cc6ae21d 100644
--- a/erpnext/hr/doctype/job_offer_term/job_offer_term.py
+++ b/erpnext/hr/doctype/job_offer_term/job_offer_term.py
@@ -2,8 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class JobOfferTerm(Document):
pass
diff --git a/erpnext/hr/doctype/job_opening/job_opening.py b/erpnext/hr/doctype/job_opening/job_opening.py
index 1e897671770..38d9a718170 100644
--- a/erpnext/hr/doctype/job_opening/job_opening.py
+++ b/erpnext/hr/doctype/job_opening/job_opening.py
@@ -4,11 +4,16 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.website.website_generator import WebsiteGenerator
+import frappe
from frappe import _
-from erpnext.hr.doctype.staffing_plan.staffing_plan import get_designation_counts, get_active_staffing_plan_details
+from frappe.website.website_generator import WebsiteGenerator
+
+from erpnext.hr.doctype.staffing_plan.staffing_plan import (
+ get_active_staffing_plan_details,
+ get_designation_counts,
+)
+
class JobOpening(WebsiteGenerator):
website = frappe._dict(
diff --git a/erpnext/hr/doctype/job_opening/job_opening_dashboard.py b/erpnext/hr/doctype/job_opening/job_opening_dashboard.py
index 31ef33ef2ce..a13e2a7c23a 100644
--- a/erpnext/hr/doctype/job_opening/job_opening_dashboard.py
+++ b/erpnext/hr/doctype/job_opening/job_opening_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/hr/doctype/job_opening/test_job_opening.py b/erpnext/hr/doctype/job_opening/test_job_opening.py
index 815ce5bdb8c..a66975c91ed 100644
--- a/erpnext/hr/doctype/job_opening/test_job_opening.py
+++ b/erpnext/hr/doctype/job_opening/test_job_opening.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Job Opening')
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 4757cd3b192..e4886d7ae72 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -2,13 +2,19 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import flt, date_diff, formatdate, add_days, today, getdate
from frappe import _
from frappe.model.document import Document
-from erpnext.hr.utils import set_employee_name, get_leave_period
-from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import expire_allocation, create_leave_ledger_entry
+from frappe.utils import add_days, date_diff, flt, formatdate, getdate
+
from erpnext.hr.doctype.leave_application.leave_application import get_approved_leaves_for_period
+from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import (
+ create_leave_ledger_entry,
+ expire_allocation,
+)
+from erpnext.hr.utils import get_leave_period, set_employee_name
+
class OverlapError(frappe.ValidationError): pass
class BackDatedAllocationError(frappe.ValidationError): pass
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py b/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py
index 7a063d92eac..84423bd2b45 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index bff06e6a91c..b1850562e3a 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -1,10 +1,14 @@
from __future__ import unicode_literals
-import frappe
-import erpnext
+
import unittest
-from frappe.utils import nowdate, add_months, getdate, add_days
+
+import frappe
+from frappe.utils import add_days, add_months, getdate, nowdate
+
+import erpnext
+from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import process_expired_allocation
from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
-from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import process_expired_allocation, expire_allocation
+
class TestLeaveAllocation(unittest.TestCase):
@classmethod
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 93fb19f4a19..9e6fc6d0f14 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -2,14 +2,33 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, get_fullname, add_days, nowdate
-from erpnext.hr.utils import set_employee_name, get_leave_period, share_doc_with_approver, validate_active_employee
-from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
-from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
+from frappe.utils import (
+ add_days,
+ cint,
+ cstr,
+ date_diff,
+ flt,
+ formatdate,
+ get_fullname,
+ get_link_to_form,
+ getdate,
+ nowdate,
+)
+
from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import daterange
+from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
+from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
+from erpnext.hr.utils import (
+ get_leave_period,
+ set_employee_name,
+ share_doc_with_approver,
+ validate_active_employee,
+)
+
class LeaveDayBlockedError(frappe.ValidationError): pass
class OverlapError(frappe.ValidationError): pass
@@ -17,6 +36,8 @@ class AttendanceAlreadyMarkedError(frappe.ValidationError): pass
class NotAnOptionalHoliday(frappe.ValidationError): pass
from frappe.model.document import Document
+
+
class LeaveApplication(Document):
def get_feed(self):
return _("{0}: From {0} of type {1}").format(self.employee_name, self.leave_type)
@@ -662,26 +683,30 @@ def is_lwp(leave_type):
@frappe.whitelist()
def get_events(start, end, filters=None):
+ from frappe.desk.reportview import get_filters_cond
events = []
- employee = frappe.db.get_value("Employee", {"user_id": frappe.session.user}, ["name", "company"],
- as_dict=True)
+ employee = frappe.db.get_value("Employee",
+ filters={"user_id": frappe.session.user},
+ fieldname=["name", "company"],
+ as_dict=True
+ )
+
if employee:
employee, company = employee.name, employee.company
else:
- employee=''
- company=frappe.db.get_value("Global Defaults", None, "default_company")
+ employee = ''
+ company = frappe.db.get_value("Global Defaults", None, "default_company")
- from frappe.desk.reportview import get_filters_cond
conditions = get_filters_cond("Leave Application", filters, [])
# show department leaves for employee
if "Employee" in frappe.get_roles():
add_department_leaves(events, start, end, employee, company)
add_leaves(events, start, end, conditions)
-
add_block_dates(events, start, end, employee, company)
add_holidays(events, start, end, employee, company)
+
return events
def add_department_leaves(events, start, end, employee, company):
@@ -697,26 +722,37 @@ def add_department_leaves(events, start, end, employee, company):
filter_conditions = " and employee in (\"%s\")" % '", "'.join(department_employees)
add_leaves(events, start, end, filter_conditions=filter_conditions)
+
def add_leaves(events, start, end, filter_conditions=None):
+ from frappe.desk.reportview import build_match_conditions
conditions = []
-
if not cint(frappe.db.get_value("HR Settings", None, "show_leaves_of_all_department_members_in_calendar")):
- from frappe.desk.reportview import build_match_conditions
match_conditions = build_match_conditions("Leave Application")
if match_conditions:
conditions.append(match_conditions)
- query = """select name, from_date, to_date, employee_name, half_day,
- status, employee, docstatus
- from `tabLeave Application` where
- from_date <= %(end)s and to_date >= %(start)s <= to_date
- and docstatus < 2
- and status!='Rejected' """
+ query = """SELECT
+ docstatus,
+ name,
+ employee,
+ employee_name,
+ leave_type,
+ from_date,
+ to_date,
+ half_day,
+ status,
+ color
+ FROM `tabLeave Application`
+ WHERE
+ from_date <= %(end)s AND to_date >= %(start)s <= to_date
+ AND docstatus < 2
+ AND status != 'Rejected'
+ """
if conditions:
- query += ' and ' + ' and '.join(conditions)
+ query += ' AND ' + ' AND '.join(conditions)
if filter_conditions:
query += filter_conditions
@@ -729,11 +765,13 @@ def add_leaves(events, start, end, filter_conditions=None):
"to_date": d.to_date,
"docstatus": d.docstatus,
"color": d.color,
- "title": cstr(d.employee_name) + (' ' + _('(Half Day)') if d.half_day else ''),
+ "all_day": int(not d.half_day),
+ "title": cstr(d.employee_name) + f' ({cstr(d.leave_type)})' + (' ' + _('(Half Day)') if d.half_day else ''),
}
if e not in events:
events.append(e)
+
def add_block_dates(events, start, end, employee, company):
# block days
from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
diff --git a/erpnext/hr/doctype/leave_application/leave_application_calendar.js b/erpnext/hr/doctype/leave_application/leave_application_calendar.js
index 31faadb1079..0ba0285552b 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_calendar.js
+++ b/erpnext/hr/doctype/leave_application/leave_application_calendar.js
@@ -7,7 +7,9 @@ frappe.views.calendar["Leave Application"] = {
"end": "to_date",
"id": "name",
"title": "title",
- "docstatus": 1
+ "docstatus": 1,
+ "color": "color",
+ "allDay": "all_day"
},
options: {
header: {
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 2832e2fad3b..b9c785a8a9c 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -2,16 +2,24 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from erpnext.hr.doctype.leave_application.leave_application import LeaveDayBlockedError, OverlapError, NotAnOptionalHoliday, get_leave_balance_on
+import frappe
from frappe.permissions import clear_user_permissions_for_doctype
-from frappe.utils import add_days, nowdate, now_datetime, getdate, add_months
-from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
-from erpnext.hr.doctype.leave_allocation.test_leave_allocation import create_leave_allocation
-from erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment import create_assignment_for_multiple_employees
+from frappe.utils import add_days, add_months, getdate, nowdate
+
from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.hr.doctype.leave_allocation.test_leave_allocation import create_leave_allocation
+from erpnext.hr.doctype.leave_application.leave_application import (
+ LeaveDayBlockedError,
+ NotAnOptionalHoliday,
+ OverlapError,
+ get_leave_balance_on,
+)
+from erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment import (
+ create_assignment_for_multiple_employees,
+)
+from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
test_dependencies = ["Leave Allocation", "Leave Block List", "Employee"]
diff --git a/erpnext/hr/doctype/leave_block_list/leave_block_list.py b/erpnext/hr/doctype/leave_block_list/leave_block_list.py
index 9cb9fc05cee..9ba079c6e1f 100644
--- a/erpnext/hr/doctype/leave_block_list/leave_block_list.py
+++ b/erpnext/hr/doctype/leave_block_list/leave_block_list.py
@@ -4,10 +4,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
class LeaveBlockList(Document):
def validate(self):
diff --git a/erpnext/hr/doctype/leave_block_list/leave_block_list_dashboard.py b/erpnext/hr/doctype/leave_block_list/leave_block_list_dashboard.py
index 45aa4915bc6..30e7572c383 100644
--- a/erpnext/hr/doctype/leave_block_list/leave_block_list_dashboard.py
+++ b/erpnext/hr/doctype/leave_block_list/leave_block_list_dashboard.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+
def get_data():
return {
'fieldname': 'leave_block_list',
diff --git a/erpnext/hr/doctype/leave_block_list/test_leave_block_list.py b/erpnext/hr/doctype/leave_block_list/test_leave_block_list.py
index 0eb69a55a70..dd90e4f9eea 100644
--- a/erpnext/hr/doctype/leave_block_list/test_leave_block_list.py
+++ b/erpnext/hr/doctype/leave_block_list/test_leave_block_list.py
@@ -2,12 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
from frappe.utils import getdate
+
from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
+
class TestLeaveBlockList(unittest.TestCase):
def tearDown(self):
frappe.set_user("Administrator")
diff --git a/erpnext/hr/doctype/leave_block_list_allow/leave_block_list_allow.py b/erpnext/hr/doctype/leave_block_list_allow/leave_block_list_allow.py
index 8e5a09e01ec..2f648470f73 100644
--- a/erpnext/hr/doctype/leave_block_list_allow/leave_block_list_allow.py
+++ b/erpnext/hr/doctype/leave_block_list_allow/leave_block_list_allow.py
@@ -4,9 +4,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class LeaveBlockListAllow(Document):
pass
diff --git a/erpnext/hr/doctype/leave_block_list_date/leave_block_list_date.py b/erpnext/hr/doctype/leave_block_list_date/leave_block_list_date.py
index 54978a1e83a..4a8f45dbcd1 100644
--- a/erpnext/hr/doctype/leave_block_list_date/leave_block_list_date.py
+++ b/erpnext/hr/doctype/leave_block_list_date/leave_block_list_date.py
@@ -4,9 +4,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class LeaveBlockListDate(Document):
pass
diff --git a/erpnext/hr/doctype/leave_control_panel/leave_control_panel.py b/erpnext/hr/doctype/leave_control_panel/leave_control_panel.py
index 74014020fc6..681a5e27943 100644
--- a/erpnext/hr/doctype/leave_control_panel/leave_control_panel.py
+++ b/erpnext/hr/doctype/leave_control_panel/leave_control_panel.py
@@ -2,11 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import cint, cstr, flt, nowdate, comma_and, date_diff
-from frappe import msgprint, _
+import frappe
+from frappe import _, msgprint
from frappe.model.document import Document
+from frappe.utils import cint, comma_and, cstr, flt
+
class LeaveControlPanel(Document):
def get_employees(self):
@@ -51,7 +52,7 @@ class LeaveControlPanel(Document):
la.docstatus = 1
la.save()
leave_allocated_for.append(d[0])
- except:
+ except Exception:
pass
if leave_allocated_for:
msgprint(_("Leaves Allocated Successfully for {0}").format(comma_and(leave_allocated_for)))
diff --git a/erpnext/hr/doctype/leave_control_panel/test_leave_control_panel.py b/erpnext/hr/doctype/leave_control_panel/test_leave_control_panel.py
index 9a907c885ac..f64b2334e86 100644
--- a/erpnext/hr/doctype/leave_control_panel/test_leave_control_panel.py
+++ b/erpnext/hr/doctype/leave_control_panel/test_leave_control_panel.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestLeaveControlPanel(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
index d136210a043..7656abfa45e 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
@@ -3,14 +3,19 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import getdate, nowdate, flt
-from erpnext.hr.utils import set_employee_name, validate_active_employee
-from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
-from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
+from frappe.utils import getdate, nowdate
+
from erpnext.hr.doctype.leave_allocation.leave_allocation import get_unused_leaves
+from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
+from erpnext.hr.utils import set_employee_name, validate_active_employee
+from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import (
+ get_assigned_salary_structure,
+)
+
class LeaveEncashment(Document):
def validate(self):
diff --git a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.js b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.js
deleted file mode 100644
index cafd9602cbe..00000000000
--- a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Leave Encashment", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Leave Encashment
- () => frappe.tests.make('Leave Encashment', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
index c1da8b47ffa..762745b88f4 100644
--- a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
@@ -3,14 +3,18 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import today, add_months
+
+import frappe
+from frappe.utils import add_months, today
+
from erpnext.hr.doctype.employee.test_employee import make_employee
-from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
from erpnext.hr.doctype.leave_period.test_leave_period import create_leave_period
-from erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment import create_assignment_for_multiple_employees
-from erpnext.hr.doctype.leave_policy.test_leave_policy import create_leave_policy\
+from erpnext.hr.doctype.leave_policy.test_leave_policy import create_leave_policy
+from erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment import (
+ create_assignment_for_multiple_employees,
+)
+from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
test_dependencies = ["Leave Type"]
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 33a6243e609..6cf96851556 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
from frappe import _
-from frappe.utils import add_days, today, flt, DATE_FORMAT, getdate
+from frappe.model.document import Document
+from frappe.utils import DATE_FORMAT, flt, getdate, today
+
class LeaveLedgerEntry(Document):
def validate(self):
diff --git a/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py
index 6f7725c254e..5fa419da43c 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestLeaveLedgerEntry(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py
index 28a33f6fac8..143d23ab14b 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.py
+++ b/erpnext/hr/doctype/leave_period/leave_period.py
@@ -3,12 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import getdate, cstr, add_days, date_diff, getdate, ceil
from frappe.model.document import Document
+from frappe.utils import getdate
+
from erpnext.hr.utils import validate_overlap
-from frappe.utils.background_jobs import enqueue
+
class LeavePeriod(Document):
diff --git a/erpnext/hr/doctype/leave_period/leave_period_dashboard.py b/erpnext/hr/doctype/leave_period/leave_period_dashboard.py
index 7c2c9632d85..a64c63af867 100644
--- a/erpnext/hr/doctype/leave_period/leave_period_dashboard.py
+++ b/erpnext/hr/doctype/leave_period/leave_period_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'leave_period',
diff --git a/erpnext/hr/doctype/leave_period/test_leave_period.js b/erpnext/hr/doctype/leave_period/test_leave_period.js
deleted file mode 100644
index ec0a8096890..00000000000
--- a/erpnext/hr/doctype/leave_period/test_leave_period.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Leave Period", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Leave Period
- () => frappe.tests.make('Leave Period', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/leave_period/test_leave_period.py b/erpnext/hr/doctype/leave_period/test_leave_period.py
index cbb34371fc9..5c5ae133a13 100644
--- a/erpnext/hr/doctype/leave_period/test_leave_period.py
+++ b/erpnext/hr/doctype/leave_period/test_leave_period.py
@@ -3,9 +3,12 @@
# See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
import unittest
+import frappe
+
+import erpnext
+
test_dependencies = ["Employee", "Leave Type", "Leave Policy"]
class TestLeavePeriod(unittest.TestCase):
diff --git a/erpnext/hr/doctype/leave_policy/leave_policy.py b/erpnext/hr/doctype/leave_policy/leave_policy.py
index 964a5de83ec..b11459d8155 100644
--- a/erpnext/hr/doctype/leave_policy/leave_policy.py
+++ b/erpnext/hr/doctype/leave_policy/leave_policy.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
class LeavePolicy(Document):
def validate(self):
if self.leave_policy_details:
diff --git a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
index 474f3a77ad0..76f886c73eb 100644
--- a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
+++ b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'leave_policy',
diff --git a/erpnext/hr/doctype/leave_policy/test_leave_policy.js b/erpnext/hr/doctype/leave_policy/test_leave_policy.js
deleted file mode 100644
index 5404a63bed1..00000000000
--- a/erpnext/hr/doctype/leave_policy/test_leave_policy.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Leave Policy", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Leave Policy
- () => frappe.tests.make('Leave Policy', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/leave_policy/test_leave_policy.py b/erpnext/hr/doctype/leave_policy/test_leave_policy.py
index af7567b5bc7..b0743f535bf 100644
--- a/erpnext/hr/doctype/leave_policy/test_leave_policy.py
+++ b/erpnext/hr/doctype/leave_policy/test_leave_policy.py
@@ -3,9 +3,11 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
+
class TestLeavePolicy(unittest.TestCase):
def test_max_leave_allowed(self):
random_leave_type = frappe.get_all("Leave Type", fields=["name", "max_leaves_allowed"])
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
index d7cb1c88c92..f62b3002194 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
@@ -3,14 +3,17 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-from frappe import _, bold
-from frappe.utils import getdate, date_diff, comma_and, formatdate, get_datetime, flt
-from math import ceil
+
import json
+from math import ceil
+
+import frappe
+from frappe import _, bold
+from frappe.model.document import Document
+from frappe.utils import date_diff, flt, formatdate, get_datetime, getdate
from six import string_types
+
class LeavePolicyAssignment(Document):
def validate(self):
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py
index a2f7f5866b7..79142a63429 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'leave_policy_assignment',
diff --git a/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py
index 0089804f512..cbb26a1e285 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py
+++ b/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py
@@ -3,11 +3,18 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from erpnext.hr.doctype.leave_application.test_leave_application import get_leave_period, get_employee
-from erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment import create_assignment_for_multiple_employees
+
+import frappe
+
+from erpnext.hr.doctype.leave_application.test_leave_application import (
+ get_employee,
+ get_leave_period,
+)
from erpnext.hr.doctype.leave_policy.test_leave_policy import create_leave_policy
+from erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment import (
+ create_assignment_for_multiple_employees,
+)
test_dependencies = ["Employee"]
diff --git a/erpnext/hr/doctype/leave_policy_detail/leave_policy_detail.py b/erpnext/hr/doctype/leave_policy_detail/leave_policy_detail.py
index c103f08cd97..f889424ee51 100644
--- a/erpnext/hr/doctype/leave_policy_detail/leave_policy_detail.py
+++ b/erpnext/hr/doctype/leave_policy_detail/leave_policy_detail.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class LeavePolicyDetail(Document):
pass
diff --git a/erpnext/hr/doctype/leave_policy_detail/test_leave_policy_detail.js b/erpnext/hr/doctype/leave_policy_detail/test_leave_policy_detail.js
deleted file mode 100644
index 1c8995b7967..00000000000
--- a/erpnext/hr/doctype/leave_policy_detail/test_leave_policy_detail.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Leave Policy Detail", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Leave Policy Detail
- () => frappe.tests.make('Leave Policy Detail', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/leave_policy_detail/test_leave_policy_detail.py b/erpnext/hr/doctype/leave_policy_detail/test_leave_policy_detail.py
index 610b1fa332e..4cf9db26a2d 100644
--- a/erpnext/hr/doctype/leave_policy_detail/test_leave_policy_detail.py
+++ b/erpnext/hr/doctype/leave_policy_detail/test_leave_policy_detail.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestLeavePolicyDetail(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/leave_type/leave_type.py b/erpnext/hr/doctype/leave_type/leave_type.py
index 21f180b857d..195c8587b97 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.py
+++ b/erpnext/hr/doctype/leave_type/leave_type.py
@@ -2,13 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import calendar
-import frappe
-from datetime import datetime
-from frappe.utils import today
-from frappe import _
+import frappe
+from frappe import _
from frappe.model.document import Document
+from frappe.utils import today
+
class LeaveType(Document):
def validate(self):
diff --git a/erpnext/hr/doctype/leave_type/leave_type_dashboard.py b/erpnext/hr/doctype/leave_type/leave_type_dashboard.py
index c8944fcb9e2..773d4e88beb 100644
--- a/erpnext/hr/doctype/leave_type/leave_type_dashboard.py
+++ b/erpnext/hr/doctype/leave_type/leave_type_dashboard.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+
def get_data():
return {
'fieldname': 'leave_type',
diff --git a/erpnext/hr/doctype/leave_type/test_leave_type.py b/erpnext/hr/doctype/leave_type/test_leave_type.py
index 048dddd3ef9..ee8db743f2a 100644
--- a/erpnext/hr/doctype/leave_type/test_leave_type.py
+++ b/erpnext/hr/doctype/leave_type/test_leave_type.py
@@ -3,7 +3,6 @@
from __future__ import unicode_literals
import frappe
-from frappe import _
test_records = frappe.get_test_records('Leave Type')
diff --git a/erpnext/hr/doctype/offer_term/offer_term.py b/erpnext/hr/doctype/offer_term/offer_term.py
index 6a632011060..5f8f591c97c 100644
--- a/erpnext/hr/doctype/offer_term/offer_term.py
+++ b/erpnext/hr/doctype/offer_term/offer_term.py
@@ -2,8 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class OfferTerm(Document):
pass
diff --git a/erpnext/hr/doctype/offer_term/test_offer_term.py b/erpnext/hr/doctype/offer_term/test_offer_term.py
index d0dd14d1e62..ec7edd44c6f 100644
--- a/erpnext/hr/doctype/offer_term/test_offer_term.py
+++ b/erpnext/hr/doctype/offer_term/test_offer_term.py
@@ -2,7 +2,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Offer Term')
diff --git a/erpnext/hr/doctype/purpose_of_travel/purpose_of_travel.py b/erpnext/hr/doctype/purpose_of_travel/purpose_of_travel.py
index 62f62a5c249..f66fd276a56 100644
--- a/erpnext/hr/doctype/purpose_of_travel/purpose_of_travel.py
+++ b/erpnext/hr/doctype/purpose_of_travel/purpose_of_travel.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class PurposeofTravel(Document):
pass
diff --git a/erpnext/hr/doctype/purpose_of_travel/test_purpose_of_travel.js b/erpnext/hr/doctype/purpose_of_travel/test_purpose_of_travel.js
deleted file mode 100644
index 936c21ccf05..00000000000
--- a/erpnext/hr/doctype/purpose_of_travel/test_purpose_of_travel.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Purpose of Travel", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Purpose of Travel
- () => frappe.tests.make('Purpose of Travel', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/purpose_of_travel/test_purpose_of_travel.py b/erpnext/hr/doctype/purpose_of_travel/test_purpose_of_travel.py
index ccd950dff3a..b33f389a48b 100644
--- a/erpnext/hr/doctype/purpose_of_travel/test_purpose_of_travel.py
+++ b/erpnext/hr/doctype/purpose_of_travel/test_purpose_of_travel.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestPurposeofTravel(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment.py b/erpnext/hr/doctype/shift_assignment/shift_assignment.py
index 89ae4d535d4..69af5c54c3b 100644
--- a/erpnext/hr/doctype/shift_assignment/shift_assignment.py
+++ b/erpnext/hr/doctype/shift_assignment/shift_assignment.py
@@ -3,14 +3,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
+from datetime import datetime, timedelta
+
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, now_datetime, nowdate
+from frappe.utils import cstr, getdate, now_datetime, nowdate
+
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
from erpnext.hr.utils import validate_active_employee
-from datetime import timedelta, datetime
+
class ShiftAssignment(Document):
def validate(self):
diff --git a/erpnext/hr/doctype/shift_assignment/test_shift_assignment.js b/erpnext/hr/doctype/shift_assignment/test_shift_assignment.js
deleted file mode 100644
index 77272877423..00000000000
--- a/erpnext/hr/doctype/shift_assignment/test_shift_assignment.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Shift Assignment", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Shift Assignment
- () => frappe.tests.make('Shift Assignment', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py b/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py
index 07d92fe61d6..84003e2ec28 100644
--- a/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py
+++ b/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py
@@ -3,9 +3,10 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import nowdate, add_days
+
+import frappe
+from frappe.utils import add_days, nowdate
test_dependencies = ["Shift Type"]
diff --git a/erpnext/hr/doctype/shift_request/shift_request.py b/erpnext/hr/doctype/shift_request/shift_request.py
index 2731da125a8..a6ac7c83aeb 100644
--- a/erpnext/hr/doctype/shift_request/shift_request.py
+++ b/erpnext/hr/doctype/shift_request/shift_request.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import formatdate, getdate
+
from erpnext.hr.utils import share_doc_with_approver, validate_active_employee
+
class OverlapError(frappe.ValidationError): pass
class ShiftRequest(Document):
diff --git a/erpnext/hr/doctype/shift_request/shift_request_dashboard.py b/erpnext/hr/doctype/shift_request/shift_request_dashboard.py
index f70b61a20a6..3ceafc0cefe 100644
--- a/erpnext/hr/doctype/shift_request/shift_request_dashboard.py
+++ b/erpnext/hr/doctype/shift_request/shift_request_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/hr/doctype/shift_request/test_shift_request.js b/erpnext/hr/doctype/shift_request/test_shift_request.js
deleted file mode 100644
index 9c8cd70020c..00000000000
--- a/erpnext/hr/doctype/shift_request/test_shift_request.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Shift Request", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Shift Request
- () => frappe.tests.make('Shift Request', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/shift_request/test_shift_request.py b/erpnext/hr/doctype/shift_request/test_shift_request.py
index 60b7676e251..7b4a3ca5aab 100644
--- a/erpnext/hr/doctype/shift_request/test_shift_request.py
+++ b/erpnext/hr/doctype/shift_request/test_shift_request.py
@@ -3,9 +3,11 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import nowdate, add_days
+
+import frappe
+from frappe.utils import add_days, nowdate
+
from erpnext.hr.doctype.employee.test_employee import make_employee
test_dependencies = ["Shift Type"]
diff --git a/erpnext/hr/doctype/shift_type/shift_type.py b/erpnext/hr/doctype/shift_type/shift_type.py
index d5fdda80944..e53373df279 100644
--- a/erpnext/hr/doctype/shift_type/shift_type.py
+++ b/erpnext/hr/doctype/shift_type/shift_type.py
@@ -3,16 +3,25 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import itertools
from datetime import timedelta
import frappe
from frappe.model.document import Document
-from frappe.utils import cint, getdate, get_datetime
-from erpnext.hr.doctype.shift_assignment.shift_assignment import get_actual_start_end_datetime_of_shift, get_employee_shift
-from erpnext.hr.doctype.employee_checkin.employee_checkin import mark_attendance_and_link_log, calculate_working_hours
+from frappe.utils import cint, get_datetime, getdate
+
from erpnext.hr.doctype.attendance.attendance import mark_attendance
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
+from erpnext.hr.doctype.employee_checkin.employee_checkin import (
+ calculate_working_hours,
+ mark_attendance_and_link_log,
+)
+from erpnext.hr.doctype.shift_assignment.shift_assignment import (
+ get_actual_start_end_datetime_of_shift,
+ get_employee_shift,
+)
+
class ShiftType(Document):
@frappe.whitelist()
diff --git a/erpnext/hr/doctype/shift_type/shift_type_dashboard.py b/erpnext/hr/doctype/shift_type/shift_type_dashboard.py
index aedd190bcb4..b78c69a2a1e 100644
--- a/erpnext/hr/doctype/shift_type/shift_type_dashboard.py
+++ b/erpnext/hr/doctype/shift_type/shift_type_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/hr/doctype/shift_type/test_shift_type.js b/erpnext/hr/doctype/shift_type/test_shift_type.js
deleted file mode 100644
index 846f9316f58..00000000000
--- a/erpnext/hr/doctype/shift_type/test_shift_type.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Shift Type", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Shift Type
- () => frappe.tests.make('Shift Type', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/shift_type/test_shift_type.py b/erpnext/hr/doctype/shift_type/test_shift_type.py
index bc4f0eafcd5..699030f2196 100644
--- a/erpnext/hr/doctype/shift_type/test_shift_type.py
+++ b/erpnext/hr/doctype/shift_type/test_shift_type.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestShiftType(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/skill/skill.py b/erpnext/hr/doctype/skill/skill.py
index 8d242120753..ebaa410fbdd 100644
--- a/erpnext/hr/doctype/skill/skill.py
+++ b/erpnext/hr/doctype/skill/skill.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class Skill(Document):
pass
diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.py b/erpnext/hr/doctype/staffing_plan/staffing_plan.py
index e6c783aca22..57a92b05871 100644
--- a/erpnext/hr/doctype/staffing_plan/staffing_plan.py
+++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.py
@@ -3,12 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
from frappe import _
-from frappe.utils import getdate, nowdate, cint, flt
+from frappe.model.document import Document
+from frappe.utils import cint, flt, getdate, nowdate
from frappe.utils.nestedset import get_descendants_of
+
class SubsidiaryCompanyError(frappe.ValidationError): pass
class ParentCompanyError(frappe.ValidationError): pass
diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan_dashboard.py b/erpnext/hr/doctype/staffing_plan/staffing_plan_dashboard.py
index 8e89d53c8e0..24ae1223440 100644
--- a/erpnext/hr/doctype/staffing_plan/staffing_plan_dashboard.py
+++ b/erpnext/hr/doctype/staffing_plan/staffing_plan_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/hr/doctype/staffing_plan/test_staffing_plan.js b/erpnext/hr/doctype/staffing_plan/test_staffing_plan.js
deleted file mode 100644
index 64320bcd92b..00000000000
--- a/erpnext/hr/doctype/staffing_plan/test_staffing_plan.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Staffing Plan", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Staffing Plan
- () => frappe.tests.make('Staffing Plan', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py b/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py
index 1c6218e9a70..4517cba2335 100644
--- a/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py
+++ b/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py
@@ -3,11 +3,15 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from erpnext.hr.doctype.staffing_plan.staffing_plan import SubsidiaryCompanyError
-from erpnext.hr.doctype.staffing_plan.staffing_plan import ParentCompanyError
-from frappe.utils import nowdate, add_days
+
+import frappe
+from frappe.utils import add_days, nowdate
+
+from erpnext.hr.doctype.staffing_plan.staffing_plan import (
+ ParentCompanyError,
+ SubsidiaryCompanyError,
+)
test_dependencies = ["Designation"]
diff --git a/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.py b/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.py
index 28a651e72d8..ea89df3ba6e 100644
--- a/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.py
+++ b/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class StaffingPlanDetail(Document):
pass
diff --git a/erpnext/hr/doctype/training_event/test_training_event.py b/erpnext/hr/doctype/training_event/test_training_event.py
index 6a275b330c0..ed44fa60704 100644
--- a/erpnext/hr/doctype/training_event/test_training_event.py
+++ b/erpnext/hr/doctype/training_event/test_training_event.py
@@ -3,11 +3,14 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import today, add_days
+
+import frappe
+from frappe.utils import add_days, today
+
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_employee
+
class TestTrainingEvent(unittest.TestCase):
def setUp(self):
create_training_program("Basic Training")
diff --git a/erpnext/hr/doctype/training_event/training_event.py b/erpnext/hr/doctype/training_event/training_event.py
index e2c30cb3145..9b01d3d9026 100644
--- a/erpnext/hr/doctype/training_event/training_event.py
+++ b/erpnext/hr/doctype/training_event/training_event.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
from frappe import _
+from frappe.model.document import Document
from frappe.utils import time_diff_in_seconds
+
from erpnext.hr.doctype.employee.employee import get_employee_emails
+
class TrainingEvent(Document):
def validate(self):
self.set_employee_emails()
diff --git a/erpnext/hr/doctype/training_event/training_event_dashboard.py b/erpnext/hr/doctype/training_event/training_event_dashboard.py
index 19afd8dd6e1..a917c8744f7 100644
--- a/erpnext/hr/doctype/training_event/training_event_dashboard.py
+++ b/erpnext/hr/doctype/training_event/training_event_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/hr/doctype/training_event_employee/training_event_employee.py b/erpnext/hr/doctype/training_event_employee/training_event_employee.py
index 234e958a212..089235507a2 100644
--- a/erpnext/hr/doctype/training_event_employee/training_event_employee.py
+++ b/erpnext/hr/doctype/training_event_employee/training_event_employee.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class TrainingEventEmployee(Document):
pass
diff --git a/erpnext/hr/doctype/training_feedback/test_training_feedback.py b/erpnext/hr/doctype/training_feedback/test_training_feedback.py
index 4c0c18029d0..a9bf6d6bbde 100644
--- a/erpnext/hr/doctype/training_feedback/test_training_feedback.py
+++ b/erpnext/hr/doctype/training_feedback/test_training_feedback.py
@@ -3,10 +3,17 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
+
+from erpnext.hr.doctype.training_event.test_training_event import (
+ create_training_event,
+ create_training_program,
+)
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_employee
-from erpnext.hr.doctype.training_event.test_training_event import create_training_program, create_training_event
+
+
class TestTrainingFeedback(unittest.TestCase):
def setUp(self):
create_training_program("Basic Training")
diff --git a/erpnext/hr/doctype/training_feedback/training_feedback.py b/erpnext/hr/doctype/training_feedback/training_feedback.py
index 3d4b9b3ea96..6a41a657cea 100644
--- a/erpnext/hr/doctype/training_feedback/training_feedback.py
+++ b/erpnext/hr/doctype/training_feedback/training_feedback.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
from frappe import _
+from frappe.model.document import Document
+
class TrainingFeedback(Document):
def validate(self):
diff --git a/erpnext/hr/doctype/training_program/test_training_program.js b/erpnext/hr/doctype/training_program/test_training_program.js
deleted file mode 100644
index 3a62b2fa221..00000000000
--- a/erpnext/hr/doctype/training_program/test_training_program.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Training Program", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Training Program
- () => frappe.tests.make('Training Program', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/training_program/test_training_program.py b/erpnext/hr/doctype/training_program/test_training_program.py
index 9d5b28616b1..aec319f4077 100644
--- a/erpnext/hr/doctype/training_program/test_training_program.py
+++ b/erpnext/hr/doctype/training_program/test_training_program.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestTrainingProgram(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/training_program/training_program.py b/erpnext/hr/doctype/training_program/training_program.py
index 7a3720b66b6..6f3ab5a806f 100644
--- a/erpnext/hr/doctype/training_program/training_program.py
+++ b/erpnext/hr/doctype/training_program/training_program.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class TrainingProgram(Document):
pass
diff --git a/erpnext/hr/doctype/training_program/training_program_dashboard.py b/erpnext/hr/doctype/training_program/training_program_dashboard.py
index 0fc18a80298..b2eed6895ca 100644
--- a/erpnext/hr/doctype/training_program/training_program_dashboard.py
+++ b/erpnext/hr/doctype/training_program/training_program_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'training_program',
diff --git a/erpnext/hr/doctype/training_result/test_training_result.js b/erpnext/hr/doctype/training_result/test_training_result.js
deleted file mode 100644
index cb1d7fb27a3..00000000000
--- a/erpnext/hr/doctype/training_result/test_training_result.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Training Result", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Training Result
- () => frappe.tests.make('Training Result', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/training_result/test_training_result.py b/erpnext/hr/doctype/training_result/test_training_result.py
index 29ed2a0ff38..17ccc4b4eef 100644
--- a/erpnext/hr/doctype/training_result/test_training_result.py
+++ b/erpnext/hr/doctype/training_result/test_training_result.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Training Result')
diff --git a/erpnext/hr/doctype/training_result/training_result.py b/erpnext/hr/doctype/training_result/training_result.py
index 7cdc51f8010..9cfc5707cac 100644
--- a/erpnext/hr/doctype/training_result/training_result.py
+++ b/erpnext/hr/doctype/training_result/training_result.py
@@ -3,11 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
from erpnext.hr.doctype.employee.employee import get_employee_emails
+
class TrainingResult(Document):
def validate(self):
training_event = frappe.get_doc("Training Event", self.training_event)
diff --git a/erpnext/hr/doctype/training_result_employee/training_result_employee.py b/erpnext/hr/doctype/training_result_employee/training_result_employee.py
index 54e2a18260a..b0d4605910c 100644
--- a/erpnext/hr/doctype/training_result_employee/training_result_employee.py
+++ b/erpnext/hr/doctype/training_result_employee/training_result_employee.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class TrainingResultEmployee(Document):
pass
diff --git a/erpnext/hr/doctype/travel_itinerary/travel_itinerary.py b/erpnext/hr/doctype/travel_itinerary/travel_itinerary.py
index 0b369beb134..467ef16aaee 100644
--- a/erpnext/hr/doctype/travel_itinerary/travel_itinerary.py
+++ b/erpnext/hr/doctype/travel_itinerary/travel_itinerary.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class TravelItinerary(Document):
pass
diff --git a/erpnext/hr/doctype/travel_request/test_travel_request.js b/erpnext/hr/doctype/travel_request/test_travel_request.js
deleted file mode 100644
index 7e645918239..00000000000
--- a/erpnext/hr/doctype/travel_request/test_travel_request.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Travel Request", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Travel Request
- () => frappe.tests.make('Travel Request', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/travel_request/test_travel_request.py b/erpnext/hr/doctype/travel_request/test_travel_request.py
index dac5517aab0..95bf8b9c8bc 100644
--- a/erpnext/hr/doctype/travel_request/test_travel_request.py
+++ b/erpnext/hr/doctype/travel_request/test_travel_request.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestTravelRequest(unittest.TestCase):
pass
diff --git a/erpnext/hr/doctype/travel_request/travel_request.py b/erpnext/hr/doctype/travel_request/travel_request.py
index 60834d3f4a6..b10333fd2d6 100644
--- a/erpnext/hr/doctype/travel_request/travel_request.py
+++ b/erpnext/hr/doctype/travel_request/travel_request.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
from erpnext.hr.utils import validate_active_employee
+
class TravelRequest(Document):
def validate(self):
validate_active_employee(self.employee)
diff --git a/erpnext/hr/doctype/travel_request_costing/travel_request_costing.py b/erpnext/hr/doctype/travel_request_costing/travel_request_costing.py
index 9fa85e84c28..9b38d888fcb 100644
--- a/erpnext/hr/doctype/travel_request_costing/travel_request_costing.py
+++ b/erpnext/hr/doctype/travel_request_costing/travel_request_costing.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class TravelRequestCosting(Document):
pass
diff --git a/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py
index 03b0cf3da21..e0a776c45d0 100644
--- a/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py
+++ b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py
@@ -3,12 +3,14 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-import erpnext
+
+import frappe
from frappe.utils import getdate
-from erpnext.hr.doctype.upload_attendance.upload_attendance import get_data
+
+import erpnext
from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.hr.doctype.upload_attendance.upload_attendance import get_data
test_dependencies = ['Holiday List']
diff --git a/erpnext/hr/doctype/upload_attendance/upload_attendance.py b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
index 9c765d73716..030ecec74f9 100644
--- a/erpnext/hr/doctype/upload_attendance/upload_attendance.py
+++ b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
@@ -4,14 +4,17 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import cstr, add_days, date_diff, getdate
from frappe import _
-from frappe.utils.csvutils import UnicodeWriter
from frappe.model.document import Document
+from frappe.utils import add_days, cstr, date_diff, getdate
+from frappe.utils.csvutils import UnicodeWriter
+
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
from erpnext.hr.utils import get_holiday_dates_for_employee
+
class UploadAttendance(Document):
pass
diff --git a/erpnext/hr/doctype/vehicle/test_vehicle.js b/erpnext/hr/doctype/vehicle/test_vehicle.js
deleted file mode 100644
index 4d40cce086a..00000000000
--- a/erpnext/hr/doctype/vehicle/test_vehicle.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Vehicle", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Vehicle
- () => frappe.tests.make('Vehicle', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hr/doctype/vehicle/test_vehicle.py b/erpnext/hr/doctype/vehicle/test_vehicle.py
index ff3429d0e7e..2bc94c65090 100644
--- a/erpnext/hr/doctype/vehicle/test_vehicle.py
+++ b/erpnext/hr/doctype/vehicle/test_vehicle.py
@@ -3,9 +3,11 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import nowdate,flt, cstr,random_string
+
+import frappe
+from frappe.utils import random_string
+
# test_records = frappe.get_test_records('Vehicle')
class TestVehicle(unittest.TestCase):
diff --git a/erpnext/hr/doctype/vehicle/vehicle.py b/erpnext/hr/doctype/vehicle/vehicle.py
index 1df50682683..2ff190426dd 100644
--- a/erpnext/hr/doctype/vehicle/vehicle.py
+++ b/erpnext/hr/doctype/vehicle/vehicle.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import getdate
from frappe.model.document import Document
+from frappe.utils import getdate
+
class Vehicle(Document):
def validate(self):
diff --git a/erpnext/hr/doctype/vehicle/vehicle_dashboard.py b/erpnext/hr/doctype/vehicle/vehicle_dashboard.py
index 628c8972cec..6a01bcffd50 100644
--- a/erpnext/hr/doctype/vehicle/vehicle_dashboard.py
+++ b/erpnext/hr/doctype/vehicle/vehicle_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'heatmap': True,
diff --git a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py
index ed02120cca3..1b0bfcb08f9 100644
--- a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py
+++ b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py
@@ -3,12 +3,15 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import nowdate, flt, cstr, random_string
+
+import frappe
+from frappe.utils import cstr, flt, nowdate, random_string
+
from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.hr.doctype.vehicle_log.vehicle_log import make_expense_claim
+
class TestVehicleLog(unittest.TestCase):
def setUp(self):
employee_id = frappe.db.sql("""select name from `tabEmployee` where name='testdriver@example.com'""")
diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.py b/erpnext/hr/doctype/vehicle_log/vehicle_log.py
index 04c94e37d5a..73c848b0346 100644
--- a/erpnext/hr/doctype/vehicle_log/vehicle_log.py
+++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.py
@@ -3,11 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt, cstr
-from frappe.model.mapper import get_mapped_doc
from frappe.model.document import Document
+from frappe.utils import flt
+
class VehicleLog(Document):
def validate(self):
diff --git a/erpnext/hr/doctype/vehicle_service/vehicle_service.py b/erpnext/hr/doctype/vehicle_service/vehicle_service.py
index 18ed7821382..bc93a97481d 100644
--- a/erpnext/hr/doctype/vehicle_service/vehicle_service.py
+++ b/erpnext/hr/doctype/vehicle_service/vehicle_service.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class VehicleService(Document):
pass
diff --git a/erpnext/hr/notification/training_feedback/training_feedback.py b/erpnext/hr/notification/training_feedback/training_feedback.py
index 2334f8b26d8..f57de916dd1 100644
--- a/erpnext/hr/notification/training_feedback/training_feedback.py
+++ b/erpnext/hr/notification/training_feedback/training_feedback.py
@@ -1,6 +1,5 @@
from __future__ import unicode_literals
-import frappe
def get_context(context):
# do your magic here
diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.py b/erpnext/hr/notification/training_scheduled/training_scheduled.py
index 2334f8b26d8..f57de916dd1 100644
--- a/erpnext/hr/notification/training_scheduled/training_scheduled.py
+++ b/erpnext/hr/notification/training_scheduled/training_scheduled.py
@@ -1,6 +1,5 @@
from __future__ import unicode_literals
-import frappe
def get_context(context):
# do your magic here
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.js b/erpnext/hr/page/organizational_chart/organizational_chart.js
index b6fcc6014bd..26a5e48ff20 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.js
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.js
@@ -15,6 +15,8 @@ frappe.pages['organizational-chart'].on_page_load = function(wrapper) {
} else {
organizational_chart = new erpnext.HierarchyChart('Employee', wrapper, method);
}
+
+ frappe.breadcrumbs.add('HR');
organizational_chart.show();
});
});
diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py
index 4423d29e402..1baf805f4b9 100644
--- a/erpnext/hr/page/organizational_chart/organizational_chart.py
+++ b/erpnext/hr/page/organizational_chart/organizational_chart.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
@frappe.whitelist()
def get_children(parent=None, company=None, exclude_node=None):
filters = [['status', '!=', 'Left']]
diff --git a/erpnext/hr/page/team_updates/team_updates.py b/erpnext/hr/page/team_updates/team_updates.py
index 58cdc4b7e1d..a5e7c44c31d 100644
--- a/erpnext/hr/page/team_updates/team_updates.py
+++ b/erpnext/hr/page/team_updates/team_updates.py
@@ -3,6 +3,7 @@ from __future__ import unicode_literals
import frappe
from email_reply_parser import EmailReplyParser
+
@frappe.whitelist()
def get_data(start=0):
#frappe.only_for('Employee', 'System Manager')
diff --git a/erpnext/hr/report/daily_work_summary_replies/daily_work_summary_replies.py b/erpnext/hr/report/daily_work_summary_replies/daily_work_summary_replies.py
index d8691b4d025..62ffb7d3445 100644
--- a/erpnext/hr/report/daily_work_summary_replies/daily_work_summary_replies.py
+++ b/erpnext/hr/report/daily_work_summary_replies/daily_work_summary_replies.py
@@ -2,10 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe import _
+
import frappe
+from frappe import _
+
from erpnext.hr.doctype.daily_work_summary.daily_work_summary import get_user_emails_from_group
+
def execute(filters=None):
if not filters.group: return [], []
columns, data = get_columns(), get_data(filters)
diff --git a/erpnext/hr/report/employee_advance_summary/employee_advance_summary.py b/erpnext/hr/report/employee_advance_summary/employee_advance_summary.py
index 363e31d0960..d0c295df9f1 100644
--- a/erpnext/hr/report/employee_advance_summary/employee_advance_summary.py
+++ b/erpnext/hr/report/employee_advance_summary/employee_advance_summary.py
@@ -2,8 +2,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import msgprint, _
+from frappe import _, msgprint
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/hr/report/employee_analytics/employee_analytics.py b/erpnext/hr/report/employee_analytics/employee_analytics.py
index fe77b6abc96..725c5a15713 100644
--- a/erpnext/hr/report/employee_analytics/employee_analytics.py
+++ b/erpnext/hr/report/employee_analytics/employee_analytics.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/hr/report/employee_birthday/employee_birthday.py b/erpnext/hr/report/employee_birthday/employee_birthday.py
index e8d78449bff..b284e6babe6 100644
--- a/erpnext/hr/report/employee_birthday/employee_birthday.py
+++ b/erpnext/hr/report/employee_birthday/employee_birthday.py
@@ -2,9 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index b8953b3eaac..6bca1368d3f 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -2,12 +2,19 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import flt, add_days
-from frappe import _
-from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period, get_leave_balance_on
+
from itertools import groupby
+import frappe
+from frappe import _
+from frappe.utils import add_days
+
+from erpnext.hr.doctype.leave_application.leave_application import (
+ get_leave_balance_on,
+ get_leaves_for_period,
+)
+
+
def execute(filters=None):
if filters.to_date <= filters.from_date:
frappe.throw(_('"From Date" can not be greater than or equal to "To Date"'))
diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
index 9dd7bcd8dd9..14ce9ed22a6 100644
--- a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
+++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
@@ -2,14 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt
-from erpnext.hr.doctype.leave_application.leave_application \
- import get_leave_details
-from erpnext.hr.report.employee_leave_balance.employee_leave_balance \
- import get_department_leave_approver_map
+from erpnext.hr.doctype.leave_application.leave_application import get_leave_details
+from erpnext.hr.report.employee_leave_balance.employee_leave_balance import (
+ get_department_leave_approver_map,
+)
+
def execute(filters=None):
leave_types = frappe.db.sql_list("select name from `tabLeave Type` order by name asc")
@@ -65,7 +66,7 @@ def get_data(filters, leave_types):
for leave_type in leave_types:
remaining = 0
if leave_type in available_leave["leave_allocation"]:
- # opening balance
+ # opening balance
remaining = available_leave["leave_allocation"][leave_type]['remaining_leaves']
row += [remaining]
diff --git a/erpnext/hr/report/employees_working_on_a_holiday/employees_working_on_a_holiday.py b/erpnext/hr/report/employees_working_on_a_holiday/employees_working_on_a_holiday.py
index 59f56d7345f..3a268821361 100644
--- a/erpnext/hr/report/employees_working_on_a_holiday/employees_working_on_a_holiday.py
+++ b/erpnext/hr/report/employees_working_on_a_holiday/employees_working_on_a_holiday.py
@@ -2,6 +2,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
diff --git a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
index c5929c6bf99..8c40da29ee9 100644
--- a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
+++ b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
@@ -2,11 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import cstr, cint, getdate
-from frappe import msgprint, _
+
from calendar import monthrange
+import frappe
+from frappe import _, msgprint
+from frappe.utils import cint, cstr, getdate
+
status_map = {
"Absent": "A",
"Half Day": "HD",
diff --git a/erpnext/hr/report/recruitment_analytics/recruitment_analytics.py b/erpnext/hr/report/recruitment_analytics/recruitment_analytics.py
index 303c829eb6c..c598e9e3730 100644
--- a/erpnext/hr/report/recruitment_analytics/recruitment_analytics.py
+++ b/erpnext/hr/report/recruitment_analytics/recruitment_analytics.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py b/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py
index 26e0f26392e..2ba87efd9b2 100644
--- a/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py
+++ b/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py
@@ -2,14 +2,18 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import unittest
+
import frappe
from frappe.utils import getdate
-from erpnext.hr.doctype.employee.test_employee import make_employee
-from erpnext.hr.doctype.vehicle_log.vehicle_log import make_expense_claim
-from erpnext.hr.doctype.vehicle_log.test_vehicle_log import get_vehicle, make_vehicle_log
-from erpnext.hr.report.vehicle_expenses.vehicle_expenses import execute
+
from erpnext.accounts.utils import get_fiscal_year
+from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.hr.doctype.vehicle_log.test_vehicle_log import get_vehicle, make_vehicle_log
+from erpnext.hr.doctype.vehicle_log.vehicle_log import make_expense_claim
+from erpnext.hr.report.vehicle_expenses.vehicle_expenses import execute
+
class TestVehicleExpenses(unittest.TestCase):
@classmethod
diff --git a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
index d847cbb5c9b..2be3565a059 100644
--- a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
+++ b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
@@ -2,12 +2,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-import erpnext
from frappe import _
from frappe.utils import flt
+
from erpnext.accounts.report.financial_statements import get_period_list
+
def execute(filters=None):
filters = frappe._dict(filters or {})
@@ -96,8 +98,6 @@ def get_columns():
}
]
- return columns
-
def get_vehicle_log_data(filters):
start_date, end_date = get_period_dates(filters)
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 9c936ab4ad0..3f4a0b90b56 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -1,14 +1,30 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-import erpnext
import frappe
-from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee, InactiveEmployeeStatusError
from frappe import _
from frappe.desk.form import assign_to
from frappe.model.document import Document
-from frappe.utils import (add_days, cstr, flt, format_datetime, formatdate,
- get_datetime, getdate, nowdate, today, unique, get_link_to_form)
+from frappe.utils import (
+ add_days,
+ cstr,
+ flt,
+ format_datetime,
+ formatdate,
+ get_datetime,
+ get_link_to_form,
+ getdate,
+ nowdate,
+ today,
+ unique,
+)
+
+import erpnext
+from erpnext.hr.doctype.employee.employee import (
+ InactiveEmployeeStatusError,
+ get_holiday_list_for_employee,
+)
+
class DuplicateDeclarationError(frappe.ValidationError): pass
@@ -385,6 +401,7 @@ def create_additional_leave_ledger_entry(allocation, leaves, date):
def check_effective_date(from_date, to_date, frequency, based_on_date_of_joining_date):
import calendar
+
from dateutil import relativedelta
from_date = get_datetime(from_date)
@@ -450,9 +467,9 @@ def get_sal_slip_total_benefit_given(employee, payroll_period, component=False):
def get_holiday_dates_for_employee(employee, start_date, end_date):
"""return a list of holiday dates for the given employee between start_date and end_date"""
- # return only date
- holidays = get_holidays_for_employee(employee, start_date, end_date)
-
+ # return only date
+ holidays = get_holidays_for_employee(employee, start_date, end_date)
+
return [cstr(h.holiday_date) for h in holidays]
@@ -465,7 +482,7 @@ def get_holidays_for_employee(employee, start_date, end_date, raise_exception=Tr
`raise_exception` (bool)
`only_non_weekly` (bool)
- return: list of dicts with `holiday_date` and `description`
+ return: list of dicts with `holiday_date` and `description`
"""
holiday_list = get_holiday_list_for_employee(employee, raise_exception=raise_exception)
@@ -481,11 +498,11 @@ def get_holidays_for_employee(employee, start_date, end_date, raise_exception=Tr
filters['weekly_off'] = False
holidays = frappe.get_all(
- 'Holiday',
+ 'Holiday',
fields=['description', 'holiday_date'],
filters=filters
)
-
+
return holidays
@erpnext.allow_regional
diff --git a/erpnext/hr/web_form/job_application/job_application.py b/erpnext/hr/web_form/job_application/job_application.py
index 2334f8b26d8..f57de916dd1 100644
--- a/erpnext/hr/web_form/job_application/job_application.py
+++ b/erpnext/hr/web_form/job_application/job_application.py
@@ -1,6 +1,5 @@
from __future__ import unicode_literals
-import frappe
def get_context(context):
# do your magic here
diff --git a/erpnext/hub_node/__init__.py b/erpnext/hub_node/__init__.py
index 85ffe29d118..6ac3255c12a 100644
--- a/erpnext/hub_node/__init__.py
+++ b/erpnext/hub_node/__init__.py
@@ -2,8 +2,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
+
@frappe.whitelist()
def enable_hub():
hub_settings = frappe.get_doc('Marketplace Settings')
diff --git a/erpnext/hub_node/api.py b/erpnext/hub_node/api.py
index 42f90006f4d..55304917759 100644
--- a/erpnext/hub_node/api.py
+++ b/erpnext/hub_node/api.py
@@ -1,11 +1,11 @@
from __future__ import unicode_literals
-import frappe
import json
+import frappe
from frappe import _
-from frappe.frappeclient import FrappeClient
from frappe.desk.form.load import get_attachments
+from frappe.frappeclient import FrappeClient
from six import string_types
current_user = frappe.session.user
diff --git a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.py b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.py
index be2cd6b3ee9..823c79eb72b 100644
--- a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.py
+++ b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class HubTrackedItem(Document):
pass
diff --git a/erpnext/hub_node/doctype/hub_tracked_item/test_hub_tracked_item.py b/erpnext/hub_node/doctype/hub_tracked_item/test_hub_tracked_item.py
index 92b294064fb..c403f902a2c 100644
--- a/erpnext/hub_node/doctype/hub_tracked_item/test_hub_tracked_item.py
+++ b/erpnext/hub_node/doctype/hub_tracked_item/test_hub_tracked_item.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestHubTrackedItem(unittest.TestCase):
pass
diff --git a/erpnext/hub_node/doctype/hub_user/hub_user.py b/erpnext/hub_node/doctype/hub_user/hub_user.py
index de43f4e0c04..1f7c8fc3f20 100644
--- a/erpnext/hub_node/doctype/hub_user/hub_user.py
+++ b/erpnext/hub_node/doctype/hub_user/hub_user.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class HubUser(Document):
pass
diff --git a/erpnext/hub_node/doctype/hub_users/hub_users.py b/erpnext/hub_node/doctype/hub_users/hub_users.py
index 440be14c0bf..e08ed68ed8f 100644
--- a/erpnext/hub_node/doctype/hub_users/hub_users.py
+++ b/erpnext/hub_node/doctype/hub_users/hub_users.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class HubUsers(Document):
pass
diff --git a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.py b/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.py
index 91c7bf5850a..af2ff37797e 100644
--- a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.py
+++ b/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.py
@@ -1,15 +1,13 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
-import frappe, requests, json, time
+import json
-from frappe.model.document import Document
-from frappe.utils import add_years, now, get_datetime, get_datetime_str, cint
-from frappe import _
+import frappe
from frappe.frappeclient import FrappeClient
-from erpnext.utilities.product import get_price, get_qty_in_stock
-from six import string_types
+from frappe.model.document import Document
+from frappe.utils import cint
+
class MarketplaceSettings(Document):
@@ -83,7 +81,6 @@ class MarketplaceSettings(Document):
def unregister(self):
"""Disable the User on hubmarket.org"""
- pass
@frappe.whitelist()
def is_marketplace_enabled():
diff --git a/erpnext/hub_node/doctype/marketplace_settings/test_marketplace_settings.js b/erpnext/hub_node/doctype/marketplace_settings/test_marketplace_settings.js
deleted file mode 100644
index fba3e098d4b..00000000000
--- a/erpnext/hub_node/doctype/marketplace_settings/test_marketplace_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Marketplace Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Marketplace Settings
- () => frappe.tests.make('Marketplace Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/hub_node/doctype/marketplace_settings/test_marketplace_settings.py b/erpnext/hub_node/doctype/marketplace_settings/test_marketplace_settings.py
index 549b9914c34..7922f45ab59 100644
--- a/erpnext/hub_node/doctype/marketplace_settings/test_marketplace_settings.py
+++ b/erpnext/hub_node/doctype/marketplace_settings/test_marketplace_settings.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestMarketplaceSettings(unittest.TestCase):
pass
diff --git a/erpnext/hub_node/legacy.py b/erpnext/hub_node/legacy.py
index b61b88bf078..2e4c2668436 100644
--- a/erpnext/hub_node/legacy.py
+++ b/erpnext/hub_node/legacy.py
@@ -1,9 +1,13 @@
from __future__ import unicode_literals
-import frappe, json
-from frappe.utils import nowdate
-from frappe.frappeclient import FrappeClient
-from frappe.utils.nestedset import get_root_of
+
+import json
+
+import frappe
from frappe.contacts.doctype.contact.contact import get_default_contact
+from frappe.frappeclient import FrappeClient
+from frappe.utils import nowdate
+from frappe.utils.nestedset import get_root_of
+
def get_list(doctype, start, limit, fields, filters, order_by):
pass
diff --git a/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.py b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.py
index 6ce2a54b190..0911e8f49bb 100644
--- a/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.py
+++ b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.py
@@ -2,12 +2,16 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.utils.dashboard import cache_source
-from erpnext.loan_management.report.applicant_wise_loan_security_exposure.applicant_wise_loan_security_exposure \
- import get_loan_security_details
from six import iteritems
+from erpnext.loan_management.report.applicant_wise_loan_security_exposure.applicant_wise_loan_security_exposure import (
+ get_loan_security_details,
+)
+
+
@frappe.whitelist()
@cache_source
def get_data(chart_name = None, chart = None, no_cache = None, filters = None, from_date = None,
diff --git a/erpnext/loan_management/doctype/loan/loan.py b/erpnext/loan_management/doctype/loan/loan.py
index ff7fbbdf49a..7dbd42297e1 100644
--- a/erpnext/loan_management/doctype/loan/loan.py
+++ b/erpnext/loan_management/doctype/loan/loan.py
@@ -3,14 +3,22 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, math, json
-import erpnext
+
+import json
+import math
+
+import frappe
from frappe import _
+from frappe.utils import add_months, flt, getdate, now_datetime, nowdate
from six import string_types
-from frappe.utils import flt, rounded, add_months, nowdate, getdate, now_datetime
-from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
+
+import erpnext
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts
+from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import (
+ get_pledged_security_qty,
+)
+
class Loan(AccountsController):
def validate(self):
@@ -361,7 +369,9 @@ def create_loan_security_unpledge(unpledge_map, loan, company, applicant_type, a
return unpledge_request
def validate_employee_currency_with_company_currency(applicant, company):
- from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import get_employee_currency
+ from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import (
+ get_employee_currency,
+ )
if not applicant:
frappe.throw(_("Please select Applicant"))
if not company:
diff --git a/erpnext/loan_management/doctype/loan/loan_dashboard.py b/erpnext/loan_management/doctype/loan/loan_dashboard.py
index 711a7829baf..28ccc03b684 100644
--- a/erpnext/loan_management/doctype/loan/loan_dashboard.py
+++ b/erpnext/loan_management/doctype/loan/loan_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py
index 122d7236051..ec0aebbb8a4 100644
--- a/erpnext/loan_management/doctype/loan/test_loan.py
+++ b/erpnext/loan_management/doctype/loan/test_loan.py
@@ -3,23 +3,40 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
-import erpnext
import unittest
-from frappe.utils import (nowdate, add_days, getdate, now_datetime, add_to_date, get_datetime,
- add_months, get_first_day, get_last_day, flt, date_diff)
-from erpnext.selling.doctype.customer.test_customer import get_customer_dict
-from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_employee
-from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (process_loan_interest_accrual_for_demand_loans,
- process_loan_interest_accrual_for_term_loans)
-from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year
-from erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall import create_process_loan_security_shortfall
-from erpnext.loan_management.doctype.loan.loan import unpledge_security, request_loan_closure, make_loan_write_off
-from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
+
+import frappe
+from frappe.utils import add_days, add_months, add_to_date, date_diff, flt, get_datetime, nowdate
+
+from erpnext.loan_management.doctype.loan.loan import (
+ make_loan_write_off,
+ request_loan_closure,
+ unpledge_security,
+)
from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge
-from erpnext.loan_management.doctype.loan_disbursement.loan_disbursement import get_disbursal_amount
+from erpnext.loan_management.doctype.loan_disbursement.loan_disbursement import (
+ get_disbursal_amount,
+)
+from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (
+ days_in_year,
+)
from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts
-from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
+from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import (
+ get_pledged_security_qty,
+)
+from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (
+ process_loan_interest_accrual_for_demand_loans,
+ process_loan_interest_accrual_for_term_loans,
+)
+from erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall import (
+ create_process_loan_security_shortfall,
+)
+from erpnext.payroll.doctype.salary_structure.test_salary_structure import (
+ make_employee,
+ make_salary_structure,
+)
+from erpnext.selling.doctype.customer.test_customer import get_customer_dict
+
class TestLoan(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/loan_management/doctype/loan_application/loan_application.py b/erpnext/loan_management/doctype/loan_application/loan_application.py
index d8f3577b2c3..e492920abb3 100644
--- a/erpnext/loan_management/doctype/loan_application/loan_application.py
+++ b/erpnext/loan_management/doctype/loan_application/loan_application.py
@@ -3,17 +3,28 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, math
-from frappe import _
-from frappe.utils import flt, rounded, cint
-from frappe.model.mapper import get_mapped_doc
-from frappe.model.document import Document
-from erpnext.loan_management.doctype.loan.loan import (get_monthly_repayment_amount, validate_repayment_method,
- get_total_loan_amount, get_sanctioned_amount_limit)
-from erpnext.loan_management.doctype.loan_security_price.loan_security_price import get_loan_security_price
+
import json
+import math
+
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import cint, flt, rounded
from six import string_types
+from erpnext.loan_management.doctype.loan.loan import (
+ get_monthly_repayment_amount,
+ get_sanctioned_amount_limit,
+ get_total_loan_amount,
+ validate_repayment_method,
+)
+from erpnext.loan_management.doctype.loan_security_price.loan_security_price import (
+ get_loan_security_price,
+)
+
+
class LoanApplication(Document):
def validate(self):
self.set_pledge_amount()
diff --git a/erpnext/loan_management/doctype/loan_application/loan_application_dashboard.py b/erpnext/loan_management/doctype/loan_application/loan_application_dashboard.py
index 3975adf4431..992d6699747 100644
--- a/erpnext/loan_management/doctype/loan_application/loan_application_dashboard.py
+++ b/erpnext/loan_management/doctype/loan_application/loan_application_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/loan_management/doctype/loan_application/test_loan_application.py b/erpnext/loan_management/doctype/loan_application/test_loan_application.py
index 2a659e9fc2e..aefa08970a4 100644
--- a/erpnext/loan_management/doctype/loan_application/test_loan_application.py
+++ b/erpnext/loan_management/doctype/loan_application/test_loan_application.py
@@ -3,10 +3,16 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_employee, make_salary_structure
-from erpnext.loan_management.doctype.loan.test_loan import create_loan_type, create_loan_accounts
+
+import frappe
+
+from erpnext.loan_management.doctype.loan.test_loan import create_loan_accounts, create_loan_type
+from erpnext.payroll.doctype.salary_structure.test_salary_structure import (
+ make_employee,
+ make_salary_structure,
+)
+
class TestLoanApplication(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
index f113c10ef71..6d9d4f490d3 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
+++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
@@ -3,15 +3,21 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+
+import frappe
from frappe import _
-from frappe.model.document import Document
-from frappe.utils import nowdate, getdate, add_days, flt
-from erpnext.controllers.accounts_controller import AccountsController
+from frappe.utils import add_days, flt, get_datetime, nowdate
+
+import erpnext
from erpnext.accounts.general_ledger import make_gl_entries
-from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans
-from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
-from frappe.utils import get_datetime
+from erpnext.controllers.accounts_controller import AccountsController
+from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import (
+ get_pledged_security_qty,
+)
+from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (
+ process_loan_interest_accrual_for_demand_loans,
+)
+
class LoanDisbursement(AccountsController):
diff --git a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
index da56710c679..b17c9a177e0 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
+++ b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
@@ -2,16 +2,44 @@
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
-import frappe
+
import unittest
-from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_last_day, date_diff, flt, add_to_date)
-from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_repayment_entry, create_loan_application,
- make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan, create_loan_security_price)
-from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans
-from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year, get_per_day_interest
-from erpnext.selling.doctype.customer.test_customer import get_customer_dict
+
+import frappe
+from frappe.utils import (
+ add_days,
+ add_to_date,
+ date_diff,
+ flt,
+ get_datetime,
+ get_first_day,
+ get_last_day,
+ nowdate,
+)
+
+from erpnext.loan_management.doctype.loan.test_loan import (
+ create_demand_loan,
+ create_loan_accounts,
+ create_loan_application,
+ create_loan_security,
+ create_loan_security_pledge,
+ create_loan_security_price,
+ create_loan_security_type,
+ create_loan_type,
+ create_repayment_entry,
+ make_loan_disbursement_entry,
+)
from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge
+from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (
+ days_in_year,
+ get_per_day_interest,
+)
from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts
+from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (
+ process_loan_interest_accrual_for_demand_loans,
+)
+from erpnext.selling.doctype.customer.test_customer import get_customer_dict
+
class TestLoanDisbursement(unittest.TestCase):
diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
index d75213ce78d..93513a83e7e 100644
--- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
@@ -3,13 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+
+import frappe
from frappe import _
-from frappe.model.document import Document
-from frappe.utils import (nowdate, getdate, now_datetime, get_datetime, flt, date_diff, get_last_day, cint,
- get_first_day, get_datetime, add_days)
-from erpnext.controllers.accounts_controller import AccountsController
+from frappe.utils import add_days, cint, date_diff, flt, get_datetime, getdate, nowdate
+
+import erpnext
from erpnext.accounts.general_ledger import make_gl_entries
+from erpnext.controllers.accounts_controller import AccountsController
+
class LoanInterestAccrual(AccountsController):
def validate(self):
diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py
index eb626f3eee0..06b801e47c5 100644
--- a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py
@@ -2,15 +2,31 @@
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
-import frappe
+
import unittest
-from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_last_day, date_diff, flt, add_to_date)
-from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_price,
- make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan, create_loan_application)
-from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans
-from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year
-from erpnext.selling.doctype.customer.test_customer import get_customer_dict
+
+import frappe
+from frappe.utils import add_to_date, date_diff, flt, get_datetime, get_first_day, nowdate
+
+from erpnext.loan_management.doctype.loan.test_loan import (
+ create_demand_loan,
+ create_loan_accounts,
+ create_loan_application,
+ create_loan_security,
+ create_loan_security_price,
+ create_loan_security_type,
+ create_loan_type,
+ make_loan_disbursement_entry,
+)
from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge
+from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (
+ days_in_year,
+)
+from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (
+ process_loan_interest_accrual_for_demand_loans,
+)
+from erpnext.selling.doctype.customer.test_customer import get_customer_dict
+
class TestLoanInterestAccrual(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index 57aec2e5c9c..13b73573274 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -3,18 +3,26 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-import json
+
+import frappe
from frappe import _
-from frappe.utils import flt, getdate, cint
+from frappe.utils import add_days, cint, date_diff, flt, get_datetime, getdate
from six import iteritems
-from frappe.model.document import Document
-from frappe.utils import date_diff, add_days, getdate, add_months, get_first_day, get_datetime
-from erpnext.controllers.accounts_controller import AccountsController
+
+import erpnext
from erpnext.accounts.general_ledger import make_gl_entries
-from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import update_shortfall_status
-from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans
-from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import get_per_day_interest, get_last_accrual_date
+from erpnext.controllers.accounts_controller import AccountsController
+from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (
+ get_last_accrual_date,
+ get_per_day_interest,
+)
+from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import (
+ update_shortfall_status,
+)
+from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (
+ process_loan_interest_accrual_for_demand_loans,
+)
+
class LoanRepayment(AccountsController):
@@ -107,12 +115,13 @@ class LoanRepayment(AccountsController):
lia = frappe.db.get_value('Loan Interest Accrual', {'process_loan_interest_accrual':
process}, ['name', 'interest_amount', 'payable_principal_amount'], as_dict=1)
- self.append('repayment_details', {
- 'loan_interest_accrual': lia.name,
- 'paid_interest_amount': flt(self.total_interest_paid - self.interest_payable, precision),
- 'paid_principal_amount': 0.0,
- 'accrual_type': 'Repayment'
- })
+ if lia:
+ self.append('repayment_details', {
+ 'loan_interest_accrual': lia.name,
+ 'paid_interest_amount': flt(self.total_interest_paid - self.interest_payable, precision),
+ 'paid_principal_amount': 0.0,
+ 'accrual_type': 'Repayment'
+ })
def update_paid_amount(self):
loan = frappe.get_doc("Loan", self.against_loan)
diff --git a/erpnext/loan_management/doctype/loan_repayment/test_loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/test_loan_repayment.py
index 73585a51592..c6ca630e599 100644
--- a/erpnext/loan_management/doctype/loan_repayment/test_loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/test_loan_repayment.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestLoanRepayment(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.py b/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.py
index a83b9b59415..495466c382e 100644
--- a/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.py
+++ b/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class LoanRepaymentDetail(Document):
pass
diff --git a/erpnext/loan_management/doctype/loan_security/loan_security.py b/erpnext/loan_management/doctype/loan_security/loan_security.py
index 8858c818362..91cce67852a 100644
--- a/erpnext/loan_management/doctype/loan_security/loan_security.py
+++ b/erpnext/loan_management/doctype/loan_security/loan_security.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class LoanSecurity(Document):
def autoname(self):
self.name = self.loan_security_name
diff --git a/erpnext/loan_management/doctype/loan_security/loan_security_dashboard.py b/erpnext/loan_management/doctype/loan_security/loan_security_dashboard.py
index 3eec5660ac1..35f3ba6830f 100644
--- a/erpnext/loan_management/doctype/loan_security/loan_security_dashboard.py
+++ b/erpnext/loan_management/doctype/loan_security/loan_security_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/loan_management/doctype/loan_security/test_loan_security.py b/erpnext/loan_management/doctype/loan_security/test_loan_security.py
index 24dbc680461..910b658a93c 100644
--- a/erpnext/loan_management/doctype/loan_security/test_loan_security.py
+++ b/erpnext/loan_management/doctype/loan_security/test_loan_security.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestLoanSecurity(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py
index c390b6c526d..eb6c79ec4fc 100644
--- a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py
+++ b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py
@@ -3,12 +3,19 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import now_datetime, cint
from frappe.model.document import Document
-from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import update_shortfall_status
-from erpnext.loan_management.doctype.loan_security_price.loan_security_price import get_loan_security_price
+from frappe.utils import cint, now_datetime
+
+from erpnext.loan_management.doctype.loan_security_price.loan_security_price import (
+ get_loan_security_price,
+)
+from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import (
+ update_shortfall_status,
+)
+
class LoanSecurityPledge(Document):
def validate(self):
diff --git a/erpnext/loan_management/doctype/loan_security_pledge/test_loan_security_pledge.py b/erpnext/loan_management/doctype/loan_security_pledge/test_loan_security_pledge.py
index d2347c00985..41bc78ede48 100644
--- a/erpnext/loan_management/doctype/loan_security_pledge/test_loan_security_pledge.py
+++ b/erpnext/loan_management/doctype/loan_security_pledge/test_loan_security_pledge.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestLoanSecurityPledge(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/loan_security_price/loan_security_price.py b/erpnext/loan_management/doctype/loan_security_price/loan_security_price.py
index 9fc1fda53f4..6ede6a2739f 100644
--- a/erpnext/loan_management/doctype/loan_security_price/loan_security_price.py
+++ b/erpnext/loan_management/doctype/loan_security_price/loan_security_price.py
@@ -3,11 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import getdate, now_datetime, add_to_date, get_datetime, get_timestamp, get_datetime_str
-from six import iteritems
+from frappe.utils import get_datetime
+
class LoanSecurityPrice(Document):
def validate(self):
diff --git a/erpnext/loan_management/doctype/loan_security_price/test_loan_security_price.py b/erpnext/loan_management/doctype/loan_security_price/test_loan_security_price.py
index 2fe0bd5a24e..ac630868427 100644
--- a/erpnext/loan_management/doctype/loan_security_price/test_loan_security_price.py
+++ b/erpnext/loan_management/doctype/loan_security_price/test_loan_security_price.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestLoanSecurityPrice(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
index cd7694b7b17..5863c03f0f4 100644
--- a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
+++ b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
@@ -3,11 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import get_datetime, flt
from frappe.model.document import Document
-from six import iteritems
-from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
+from frappe.utils import flt, get_datetime
+
+from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import (
+ get_pledged_security_qty,
+)
+
class LoanSecurityShortfall(Document):
pass
@@ -71,7 +75,7 @@ def check_for_ltv_shortfall(process_loan_security_shortfall):
- flt(loan.total_principal_paid)
pledged_securities = get_pledged_security_qty(loan.name)
- ltv_ratio = ''
+ ltv_ratio = 0.0
security_value = 0.0
for security, qty in pledged_securities.items():
diff --git a/erpnext/loan_management/doctype/loan_security_shortfall/test_loan_security_shortfall.py b/erpnext/loan_management/doctype/loan_security_shortfall/test_loan_security_shortfall.py
index b82f3d25936..fefec43bf41 100644
--- a/erpnext/loan_management/doctype/loan_security_shortfall/test_loan_security_shortfall.py
+++ b/erpnext/loan_management/doctype/loan_security_shortfall/test_loan_security_shortfall.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestLoanSecurityShortfall(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/loan_security_type/loan_security_type.py b/erpnext/loan_management/doctype/loan_security_type/loan_security_type.py
index cb8a50a27ba..ca1957fb3aa 100644
--- a/erpnext/loan_management/doctype/loan_security_type/loan_security_type.py
+++ b/erpnext/loan_management/doctype/loan_security_type/loan_security_type.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class LoanSecurityType(Document):
pass
diff --git a/erpnext/loan_management/doctype/loan_security_type/loan_security_type_dashboard.py b/erpnext/loan_management/doctype/loan_security_type/loan_security_type_dashboard.py
index 17de8c1da4d..7a2732e3190 100644
--- a/erpnext/loan_management/doctype/loan_security_type/loan_security_type_dashboard.py
+++ b/erpnext/loan_management/doctype/loan_security_type/loan_security_type_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/loan_management/doctype/loan_security_type/test_loan_security_type.py b/erpnext/loan_management/doctype/loan_security_type/test_loan_security_type.py
index f7d845a779c..99d7aafb343 100644
--- a/erpnext/loan_management/doctype/loan_security_type/test_loan_security_type.py
+++ b/erpnext/loan_management/doctype/loan_security_type/test_loan_security_type.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestLoanSecurityType(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
index 4f936dd7c11..0af0de1a53a 100644
--- a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
+++ b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
@@ -3,13 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import get_datetime, flt, getdate
-import json
+from frappe.utils import flt, get_datetime, getdate
from six import iteritems
-from erpnext.loan_management.doctype.loan_security_price.loan_security_price import get_loan_security_price
+
class LoanSecurityUnpledge(Document):
def validate(self):
@@ -30,7 +30,9 @@ class LoanSecurityUnpledge(Document):
d.idx, frappe.bold(d.loan_security)))
def validate_unpledge_qty(self):
- from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import get_ltv_ratio
+ from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import (
+ get_ltv_ratio,
+ )
pledge_qty_map = get_pledged_security_qty(self.loan)
diff --git a/erpnext/loan_management/doctype/loan_security_unpledge/test_loan_security_unpledge.py b/erpnext/loan_management/doctype/loan_security_unpledge/test_loan_security_unpledge.py
index 5b5c205bda0..17eb7c63c7a 100644
--- a/erpnext/loan_management/doctype/loan_security_unpledge/test_loan_security_unpledge.py
+++ b/erpnext/loan_management/doctype/loan_security_unpledge/test_loan_security_unpledge.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestLoanSecurityUnpledge(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/loan_type/loan_type.py b/erpnext/loan_management/doctype/loan_type/loan_type.py
index 50ef930dbbe..5458d358f3b 100644
--- a/erpnext/loan_management/doctype/loan_type/loan_type.py
+++ b/erpnext/loan_management/doctype/loan_type/loan_type.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
class LoanType(Document):
def validate(self):
self.validate_accounts()
diff --git a/erpnext/loan_management/doctype/loan_type/loan_type_dashboard.py b/erpnext/loan_management/doctype/loan_type/loan_type_dashboard.py
index 95d97fdf9b0..96b2c4aedcf 100644
--- a/erpnext/loan_management/doctype/loan_type/loan_type_dashboard.py
+++ b/erpnext/loan_management/doctype/loan_type/loan_type_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/loan_management/doctype/loan_type/test_loan_type.py b/erpnext/loan_management/doctype/loan_type/test_loan_type.py
index 5877ab6f7f0..9e57fdef2fa 100644
--- a/erpnext/loan_management/doctype/loan_type/test_loan_type.py
+++ b/erpnext/loan_management/doctype/loan_type/test_loan_type.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestLoanType(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py
index 676df701cc3..4d5e7df4de1 100644
--- a/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py
+++ b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py
@@ -3,11 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+
+import frappe
from frappe import _
-from frappe.utils import getdate, flt, cint
-from erpnext.controllers.accounts_controller import AccountsController
+from frappe.utils import cint, flt, getdate
+
+import erpnext
from erpnext.accounts.general_ledger import make_gl_entries
+from erpnext.controllers.accounts_controller import AccountsController
+
class LoanWriteOff(AccountsController):
def validate(self):
diff --git a/erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py b/erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py
index 9f6700e2749..57337c7e5d2 100644
--- a/erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py
+++ b/erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestLoanWriteOff(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/pledge/pledge.py b/erpnext/loan_management/doctype/pledge/pledge.py
index 0457ad7abdb..5a41cde4b58 100644
--- a/erpnext/loan_management/doctype/pledge/pledge.py
+++ b/erpnext/loan_management/doctype/pledge/pledge.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class Pledge(Document):
pass
diff --git a/erpnext/loan_management/doctype/pledge/test_pledge.py b/erpnext/loan_management/doctype/pledge/test_pledge.py
index 2e01dc114d7..adcbc6eae03 100644
--- a/erpnext/loan_management/doctype/pledge/test_pledge.py
+++ b/erpnext/loan_management/doctype/pledge/test_pledge.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestPledge(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py
index 8c67c0affee..efee701dc04 100644
--- a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py
@@ -3,11 +3,16 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import nowdate
from frappe.model.document import Document
-from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (make_accrual_interest_entry_for_demand_loans,
- make_accrual_interest_entry_for_term_loans)
+from frappe.utils import nowdate
+
+from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (
+ make_accrual_interest_entry_for_demand_loans,
+ make_accrual_interest_entry_for_term_loans,
+)
+
class ProcessLoanInterestAccrual(Document):
def on_submit(self):
diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual_dashboard.py b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual_dashboard.py
index e104c6646b0..fcd0399c6e9 100644
--- a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual_dashboard.py
+++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/test_process_loan_interest_accrual.py b/erpnext/loan_management/doctype/process_loan_interest_accrual/test_process_loan_interest_accrual.py
index 6bfd3f42103..e7d360209ca 100644
--- a/erpnext/loan_management/doctype/process_loan_interest_accrual/test_process_loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/test_process_loan_interest_accrual.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestProcessLoanInterestAccrual(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.py b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.py
index b4aad25ac80..c3f59543c4e 100644
--- a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.py
+++ b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.py
@@ -3,11 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import get_datetime
-from frappe import _
from frappe.model.document import Document
-from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import check_for_ltv_shortfall
+from frappe.utils import get_datetime
+
+from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import (
+ check_for_ltv_shortfall,
+)
+
class ProcessLoanSecurityShortfall(Document):
def onload(self):
diff --git a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall_dashboard.py b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall_dashboard.py
index e67e4d4738f..ced3bd7e4fb 100644
--- a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall_dashboard.py
+++ b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/loan_management/doctype/process_loan_security_shortfall/test_process_loan_security_shortfall.py b/erpnext/loan_management/doctype/process_loan_security_shortfall/test_process_loan_security_shortfall.py
index cd379a1bea2..50e0a46ee4f 100644
--- a/erpnext/loan_management/doctype/process_loan_security_shortfall/test_process_loan_security_shortfall.py
+++ b/erpnext/loan_management/doctype/process_loan_security_shortfall/test_process_loan_security_shortfall.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestProcessLoanSecurityShortfall(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.py b/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.py
index dfa5c7965a0..5c125e1307e 100644
--- a/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.py
+++ b/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ProposedPledge(Document):
pass
diff --git a/erpnext/loan_management/doctype/repayment_schedule/repayment_schedule.py b/erpnext/loan_management/doctype/repayment_schedule/repayment_schedule.py
index 2aa27b09687..af9c6696aca 100644
--- a/erpnext/loan_management/doctype/repayment_schedule/repayment_schedule.py
+++ b/erpnext/loan_management/doctype/repayment_schedule/repayment_schedule.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class RepaymentSchedule(Document):
pass
diff --git a/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.py b/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.py
index 9ee0b96dc1d..64be1b2673e 100644
--- a/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.py
+++ b/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class SalarySlipLoan(Document):
pass
diff --git a/erpnext/loan_management/doctype/sanctioned_loan_amount/sanctioned_loan_amount.py b/erpnext/loan_management/doctype/sanctioned_loan_amount/sanctioned_loan_amount.py
index 74a131015b5..5660c421022 100644
--- a/erpnext/loan_management/doctype/sanctioned_loan_amount/sanctioned_loan_amount.py
+++ b/erpnext/loan_management/doctype/sanctioned_loan_amount/sanctioned_loan_amount.py
@@ -3,9 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
+from frappe import _
from frappe.model.document import Document
+
class SanctionedLoanAmount(Document):
def validate(self):
sanctioned_doc = frappe.db.exists('Sanctioned Loan Amount', {'applicant': self.applicant, 'company': self.company})
diff --git a/erpnext/loan_management/doctype/sanctioned_loan_amount/test_sanctioned_loan_amount.py b/erpnext/loan_management/doctype/sanctioned_loan_amount/test_sanctioned_loan_amount.py
index ba1372f175d..663f2e72beb 100644
--- a/erpnext/loan_management/doctype/sanctioned_loan_amount/test_sanctioned_loan_amount.py
+++ b/erpnext/loan_management/doctype/sanctioned_loan_amount/test_sanctioned_loan_amount.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestSanctionedLoanAmount(unittest.TestCase):
pass
diff --git a/erpnext/loan_management/doctype/unpledge/unpledge.py b/erpnext/loan_management/doctype/unpledge/unpledge.py
index 205230a308f..2e82e239979 100644
--- a/erpnext/loan_management/doctype/unpledge/unpledge.py
+++ b/erpnext/loan_management/doctype/unpledge/unpledge.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class Unpledge(Document):
pass
diff --git a/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.py b/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.py
index f2cbbb469f0..ff527029f67 100644
--- a/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.py
+++ b/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.py
@@ -2,12 +2,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-import erpnext
from frappe import _
-from frappe.utils import get_datetime, flt
+from frappe.utils import flt
from six import iteritems
+import erpnext
+
+
def execute(filters=None):
columns = get_columns(filters)
data = get_data(filters)
diff --git a/erpnext/loan_management/report/loan_interest_report/loan_interest_report.py b/erpnext/loan_management/report/loan_interest_report/loan_interest_report.py
index a505e72c4d9..c4adef1c7ba 100644
--- a/erpnext/loan_management/report/loan_interest_report/loan_interest_report.py
+++ b/erpnext/loan_management/report/loan_interest_report/loan_interest_report.py
@@ -2,12 +2,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-import erpnext
from frappe import _
-from frappe.utils import flt, getdate, add_days
-from erpnext.loan_management.report.applicant_wise_loan_security_exposure.applicant_wise_loan_security_exposure \
- import get_loan_security_details
+from frappe.utils import add_days, flt, getdate
+
+import erpnext
+from erpnext.loan_management.report.applicant_wise_loan_security_exposure.applicant_wise_loan_security_exposure import (
+ get_loan_security_details,
+)
def execute(filters=None):
diff --git a/erpnext/loan_management/report/loan_repayment_and_closure/loan_repayment_and_closure.py b/erpnext/loan_management/report/loan_repayment_and_closure/loan_repayment_and_closure.py
index 65910770881..9d8a425b30c 100644
--- a/erpnext/loan_management/report/loan_repayment_and_closure/loan_repayment_and_closure.py
+++ b/erpnext/loan_management/report/loan_repayment_and_closure/loan_repayment_and_closure.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
columns = get_columns()
data = get_data(filters)
diff --git a/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py b/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py
index 34bbe5a4503..3d6242a4fa1 100644
--- a/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py
+++ b/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py
@@ -2,12 +2,17 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import erpnext
+
from frappe import _
from frappe.utils import flt
from six import iteritems
-from erpnext.loan_management.report.applicant_wise_loan_security_exposure.applicant_wise_loan_security_exposure \
- import get_loan_security_details, get_applicant_wise_total_loan_security_qty
+
+import erpnext
+from erpnext.loan_management.report.applicant_wise_loan_security_exposure.applicant_wise_loan_security_exposure import (
+ get_applicant_wise_total_loan_security_qty,
+ get_loan_security_details,
+)
+
def execute(filters=None):
columns = get_columns(filters)
diff --git a/erpnext/loan_management/report/loan_security_status/loan_security_status.py b/erpnext/loan_management/report/loan_security_status/loan_security_status.py
index 19518554759..a93a381eb3f 100644
--- a/erpnext/loan_management/report/loan_security_status/loan_security_status.py
+++ b/erpnext/loan_management/report/loan_security_status/loan_security_status.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
columns = get_columns(filters)
data = get_data(filters)
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
index 97289032d70..52e41c5863e 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
@@ -2,15 +2,16 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+from frappe import _, throw
+from frappe.utils import add_days, cint, cstr, date_diff, formatdate, getdate
-from frappe.utils import add_days, getdate, cint, cstr, date_diff, formatdate
-
-from frappe import throw, _
-from erpnext.utilities.transaction_base import TransactionBase, delete_events
-from erpnext.stock.utils import get_valid_serial_nos
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+from erpnext.stock.utils import get_valid_serial_nos
+from erpnext.utilities.transaction_base import TransactionBase, delete_events
+
class MaintenanceSchedule(TransactionBase):
@frappe.whitelist()
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.js
deleted file mode 100644
index e0f05b1abbd..00000000000
--- a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Maintenance Schedule", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Maintenance Schedule
- () => frappe.tests.make('Maintenance Schedule', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py
index c733dd0c92c..38654de6638 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py
@@ -2,11 +2,15 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
-from frappe.utils.data import add_days, today, formatdate
-from erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule import make_maintenance_visit
+
+import unittest
import frappe
-import unittest
+from frappe.utils.data import add_days, formatdate, today
+
+from erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule import (
+ make_maintenance_visit,
+)
# test_records = frappe.get_test_records('Maintenance Schedule')
diff --git a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.py b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.py
index e69b4fb65e0..27c95a1ea2b 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class MaintenanceScheduleDetail(Document):
pass
diff --git a/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.py b/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.py
index 1dd47fea24f..9c4a690789d 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class MaintenanceScheduleItem(Document):
pass
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
index 8e488c1ce12..443fb6d2dc7 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
@@ -31,8 +31,8 @@ frappe.ui.form.on('Maintenance Visit', {
},
onload: function (frm, cdt, cdn) {
let item = locals[cdt][cdn];
- if (frm.maintenance_type == 'Scheduled') {
- let schedule_id = item.purposes[0].prevdoc_detail_docname;
+ if (frm.doc.maintenance_type === "Scheduled") {
+ const schedule_id = item.purposes[0].prevdoc_detail_docname || frm.doc.maintenance_schedule_detail;
frappe.call({
method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.update_serial_nos",
args: {
@@ -43,6 +43,9 @@ frappe.ui.form.on('Maintenance Visit', {
}
});
}
+ else {
+ frm.clear_table("purposes");
+ }
if (!frm.doc.status) {
frm.set_value({ status: 'Draft' });
@@ -73,12 +76,16 @@ erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({
if (this.frm.doc.docstatus === 0) {
this.frm.add_custom_button(__('Maintenance Schedule'),
function () {
+ if (!me.frm.doc.customer) {
+ frappe.msgprint(__('Please select Customer first'));
+ return;
+ }
erpnext.utils.map_current_doc({
method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit",
source_doctype: "Maintenance Schedule",
target: me.frm,
setters: {
- customer: me.frm.doc.customer || undefined,
+ customer: me.frm.doc.customer,
},
get_query_filters: {
docstatus: 1,
@@ -104,12 +111,16 @@ erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({
}, __("Get Items From"));
this.frm.add_custom_button(__('Sales Order'),
function () {
+ if (!me.frm.doc.customer) {
+ frappe.msgprint(__('Please select Customer first'));
+ return;
+ }
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit",
source_doctype: "Sales Order",
target: me.frm,
setters: {
- customer: me.frm.doc.customer || undefined,
+ customer: me.frm.doc.customer,
},
get_query_filters: {
docstatus: 1,
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
index d63c7003870..814ec0cae4b 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
@@ -2,12 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import get_datetime
from erpnext.utilities.transaction_base import TransactionBase
+
class MaintenanceVisit(TransactionBase):
def get_feed(self):
return _("To {0}").format(self.customer_name)
diff --git a/erpnext/maintenance/doctype/maintenance_visit/test_maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/test_maintenance_visit.py
index 2bea8d1e2f6..57e728d1b13 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/test_maintenance_visit.py
+++ b/erpnext/maintenance/doctype/maintenance_visit/test_maintenance_visit.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Maintenance Visit')
diff --git a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py
index a7f0f5b3bb9..4c59562685d 100644
--- a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py
+++ b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class MaintenanceVisitPurpose(Document):
pass
diff --git a/erpnext/manufacturing/dashboard_fixtures.py b/erpnext/manufacturing/dashboard_fixtures.py
index 7ba43d6471e..1bc12ff35eb 100644
--- a/erpnext/manufacturing/dashboard_fixtures.py
+++ b/erpnext/manufacturing/dashboard_fixtures.py
@@ -1,9 +1,14 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-import frappe, erpnext, json
+import json
+
+import frappe
from frappe import _
-from frappe.utils import nowdate, get_first_day, get_last_day, add_months
+from frappe.utils import add_months, nowdate
+
+import erpnext
+
def get_data():
return frappe._dict({
diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py
index 1aedb1e590f..59eb168d4e4 100644
--- a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py
+++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py
@@ -3,11 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt, getdate
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
+from frappe.utils import flt, getdate
+
from erpnext.stock.doctype.item.item import get_item_defaults
diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order_dashboard.py b/erpnext/manufacturing/doctype/blanket_order/blanket_order_dashboard.py
index d9aa0ca49d0..83260ec1b9f 100644
--- a/erpnext/manufacturing/doctype/blanket_order/blanket_order_dashboard.py
+++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.js b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.js
deleted file mode 100644
index 51a0d948419..00000000000
--- a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Blanket Order", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Blanket Order
- () => frappe.tests.make('Blanket Order', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py
index 9a0a72fb475..3104ae01177 100644
--- a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py
+++ b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py
@@ -3,12 +3,16 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
from frappe.utils import add_months, today
+
from erpnext import get_company_currency
+
from .blanket_order import make_order
+
class TestBlanketOrder(unittest.TestCase):
def setUp(self):
frappe.flags.args = frappe._dict()
diff --git a/erpnext/manufacturing/doctype/blanket_order_item/blanket_order_item.py b/erpnext/manufacturing/doctype/blanket_order_item/blanket_order_item.py
index f07f3c8e046..0825f763dcf 100644
--- a/erpnext/manufacturing/doctype/blanket_order_item/blanket_order_item.py
+++ b/erpnext/manufacturing/doctype/blanket_order_item/blanket_order_item.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class BlanketOrderItem(Document):
pass
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index ed0874b5775..3ea756eec97 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -1,23 +1,22 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-from typing import List
-from collections import deque
-import frappe, erpnext
-from frappe.utils import cint, cstr, flt, today
-from frappe import _
-from erpnext.setup.utils import get_exchange_rate
-from frappe.website.website_generator import WebsiteGenerator
-from erpnext.stock.get_item_details import get_conversion_factor
-from erpnext.stock.get_item_details import get_price_list_rate
-from frappe.core.doctype.version.version import get_diff
-from erpnext.controllers.queries import get_match_cond
-from erpnext.stock.doctype.item.item import get_item_details
-from frappe.model.mapper import get_mapped_doc
-
import functools
-
+from collections import deque
from operator import itemgetter
+from typing import List
+
+import frappe
+from frappe import _
+from frappe.core.doctype.version.version import get_diff
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import cint, cstr, flt, today
+from frappe.website.website_generator import WebsiteGenerator
+
+import erpnext
+from erpnext.setup.utils import get_exchange_rate
+from erpnext.stock.doctype.item.item import get_item_details
+from erpnext.stock.get_item_details import get_conversion_factor, get_price_list_rate
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@@ -448,25 +447,29 @@ class BOM(WebsiteGenerator):
frappe.throw(_("Quantity required for Item {0} in row {1}").format(m.item_code, m.idx))
check_list.append(m)
- def check_recursion(self, bom_list=[]):
+ def check_recursion(self, bom_list=None):
""" Check whether recursion occurs in any bom"""
+ def _throw_error(bom_name):
+ frappe.throw(_("BOM recursion: {0} cannot be parent or child of {0}").format(bom_name))
+
bom_list = self.traverse_tree()
- bom_nos = frappe.get_all('BOM Item', fields=["bom_no"],
- filters={'parent': ('in', bom_list), 'parenttype': 'BOM'})
+ child_items = frappe.get_all('BOM Item', fields=["bom_no", "item_code"],
+ filters={'parent': ('in', bom_list), 'parenttype': 'BOM'}) or []
- raise_exception = False
- if bom_nos and self.name in [d.bom_no for d in bom_nos]:
- raise_exception = True
+ child_bom = {d.bom_no for d in child_items}
+ child_items_codes = {d.item_code for d in child_items}
- if not raise_exception:
- bom_nos = frappe.get_all('BOM Item', fields=["parent"],
- filters={'bom_no': self.name, 'parenttype': 'BOM'})
+ if self.name in child_bom:
+ _throw_error(self.name)
- if self.name in [d.parent for d in bom_nos]:
- raise_exception = True
+ if self.item in child_items_codes:
+ _throw_error(self.item)
- if raise_exception:
- frappe.throw(_("BOM recursion: {0} cannot be parent or child of {1}").format(self.name, self.name))
+ bom_nos = frappe.get_all('BOM Item', fields=["parent"],
+ filters={'bom_no': self.name, 'parenttype': 'BOM'}) or []
+
+ if self.name in {d.parent for d in bom_nos}:
+ _throw_error(self.name)
def traverse_tree(self, bom_list=None):
def _get_children(bom_no):
@@ -508,8 +511,14 @@ class BOM(WebsiteGenerator):
if d.workstation:
self.update_rate_and_time(d, update_hour_rate)
- self.operating_cost += flt(d.operating_cost)
- self.base_operating_cost += flt(d.base_operating_cost)
+ operating_cost = d.operating_cost
+ base_operating_cost = d.base_operating_cost
+ if d.set_cost_based_on_bom_qty:
+ operating_cost = flt(d.cost_per_unit) * flt(self.quantity)
+ base_operating_cost = flt(d.base_cost_per_unit) * flt(self.quantity)
+
+ self.operating_cost += flt(operating_cost)
+ self.base_operating_cost += flt(base_operating_cost)
def update_rate_and_time(self, row, update_hour_rate = False):
if not row.hour_rate or update_hour_rate:
@@ -533,6 +542,8 @@ class BOM(WebsiteGenerator):
row.base_hour_rate = flt(row.hour_rate) * flt(self.conversion_rate)
row.operating_cost = flt(row.hour_rate) * flt(row.time_in_mins) / 60.0
row.base_operating_cost = flt(row.operating_cost) * flt(self.conversion_rate)
+ row.cost_per_unit = row.operating_cost / (row.batch_size or 1.0)
+ row.base_cost_per_unit = row.base_operating_cost / (row.batch_size or 1.0)
if update_hour_rate:
row.db_update()
diff --git a/erpnext/manufacturing/doctype/bom/bom_dashboard.py b/erpnext/manufacturing/doctype/bom/bom_dashboard.py
index 361826e2d0c..f65df011a93 100644
--- a/erpnext/manufacturing/doctype/bom/bom_dashboard.py
+++ b/erpnext/manufacturing/doctype/bom/bom_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'bom_no',
diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py
index 6a81ac33679..8338fa30ddc 100644
--- a/erpnext/manufacturing/doctype/bom/test_bom.py
+++ b/erpnext/manufacturing/doctype/bom/test_bom.py
@@ -2,15 +2,19 @@
# License: GNU General Public License v3. See license.txt
-from collections import deque
import unittest
+from collections import deque
+
import frappe
-from frappe.utils import cstr, flt
from frappe.test_runner import make_test_records
-from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
+from frappe.utils import cstr, flt
+
+from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
from erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool import update_cost
from erpnext.stock.doctype.item.test_item import make_item
-from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
+from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
+ create_stock_reconciliation,
+)
from erpnext.tests.test_subcontracting import set_backflush_based_on
test_records = frappe.get_test_records('BOM')
@@ -103,6 +107,24 @@ class TestBOM(unittest.TestCase):
self.assertAlmostEqual(bom.base_raw_material_cost, base_raw_material_cost)
self.assertAlmostEqual(bom.base_total_cost, base_raw_material_cost + base_op_cost)
+ def test_bom_cost_with_batch_size(self):
+ bom = frappe.copy_doc(test_records[2])
+ bom.docstatus = 0
+ op_cost = 0.0
+ for op_row in bom.operations:
+ op_row.docstatus = 0
+ op_row.batch_size = 2
+ op_row.set_cost_based_on_bom_qty = 1
+ op_cost += op_row.operating_cost
+
+ bom.save()
+
+ for op_row in bom.operations:
+ self.assertAlmostEqual(op_row.cost_per_unit, op_row.operating_cost / 2)
+
+ self.assertAlmostEqual(bom.operating_cost, op_cost/2)
+ bom.delete()
+
def test_bom_cost_multi_uom_multi_currency_based_on_price_list(self):
frappe.db.set_value("Price List", "_Test Price List", "price_not_uom_dependent", 1)
for item_code, rate in (("_Test Item", 3600), ("_Test Item Home Desktop Manufactured", 3000)):
@@ -227,6 +249,46 @@ class TestBOM(unittest.TestCase):
self.assertEqual(bom_items, supplied_items)
+ def test_bom_recursion_1st_level(self):
+ """BOM should not allow BOM item again in child"""
+ item_code = "_Test BOM Recursion"
+ make_item(item_code, {'is_stock_item': 1})
+
+ bom = frappe.new_doc("BOM")
+ bom.item = item_code
+ bom.append("items", frappe._dict(item_code=item_code))
+ with self.assertRaises(frappe.ValidationError) as err:
+ bom.save()
+
+ self.assertTrue("recursion" in str(err.exception).lower())
+ frappe.delete_doc("BOM", bom.name, ignore_missing=True)
+
+ def test_bom_recursion_transitive(self):
+ item1 = "_Test BOM Recursion"
+ item2 = "_Test BOM Recursion 2"
+ make_item(item1, {'is_stock_item': 1})
+ make_item(item2, {'is_stock_item': 1})
+
+ bom1 = frappe.new_doc("BOM")
+ bom1.item = item1
+ bom1.append("items", frappe._dict(item_code=item2))
+ bom1.save()
+ bom1.submit()
+
+ bom2 = frappe.new_doc("BOM")
+ bom2.item = item2
+ bom2.append("items", frappe._dict(item_code=item1))
+
+ with self.assertRaises(frappe.ValidationError) as err:
+ bom2.save()
+ bom2.submit()
+
+ self.assertTrue("recursion" in str(err.exception).lower())
+
+ bom1.cancel()
+ frappe.delete_doc("BOM", bom1.name, ignore_missing=True, force=True)
+ frappe.delete_doc("BOM", bom2.name, ignore_missing=True, force=True)
+
def test_bom_with_process_loss_item(self):
fg_item_non_whole, fg_item_whole, bom_item = create_process_loss_bom_items()
diff --git a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.py b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.py
index 39ccbddbea2..4317d3adf68 100644
--- a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.py
+++ b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class BOMExplosionItem(Document):
pass
diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.py b/erpnext/manufacturing/doctype/bom_item/bom_item.py
index 220c73e1493..2954238a571 100644
--- a/erpnext/manufacturing/doctype/bom_item/bom_item.py
+++ b/erpnext/manufacturing/doctype/bom_item/bom_item.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class BOMItem(Document):
pass
diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
index 4458e6db234..ec617f3aaa9 100644
--- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
+++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
@@ -8,15 +8,23 @@
"field_order": [
"sequence_id",
"operation",
- "workstation",
- "description",
"col_break1",
- "hour_rate",
+ "workstation",
"time_in_mins",
- "operating_cost",
+ "costing_section",
+ "hour_rate",
"base_hour_rate",
+ "column_break_9",
+ "operating_cost",
"base_operating_cost",
+ "column_break_11",
"batch_size",
+ "set_cost_based_on_bom_qty",
+ "cost_per_unit",
+ "base_cost_per_unit",
+ "more_information_section",
+ "description",
+ "column_break_18",
"image"
],
"fields": [
@@ -117,13 +125,59 @@
"fieldname": "sequence_id",
"fieldtype": "Int",
"label": "Sequence ID"
+ },
+ {
+ "depends_on": "eval:doc.batch_size > 0 && doc.set_cost_based_on_bom_qty",
+ "fieldname": "cost_per_unit",
+ "fieldtype": "Float",
+ "label": "Cost Per Unit",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "base_cost_per_unit",
+ "fieldtype": "Float",
+ "hidden": 1,
+ "label": "Base Cost Per Unit",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "costing_section",
+ "fieldtype": "Section Break",
+ "label": "Costing"
+ },
+ {
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "more_information_section",
+ "fieldtype": "Section Break",
+ "label": "More Information"
+ },
+ {
+ "fieldname": "column_break_18",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_9",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "set_cost_based_on_bom_qty",
+ "fieldtype": "Check",
+ "label": "Set Operating Cost Based On BOM Quantity"
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-01-12 14:48:09.596843",
+ "modified": "2021-09-13 16:45:01.092868",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Operation",
diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.py b/erpnext/manufacturing/doctype/bom_operation/bom_operation.py
index e3501eb9cf6..5e46c7ef932 100644
--- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.py
+++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class BOMOperation(Document):
pass
diff --git a/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.py b/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.py
index b6d423f09f2..891fc53c71e 100644
--- a/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.py
+++ b/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class BOMScrapItem(Document):
pass
diff --git a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
index 8fbcd4ea1db..ed71c6d6d7b 100644
--- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
+++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
@@ -3,13 +3,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, json
-from frappe.utils import cstr, flt
-from frappe import _
-from six import string_types
-from erpnext.manufacturing.doctype.bom.bom import get_boms_in_bottom_up_order
-from frappe.model.document import Document
+
+import json
+
import click
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from frappe.utils import cstr, flt
+from six import string_types
+
+from erpnext.manufacturing.doctype.bom.bom import get_boms_in_bottom_up_order
+
class BOMUpdateTool(Document):
def replace_bom(self):
diff --git a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.js b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.js
deleted file mode 100644
index d220df2824f..00000000000
--- a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* 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()
- ]);
-
-});
diff --git a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py
index 80d1cdfc8f2..88c69ce2a5e 100644
--- a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py
+++ b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py
@@ -3,11 +3,14 @@
from __future__ import unicode_literals
+
import unittest
+
import frappe
-from erpnext.stock.doctype.item.test_item import create_item
-from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
+
from erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool import update_cost
+from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
+from erpnext.stock.doctype.item.test_item import create_item
test_records = frappe.get_test_records('BOM')
diff --git a/erpnext/manufacturing/doctype/bom_website_item/bom_website_item.py b/erpnext/manufacturing/doctype/bom_website_item/bom_website_item.py
index 4088a7fc540..f627b4e5283 100644
--- a/erpnext/manufacturing/doctype/bom_website_item/bom_website_item.py
+++ b/erpnext/manufacturing/doctype/bom_website_item/bom_website_item.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class BOMWebsiteItem(Document):
pass
diff --git a/erpnext/manufacturing/doctype/bom_website_operation/bom_website_operation.py b/erpnext/manufacturing/doctype/bom_website_operation/bom_website_operation.py
index bcc5ddab089..5bd8cf568c7 100644
--- a/erpnext/manufacturing/doctype/bom_website_operation/bom_website_operation.py
+++ b/erpnext/manufacturing/doctype/bom_website_operation/bom_website_operation.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class BOMWebsiteOperation(Document):
pass
diff --git a/erpnext/manufacturing/doctype/downtime_entry/downtime_entry.py b/erpnext/manufacturing/doctype/downtime_entry/downtime_entry.py
index 56ec4356af4..62833d7cd20 100644
--- a/erpnext/manufacturing/doctype/downtime_entry/downtime_entry.py
+++ b/erpnext/manufacturing/doctype/downtime_entry/downtime_entry.py
@@ -3,9 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import time_diff_in_hours
+
from frappe.model.document import Document
+from frappe.utils import time_diff_in_hours
+
class DowntimeEntry(Document):
def validate(self):
diff --git a/erpnext/manufacturing/doctype/downtime_entry/test_downtime_entry.py b/erpnext/manufacturing/doctype/downtime_entry/test_downtime_entry.py
index 8b2a8d36c12..37169f4439a 100644
--- a/erpnext/manufacturing/doctype/downtime_entry/test_downtime_entry.py
+++ b/erpnext/manufacturing/doctype/downtime_entry/test_downtime_entry.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestDowntimeEntry(unittest.TestCase):
pass
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js
index 91eb4a0fa90..35be38813e5 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.js
+++ b/erpnext/manufacturing/doctype/job_card/job_card.js
@@ -26,15 +26,23 @@ frappe.ui.form.on('Job Card', {
refresh: function(frm) {
frappe.flags.pause_job = 0;
frappe.flags.resume_job = 0;
+ let has_items = frm.doc.items && frm.doc.items.length;
- if(!frm.doc.__islocal && frm.doc.items && frm.doc.items.length) {
- if (frm.doc.for_quantity != frm.doc.transferred_qty) {
+ if (!frm.doc.__islocal && has_items && frm.doc.docstatus < 2) {
+ let to_request = frm.doc.for_quantity > frm.doc.transferred_qty;
+ let excess_transfer_allowed = frm.doc.__onload.job_card_excess_transfer;
+
+ if (to_request || excess_transfer_allowed) {
frm.add_custom_button(__("Material Request"), () => {
frm.trigger("make_material_request");
});
}
- if (frm.doc.for_quantity != frm.doc.transferred_qty) {
+ // check if any row has untransferred materials
+ // in case of multiple items in JC
+ let to_transfer = frm.doc.items.some((row) => row.transferred_qty < row.required_qty);
+
+ if (to_transfer || excess_transfer_allowed) {
frm.add_custom_button(__("Material Transfer"), () => {
frm.trigger("make_stock_entry");
}).addClass("btn-primary");
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.json b/erpnext/manufacturing/doctype/job_card/job_card.json
index 046e2fd1825..7dd38f4673d 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.json
+++ b/erpnext/manufacturing/doctype/job_card/job_card.json
@@ -38,6 +38,8 @@
"total_time_in_mins",
"section_break_8",
"items",
+ "scrap_items_section",
+ "scrap_items",
"corrective_operation_section",
"for_job_card",
"is_corrective_job_card",
@@ -185,7 +187,7 @@
"default": "0",
"fieldname": "transferred_qty",
"fieldtype": "Float",
- "label": "Transferred Qty",
+ "label": "FG Qty from Transferred Raw Materials",
"read_only": 1
},
{
@@ -392,14 +394,28 @@
"fieldtype": "Link",
"label": "Batch No",
"options": "Batch"
+ },
+ {
+ "fieldname": "scrap_items_section",
+ "fieldtype": "Section Break",
+ "label": "Scrap Items"
+ },
+ {
+ "fieldname": "scrap_items",
+ "fieldtype": "Table",
+ "label": "Scrap Items",
+ "no_copy": 1,
+ "options": "Job Card Scrap Item",
+ "print_hide": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2021-03-16 15:59:32.766484",
+ "modified": "2021-09-14 00:38:46.873105",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Job Card",
+ "naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index 3efbe88adaf..3209546a12c 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -1,18 +1,31 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
import datetime
import json
-from frappe import _, bold
-from frappe.model.mapper import get_mapped_doc
-from frappe.model.document import Document
-from frappe.utils import (flt, cint, time_diff_in_hours, get_datetime, getdate,
- get_time, add_to_date, time_diff, add_days, get_datetime_str, get_link_to_form, time_diff_in_seconds)
-from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
+import frappe
+from frappe import _, bold
+from frappe.model.document import Document
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import (
+ add_days,
+ add_to_date,
+ cint,
+ flt,
+ get_datetime,
+ get_link_to_form,
+ get_time,
+ getdate,
+ time_diff,
+ time_diff_in_hours,
+ time_diff_in_seconds,
+)
+
+from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import (
+ get_mins_between_operations,
+)
+
class OverlapError(frappe.ValidationError): pass
@@ -21,6 +34,10 @@ class OperationSequenceError(frappe.ValidationError): pass
class JobCardCancelError(frappe.ValidationError): pass
class JobCard(Document):
+ def onload(self):
+ excess_transfer = frappe.db.get_single_value("Manufacturing Settings", "job_card_excess_transfer")
+ self.set_onload("job_card_excess_transfer", excess_transfer)
+
def validate(self):
self.validate_time_logs()
self.set_status()
@@ -75,7 +92,7 @@ class JobCard(Document):
if args.get("employee"):
# override capacity for employee
production_capacity = 1
- validate_overlap_for = " and jc.employee = %(employee)s "
+ validate_overlap_for = " and jctl.employee = %(employee)s "
extra_cond = ''
if check_next_available_slot:
@@ -433,6 +450,7 @@ class JobCard(Document):
frappe.db.set_value('Job Card Item', row.job_card_item, 'transferred_qty', flt(qty))
def set_transferred_qty(self, update_status=False):
+ "Set total FG Qty for which RM was transferred."
if not self.items:
self.transferred_qty = self.for_quantity if self.docstatus == 1 else 0
@@ -441,6 +459,7 @@ class JobCard(Document):
return
if self.items:
+ # sum of 'For Quantity' of Stock Entries against JC
self.transferred_qty = frappe.db.get_value('Stock Entry', {
'job_card': self.name,
'work_order': self.work_order,
@@ -484,7 +503,9 @@ class JobCard(Document):
self.status = 'Work In Progress'
if (self.docstatus == 1 and
- (self.for_quantity == self.transferred_qty or not self.items)):
+ (self.for_quantity <= self.transferred_qty or not self.items)):
+ # consider excess transfer
+ # completed qty is checked via separate validation
self.status = 'Completed'
if self.status != 'Completed':
@@ -602,7 +623,11 @@ def make_stock_entry(source_name, target_doc=None):
def set_missing_values(source, target):
target.purpose = "Material Transfer for Manufacture"
target.from_bom = 1
- target.fg_completed_qty = source.get('for_quantity', 0) - source.get('transferred_qty', 0)
+
+ # avoid negative 'For Quantity'
+ pending_fg_qty = source.get('for_quantity', 0) - source.get('transferred_qty', 0)
+ target.fg_completed_qty = pending_fg_qty if pending_fg_qty > 0 else 0
+
target.set_transfer_qty()
target.calculate_rate_and_amount()
target.set_missing_values()
diff --git a/erpnext/manufacturing/doctype/job_card/job_card_dashboard.py b/erpnext/manufacturing/doctype/job_card/job_card_dashboard.py
index c2aa2bd968a..3ec6697b9f4 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card_dashboard.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'job_card',
diff --git a/erpnext/manufacturing/doctype/job_card/test_job_card.js b/erpnext/manufacturing/doctype/job_card/test_job_card.js
deleted file mode 100644
index 5dc7805d226..00000000000
--- a/erpnext/manufacturing/doctype/job_card/test_job_card.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Job Card", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Job Card
- () => frappe.tests.make('Job Card', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/manufacturing/doctype/job_card/test_job_card.py b/erpnext/manufacturing/doctype/job_card/test_job_card.py
index 8fa0b27fcb8..57336e1b330 100644
--- a/erpnext/manufacturing/doctype/job_card/test_job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/test_job_card.py
@@ -1,75 +1,195 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
-from __future__ import unicode_literals
-
import unittest
+
import frappe
from frappe.utils import random_string
-from erpnext.manufacturing.doctype.workstation.test_workstation import make_workstation
+
+from erpnext.manufacturing.doctype.job_card.job_card import (
+ make_stock_entry as make_stock_entry_from_jc,
+ OperationMismatchError,
+ OverlapError
+)
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
-from erpnext.manufacturing.doctype.job_card.job_card import OperationMismatchError
+from erpnext.manufacturing.doctype.workstation.test_workstation import make_workstation
+from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+
class TestJobCard(unittest.TestCase):
+
+ def setUp(self):
+ transfer_material_against, source_warehouse = None, None
+ tests_that_transfer_against_jc = ("test_job_card_multiple_materials_transfer",
+ "test_job_card_excess_material_transfer")
+
+ if self._testMethodName in tests_that_transfer_against_jc:
+ transfer_material_against = "Job Card"
+ source_warehouse = "Stores - _TC"
+
+ self.work_order = make_wo_order_test_record(
+ item="_Test FG Item 2",
+ qty=2,
+ transfer_material_against=transfer_material_against,
+ source_warehouse=source_warehouse
+ )
+
+ def tearDown(self):
+ frappe.db.rollback()
+
def test_job_card(self):
- data = frappe.get_cached_value('BOM',
- {'docstatus': 1, 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item'])
- if data:
- bom, bom_item = data
+ job_cards = frappe.get_all('Job Card',
+ filters = {'work_order': self.work_order.name}, fields = ["operation_id", "name"])
- work_order = make_wo_order_test_record(item=bom_item, qty=1, bom_no=bom)
+ if job_cards:
+ job_card = job_cards[0]
+ frappe.db.set_value("Job Card", job_card.name, "operation_row_number", job_card.operation_id)
- job_cards = frappe.get_all('Job Card',
- filters = {'work_order': work_order.name}, fields = ["operation_id", "name"])
+ doc = frappe.get_doc("Job Card", job_card.name)
+ doc.operation_id = "Test Data"
+ self.assertRaises(OperationMismatchError, doc.save)
- if job_cards:
- job_card = job_cards[0]
- frappe.db.set_value("Job Card", job_card.name, "operation_row_number", job_card.operation_id)
-
- doc = frappe.get_doc("Job Card", job_card.name)
- doc.operation_id = "Test Data"
- self.assertRaises(OperationMismatchError, doc.save)
-
- for d in job_cards:
- frappe.delete_doc("Job Card", d.name)
+ for d in job_cards:
+ frappe.delete_doc("Job Card", d.name)
def test_job_card_with_different_work_station(self):
- data = frappe.get_cached_value('BOM',
- {'docstatus': 1, 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item'])
+ job_cards = frappe.get_all('Job Card',
+ filters = {'work_order': self.work_order.name},
+ fields = ["operation_id", "workstation", "name", "for_quantity"])
- if data:
- bom, bom_item = data
+ job_card = job_cards[0]
- work_order = make_wo_order_test_record(item=bom_item, qty=1, bom_no=bom)
+ if job_card:
+ workstation = frappe.db.get_value("Workstation",
+ {"name": ("not in", [job_card.workstation])}, "name")
- job_cards = frappe.get_all('Job Card',
- filters = {'work_order': work_order.name},
- fields = ["operation_id", "workstation", "name", "for_quantity"])
+ if not workstation or job_card.workstation == workstation:
+ workstation = make_workstation(workstation_name=random_string(5)).name
- job_card = job_cards[0]
+ doc = frappe.get_doc("Job Card", job_card.name)
+ doc.workstation = workstation
+ doc.append("time_logs", {
+ "from_time": "2009-01-01 12:06:25",
+ "to_time": "2009-01-01 12:37:25",
+ "time_in_mins": "31.00002",
+ "completed_qty": job_card.for_quantity
+ })
+ doc.submit()
- if job_card:
- workstation = frappe.db.get_value("Workstation",
- {"name": ("not in", [job_card.workstation])}, "name")
+ completed_qty = frappe.db.get_value("Work Order Operation", job_card.operation_id, "completed_qty")
+ self.assertEqual(completed_qty, job_card.for_quantity)
- if not workstation or job_card.workstation == workstation:
- workstation = make_workstation(workstation_name=random_string(5)).name
-
- doc = frappe.get_doc("Job Card", job_card.name)
- doc.workstation = workstation
- doc.append("time_logs", {
- "from_time": "2009-01-01 12:06:25",
- "to_time": "2009-01-01 12:37:25",
- "time_in_mins": "31.00002",
- "completed_qty": job_card.for_quantity
- })
- doc.submit()
-
- completed_qty = frappe.db.get_value("Work Order Operation", job_card.operation_id, "completed_qty")
- self.assertEqual(completed_qty, job_card.for_quantity)
-
- doc.cancel()
+ doc.cancel()
for d in job_cards:
frappe.delete_doc("Job Card", d.name)
+
+ def test_job_card_overlap(self):
+ wo2 = make_wo_order_test_record(item="_Test FG Item 2", qty=2)
+
+ jc1_name = frappe.db.get_value("Job Card", {'work_order': self.work_order.name})
+ jc2_name = frappe.db.get_value("Job Card", {'work_order': wo2.name})
+
+ jc1 = frappe.get_doc("Job Card", jc1_name)
+ jc2 = frappe.get_doc("Job Card", jc2_name)
+
+ employee = "_T-Employee-00001" # from test records
+
+ jc1.append("time_logs", {
+ "from_time": "2021-01-01 00:00:00",
+ "to_time": "2021-01-01 08:00:00",
+ "completed_qty": 1,
+ "employee": employee,
+ })
+ jc1.save()
+
+ # add a new entry in same time slice
+ jc2.append("time_logs", {
+ "from_time": "2021-01-01 00:01:00",
+ "to_time": "2021-01-01 06:00:00",
+ "completed_qty": 1,
+ "employee": employee,
+ })
+ self.assertRaises(OverlapError, jc2.save)
+
+ def test_job_card_multiple_materials_transfer(self):
+ "Test transferring RMs separately against Job Card with multiple RMs."
+ make_stock_entry(
+ item_code="_Test Item",
+ target="Stores - _TC",
+ qty=10,
+ basic_rate=100
+ )
+ make_stock_entry(
+ item_code="_Test Item Home Desktop Manufactured",
+ target="Stores - _TC",
+ qty=6,
+ basic_rate=100
+ )
+
+ job_card_name = frappe.db.get_value("Job Card", {'work_order': self.work_order.name})
+ job_card = frappe.get_doc("Job Card", job_card_name)
+
+ transfer_entry_1 = make_stock_entry_from_jc(job_card_name)
+ del transfer_entry_1.items[1] # transfer only 1 of 2 RMs
+ transfer_entry_1.insert()
+ transfer_entry_1.submit()
+
+ job_card.reload()
+
+ self.assertEqual(transfer_entry_1.fg_completed_qty, 2)
+ self.assertEqual(job_card.transferred_qty, 2)
+
+ # transfer second RM
+ transfer_entry_2 = make_stock_entry_from_jc(job_card_name)
+ del transfer_entry_2.items[0]
+ transfer_entry_2.insert()
+ transfer_entry_2.submit()
+
+ # 'For Quantity' here will be 0 since
+ # transfer was made for 2 fg qty in first transfer Stock Entry
+ self.assertEqual(transfer_entry_2.fg_completed_qty, 0)
+
+ def test_job_card_excess_material_transfer(self):
+ "Test transferring more than required RM against Job Card."
+ make_stock_entry(item_code="_Test Item", target="Stores - _TC",
+ qty=25, basic_rate=100)
+ make_stock_entry(item_code="_Test Item Home Desktop Manufactured",
+ target="Stores - _TC", qty=15, basic_rate=100)
+
+ job_card_name = frappe.db.get_value("Job Card", {'work_order': self.work_order.name})
+ job_card = frappe.get_doc("Job Card", job_card_name)
+
+ # fully transfer both RMs
+ transfer_entry_1 = make_stock_entry_from_jc(job_card_name)
+ transfer_entry_1.insert()
+ transfer_entry_1.submit()
+
+ # transfer extra qty of both RM due to previously damaged RM
+ transfer_entry_2 = make_stock_entry_from_jc(job_card_name)
+ # deliberately change 'For Quantity'
+ transfer_entry_2.fg_completed_qty = 1
+ transfer_entry_2.items[0].qty = 5
+ transfer_entry_2.items[1].qty = 3
+ transfer_entry_2.insert()
+ transfer_entry_2.submit()
+
+ job_card.reload()
+ self.assertGreater(job_card.transferred_qty, job_card.for_quantity)
+
+ # Check if 'For Quantity' is negative
+ # as 'transferred_qty' > Qty to Manufacture
+ transfer_entry_3 = make_stock_entry_from_jc(job_card_name)
+ self.assertEqual(transfer_entry_3.fg_completed_qty, 0)
+
+ job_card.append("time_logs", {
+ "from_time": "2021-01-01 00:01:00",
+ "to_time": "2021-01-01 06:00:00",
+ "completed_qty": 2
+ })
+ job_card.save()
+ job_card.submit()
+
+ # JC is Completed with excess transfer
+ self.assertEqual(job_card.status, "Completed")
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/job_card_item/job_card_item.py b/erpnext/manufacturing/doctype/job_card_item/job_card_item.py
index 373cba293e3..a1338364aa4 100644
--- a/erpnext/manufacturing/doctype/job_card_item/job_card_item.py
+++ b/erpnext/manufacturing/doctype/job_card_item/job_card_item.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class JobCardItem(Document):
pass
diff --git a/erpnext/manufacturing/doctype/job_card_operation/job_card_operation.py b/erpnext/manufacturing/doctype/job_card_operation/job_card_operation.py
index 85d72982ed3..43d14220649 100644
--- a/erpnext/manufacturing/doctype/job_card_operation/job_card_operation.py
+++ b/erpnext/manufacturing/doctype/job_card_operation/job_card_operation.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class JobCardOperation(Document):
pass
diff --git a/erpnext/manufacturing/doctype/job_card_scrap_item/__init__.py b/erpnext/manufacturing/doctype/job_card_scrap_item/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/manufacturing/doctype/job_card_scrap_item/job_card_scrap_item.json b/erpnext/manufacturing/doctype/job_card_scrap_item/job_card_scrap_item.json
new file mode 100644
index 00000000000..9e9f1c4c89f
--- /dev/null
+++ b/erpnext/manufacturing/doctype/job_card_scrap_item/job_card_scrap_item.json
@@ -0,0 +1,82 @@
+{
+ "actions": [],
+ "creation": "2021-09-14 00:30:28.533884",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "item_code",
+ "item_name",
+ "column_break_3",
+ "description",
+ "quantity_and_rate",
+ "stock_qty",
+ "column_break_6",
+ "stock_uom"
+ ],
+ "fields": [
+ {
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Scrap Item Code",
+ "options": "Item",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "item_code.item_name",
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Scrap Item Name"
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fetch_from": "item_code.description",
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Description",
+ "read_only": 1
+ },
+ {
+ "fieldname": "quantity_and_rate",
+ "fieldtype": "Section Break",
+ "label": "Quantity and Rate"
+ },
+ {
+ "fieldname": "stock_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Qty",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_6",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fetch_from": "item_code.stock_uom",
+ "fieldname": "stock_uom",
+ "fieldtype": "Link",
+ "label": "Stock UOM",
+ "options": "UOM",
+ "read_only": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-09-14 01:20:48.588052",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Job Card Scrap Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/job_card_scrap_item/job_card_scrap_item.py b/erpnext/manufacturing/doctype/job_card_scrap_item/job_card_scrap_item.py
new file mode 100644
index 00000000000..372df1b0fad
--- /dev/null
+++ b/erpnext/manufacturing/doctype/job_card_scrap_item/job_card_scrap_item.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from frappe.model.document import Document
+
+
+class JobCardScrapItem(Document):
+ pass
diff --git a/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.py b/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.py
index 3dc66891216..ed27e7ff824 100644
--- a/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.py
+++ b/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class JobCardTimeLog(Document):
pass
diff --git a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json
index 024f7847259..01647d56c91 100644
--- a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json
+++ b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json
@@ -25,9 +25,12 @@
"overproduction_percentage_for_sales_order",
"column_break_16",
"overproduction_percentage_for_work_order",
+ "job_card_section",
+ "add_corrective_operation_cost_in_finished_good_valuation",
+ "column_break_24",
+ "job_card_excess_transfer",
"other_settings_section",
"update_bom_costs_automatically",
- "add_corrective_operation_cost_in_finished_good_valuation",
"column_break_23",
"make_serial_no_batch_from_work_order"
],
@@ -96,10 +99,10 @@
},
{
"default": "0",
- "description": "Allow multiple material consumptions against a Work Order",
+ "description": "Allow material consumptions without immediately manufacturing finished goods against a Work Order",
"fieldname": "material_consumption",
"fieldtype": "Check",
- "label": "Allow Multiple Material Consumption"
+ "label": "Allow Continuous Material Consumption"
},
{
"default": "0",
@@ -175,13 +178,29 @@
"fieldname": "add_corrective_operation_cost_in_finished_good_valuation",
"fieldtype": "Check",
"label": "Add Corrective Operation Cost in Finished Good Valuation"
+ },
+ {
+ "fieldname": "job_card_section",
+ "fieldtype": "Section Break",
+ "label": "Job Card"
+ },
+ {
+ "fieldname": "column_break_24",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "description": "Allow transferring raw materials even after the Required Quantity is fulfilled",
+ "fieldname": "job_card_excess_transfer",
+ "fieldtype": "Check",
+ "label": "Allow Excess Material Transfer"
}
],
"icon": "icon-wrench",
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-03-16 15:54:38.967341",
+ "modified": "2021-09-13 22:09:09.401559",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Manufacturing Settings",
diff --git a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py
index 149fe3e22b8..18d78b59f53 100644
--- a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py
+++ b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py
@@ -2,10 +2,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
+from dateutil.relativedelta import relativedelta
from frappe.model.document import Document
from frappe.utils import cint
-from dateutil.relativedelta import relativedelta
+
class ManufacturingSettings(Document):
pass
diff --git a/erpnext/manufacturing/doctype/manufacturing_settings/test_manufacturing_settings.js b/erpnext/manufacturing/doctype/manufacturing_settings/test_manufacturing_settings.js
deleted file mode 100644
index 2b2589eddd8..00000000000
--- a/erpnext/manufacturing/doctype/manufacturing_settings/test_manufacturing_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* 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()
- ]);
-
-});
diff --git a/erpnext/manufacturing/doctype/manufacturing_settings/test_manufacturing_settings.py b/erpnext/manufacturing/doctype/manufacturing_settings/test_manufacturing_settings.py
index 7391f65dec9..fd0ac725914 100644
--- a/erpnext/manufacturing/doctype/manufacturing_settings/test_manufacturing_settings.py
+++ b/erpnext/manufacturing/doctype/manufacturing_settings/test_manufacturing_settings.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestManufacturingSettings(unittest.TestCase):
pass
diff --git a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
index 6c60bbde86c..27d7c4175e5 100644
--- a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
+++ b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
@@ -6,17 +6,17 @@
"engine": "InnoDB",
"field_order": [
"item_code",
- "item_name",
- "material_request_type",
"from_warehouse",
"warehouse",
- "column_break_4",
+ "item_name",
+ "material_request_type",
+ "actual_qty",
+ "ordered_qty",
"required_bom_qty",
+ "column_break_4",
"quantity",
"uom",
"projected_qty",
- "actual_qty",
- "ordered_qty",
"reserved_qty_for_production",
"safety_stock",
"item_details",
@@ -28,6 +28,7 @@
],
"fields": [
{
+ "columns": 2,
"fieldname": "item_code",
"fieldtype": "Link",
"in_list_view": 1,
@@ -41,6 +42,7 @@
"label": "Item Name"
},
{
+ "columns": 2,
"fieldname": "warehouse",
"fieldtype": "Link",
"in_list_view": 1,
@@ -50,10 +52,11 @@
"reqd": 1
},
{
+ "columns": 1,
"fieldname": "material_request_type",
"fieldtype": "Select",
"in_list_view": 1,
- "label": "Material Request Type",
+ "label": "Type",
"options": "\nPurchase\nMaterial Transfer\nMaterial Issue\nManufacture\nCustomer Provided"
},
{
@@ -61,10 +64,11 @@
"fieldtype": "Column Break"
},
{
+ "columns": 1,
"fieldname": "quantity",
"fieldtype": "Float",
"in_list_view": 1,
- "label": "Required Quantity",
+ "label": "Plan to Request Qty",
"no_copy": 1,
"reqd": 1
},
@@ -75,11 +79,12 @@
"read_only": 1
},
{
+ "columns": 2,
"default": "0",
"fieldname": "actual_qty",
"fieldtype": "Float",
"in_list_view": 1,
- "label": "Actual Qty",
+ "label": "Available Qty",
"no_copy": 1,
"read_only": 1
},
@@ -157,16 +162,18 @@
"read_only": 1
},
{
+ "columns": 2,
"fieldname": "required_bom_qty",
"fieldtype": "Float",
- "label": "Required Qty as per BOM",
+ "in_list_view": 1,
+ "label": "Qty As Per BOM",
"no_copy": 1,
"read_only": 1
}
],
"istable": 1,
"links": [],
- "modified": "2021-03-26 12:41:13.013149",
+ "modified": "2021-08-23 18:17:58.400462",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Material Request Plan Item",
diff --git a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.py b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.py
index 73e369c149e..bc26644067f 100644
--- a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.py
+++ b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class MaterialRequestPlanItem(Document):
pass
diff --git a/erpnext/manufacturing/doctype/material_request_plan_item/test_material_request_plan_item.js b/erpnext/manufacturing/doctype/material_request_plan_item/test_material_request_plan_item.js
deleted file mode 100644
index 14c6e393847..00000000000
--- a/erpnext/manufacturing/doctype/material_request_plan_item/test_material_request_plan_item.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Material Request Plan Item", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Material Request Plan Item
- () => frappe.tests.make('Material Request Plan Item', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/manufacturing/doctype/material_request_plan_item/test_material_request_plan_item.py b/erpnext/manufacturing/doctype/material_request_plan_item/test_material_request_plan_item.py
index dc43b69ef24..2675af94a72 100644
--- a/erpnext/manufacturing/doctype/material_request_plan_item/test_material_request_plan_item.py
+++ b/erpnext/manufacturing/doctype/material_request_plan_item/test_material_request_plan_item.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestMaterialRequestPlanItem(unittest.TestCase):
pass
diff --git a/erpnext/manufacturing/doctype/operation/operation.py b/erpnext/manufacturing/doctype/operation/operation.py
index 374f32019bd..2926f911ea1 100644
--- a/erpnext/manufacturing/doctype/operation/operation.py
+++ b/erpnext/manufacturing/doctype/operation/operation.py
@@ -7,6 +7,7 @@ import frappe
from frappe import _
from frappe.model.document import Document
+
class Operation(Document):
def validate(self):
if not self.description:
diff --git a/erpnext/manufacturing/doctype/operation/operation_dashboard.py b/erpnext/manufacturing/doctype/operation/operation_dashboard.py
index 8deb9ec6e0b..284fd9dfc2f 100644
--- a/erpnext/manufacturing/doctype/operation/operation_dashboard.py
+++ b/erpnext/manufacturing/doctype/operation/operation_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'operation',
diff --git a/erpnext/manufacturing/doctype/operation/test_operation.py b/erpnext/manufacturing/doctype/operation/test_operation.py
index 8e7e7237263..2b24118fc41 100644
--- a/erpnext/manufacturing/doctype/operation/test_operation.py
+++ b/erpnext/manufacturing/doctype/operation/test_operation.py
@@ -2,9 +2,10 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
test_records = frappe.get_test_records('Operation')
class TestOperation(unittest.TestCase):
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js
index d198a6962a5..4343e8a24eb 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.js
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js
@@ -254,7 +254,7 @@ frappe.ui.form.on('Production Plan', {
get_items_for_mr: function(frm) {
if (!frm.doc.for_warehouse) {
- frappe.throw(__("Select warehouse for material requests"));
+ frappe.throw(__("To make material requests, 'Make Material Request for Warehouse' field is mandatory"));
}
if (frm.doc.ignore_existing_ordered_qty) {
@@ -265,9 +265,18 @@ frappe.ui.form.on('Production Plan', {
title: title,
fields: [
{
- "fieldtype": "Table MultiSelect", "label": __("Source Warehouses (Optional)"),
- "fieldname": "warehouses", "options": "Production Plan Material Request Warehouse",
- "description": __("System will pickup the materials from the selected warehouses. If not specified, system will create material request for purchase."),
+ 'label': __('Target Warehouse'),
+ 'fieldtype': 'Link',
+ 'fieldname': 'target_warehouse',
+ 'read_only': true,
+ 'default': frm.doc.for_warehouse
+ },
+ {
+ 'label': __('Source Warehouses (Optional)'),
+ 'fieldtype': 'Table MultiSelect',
+ 'fieldname': 'warehouses',
+ 'options': 'Production Plan Material Request Warehouse',
+ 'description': __('If source warehouse selected then system will create the material request with type Material Transfer from Source to Target warehouse. If not selected then will create the material request with type Purchase for the target warehouse.'),
get_query: function () {
return {
filters: {
@@ -342,7 +351,11 @@ frappe.ui.form.on('Production Plan', {
frappe.prompt(fields, (row) => {
let get_template_url = 'erpnext.manufacturing.doctype.production_plan.production_plan.download_raw_materials';
- open_url_post(frappe.request.url, { cmd: get_template_url, doc: frm.doc, warehouses: row.warehouses });
+ open_url_post(frappe.request.url, {
+ cmd: get_template_url,
+ doc: frm.doc,
+ warehouses: row.warehouses
+ });
}, __('Select Warehouses to get Stock for Materials Planning'), __('Get Stock'));
},
@@ -421,6 +434,25 @@ frappe.ui.form.on("Material Request Plan Item", {
}
});
+frappe.ui.form.on("Production Plan Sales Order", {
+ sales_order(frm, cdt, cdn) {
+ const { sales_order } = locals[cdt][cdn];
+ if (!sales_order) {
+ return;
+ }
+ frappe.call({
+ method: "erpnext.manufacturing.doctype.production_plan.production_plan.get_so_details",
+ args: { sales_order },
+ callback(r) {
+ const {transaction_date, customer, grand_total} = r.message;
+ frappe.model.set_value(cdt, cdn, 'sales_order_date', transaction_date);
+ frappe.model.set_value(cdt, cdn, 'customer', customer);
+ frappe.model.set_value(cdt, cdn, 'grand_total', grand_total);
+ }
+ });
+ }
+});
+
cur_frm.fields_dict['sales_orders'].grid.get_field("sales_order").get_query = function() {
return{
filters: [
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json
index 84378956c61..56cf2b4f08a 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.json
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json
@@ -16,10 +16,12 @@
"customer",
"warehouse",
"project",
+ "sales_order_status",
"column_break2",
"from_date",
"to_date",
- "sales_order_status",
+ "from_delivery_date",
+ "to_delivery_date",
"sales_orders_detail",
"get_sales_orders",
"sales_orders",
@@ -300,7 +302,7 @@
{
"fieldname": "for_warehouse",
"fieldtype": "Link",
- "label": "Material Request Warehouse",
+ "label": "Make Material Request for Warehouse",
"options": "Warehouse"
},
{
@@ -358,13 +360,23 @@
"fieldname": "get_sub_assembly_items",
"fieldtype": "Button",
"label": "Get Sub Assembly Items"
+ },
+ {
+ "fieldname": "from_delivery_date",
+ "fieldtype": "Date",
+ "label": "From Delivery Date"
+ },
+ {
+ "fieldname": "to_delivery_date",
+ "fieldtype": "Date",
+ "label": "To Delivery Date"
}
],
"icon": "fa fa-calendar",
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-28 20:00:33.905114",
+ "modified": "2021-09-06 18:35:59.642232",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Plan",
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index b4c663507ce..a28fc7abf0e 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -3,18 +3,32 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, json, copy
-from frappe import msgprint, _
+
+import copy
+import json
+
+import frappe
+from frappe import _, msgprint
+from frappe.model.document import Document
+from frappe.utils import (
+ add_days,
+ ceil,
+ cint,
+ comma_and,
+ flt,
+ get_link_to_form,
+ getdate,
+ now_datetime,
+ nowdate,
+)
+from frappe.utils.csvutils import build_csv_response
from six import iteritems
-from frappe.model.document import Document
-from frappe.utils import (flt, cint, nowdate, add_days, comma_and, now_datetime,
- ceil, get_link_to_form, getdate)
-from frappe.utils.csvutils import build_csv_response
-from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, get_children
+from erpnext.manufacturing.doctype.bom.bom import get_children, validate_bom_no
from erpnext.manufacturing.doctype.work_order.work_order import get_item_details
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
+
class ProductionPlan(Document):
def validate(self):
self.calculate_total_planned_qty()
@@ -213,7 +227,6 @@ class ProductionPlan(Document):
})
pi = self.append('po_items', {
- 'include_exploded_items': 1,
'warehouse': data.warehouse,
'item_code': data.item_code,
'description': data.description or item_details.description,
@@ -224,6 +237,7 @@ class ProductionPlan(Document):
'planned_start_date': now_datetime(),
'product_bundle_item': data.parent_item
})
+ pi._set_defaults()
if self.get_items_from == "Sales Order":
pi.sales_order = data.parent
@@ -331,7 +345,7 @@ class ProductionPlan(Document):
def get_production_items(self):
item_dict = {}
for d in self.po_items:
- item_details= {
+ item_details = {
"production_item" : d.item_code,
"use_multi_level_bom" : d.include_exploded_items,
"sales_order" : d.sales_order,
@@ -346,8 +360,7 @@ class ProductionPlan(Document):
"production_plan" : self.name,
"production_plan_item" : d.name,
"product_bundle_item" : d.product_bundle_item,
- "planned_start_date" : d.planned_start_date,
- "make_work_order_for_sub_assembly_items": d.get("make_work_order_for_sub_assembly_items", 0)
+ "planned_start_date" : d.planned_start_date
}
item_details.update({
@@ -454,10 +467,14 @@ class ProductionPlan(Document):
})
def create_work_order(self, item):
- from erpnext.manufacturing.doctype.work_order.work_order import OverProductionError, get_default_warehouse
+ from erpnext.manufacturing.doctype.work_order.work_order import (
+ OverProductionError,
+ get_default_warehouse,
+ )
warehouse = get_default_warehouse()
wo = frappe.new_doc("Work Order")
wo.update(item)
+ wo.planned_start_date = item.get('planned_start_date') or item.get('schedule_date')
if item.get("warehouse"):
wo.fg_warehouse = item.get("warehouse")
@@ -569,7 +586,10 @@ def download_raw_materials(doc, warehouses=None):
'Reserved Qty for Production', 'Safety Stock', 'Required Qty']]
doc.warehouse = None
- for d in get_items_for_material_requests(doc, warehouses=warehouses, get_parent_warehouse_data=True):
+ frappe.flags.show_qty_in_stock_uom = 1
+ items = get_items_for_material_requests(doc, warehouses=warehouses, get_parent_warehouse_data=True)
+
+ for d in items:
item_list.append([d.get('item_code'), d.get('description'), d.get('stock_uom'), d.get('warehouse'),
d.get('required_bom_qty'), d.get('projected_qty'), d.get('actual_qty'), d.get('ordered_qty'),
d.get('planned_qty'), d.get('reserved_qty_for_production'), d.get('safety_stock'), d.get('quantity')])
@@ -605,9 +625,16 @@ def get_exploded_items(item_details, company, bom_no, include_non_stock_items, p
and bom.name=%s and item.is_stock_item in (1, {0})
group by bei.item_code, bei.stock_uom""".format(0 if include_non_stock_items else 1),
(planned_qty, company, bom_no), as_dict=1):
- item_details.setdefault(d.get('item_code'), d)
+ if not d.conversion_factor and d.purchase_uom:
+ d.conversion_factor = get_uom_conversion_factor(d.item_code, d.purchase_uom)
+ item_details.setdefault(d.get('item_code'), d)
+
return item_details
+def get_uom_conversion_factor(item_code, uom):
+ return frappe.db.get_value('UOM Conversion Detail',
+ {'parent': item_code, 'uom': uom}, 'conversion_factor')
+
def get_subitems(doc, data, item_details, bom_no, company, include_non_stock_items,
include_subcontracted_items, parent_qty, planned_qty=1):
items = frappe.db.sql("""
@@ -642,6 +669,9 @@ def get_subitems(doc, data, item_details, bom_no, company, include_non_stock_ite
if d.item_code in item_details:
item_details[d.item_code].qty = item_details[d.item_code].qty + d.qty
else:
+ if not d.conversion_factor and d.purchase_uom:
+ d.conversion_factor = get_uom_conversion_factor(d.item_code, d.purchase_uom)
+
item_details[d.item_code] = d
if data.get('include_exploded_items') and d.default_bom:
@@ -669,10 +699,11 @@ def get_material_request_items(row, sales_order, company,
row['purchase_uom'] = row['stock_uom']
if row['purchase_uom'] != row['stock_uom']:
- if not row['conversion_factor']:
+ if not (row['conversion_factor'] or frappe.flags.show_qty_in_stock_uom):
frappe.throw(_("UOM Conversion factor ({0} -> {1}) not found for item: {2}")
.format(row['purchase_uom'], row['stock_uom'], row.item_code))
- required_qty = required_qty / row['conversion_factor']
+
+ required_qty = required_qty / row['conversion_factor']
if frappe.db.get_value("UOM", row['purchase_uom'], "must_be_whole_number"):
required_qty = ceil(required_qty)
@@ -704,43 +735,42 @@ def get_material_request_items(row, sales_order, company,
def get_sales_orders(self):
so_filter = item_filter = ""
bom_item = "bom.item = so_item.item_code"
- if self.from_date:
- so_filter += " and so.transaction_date >= %(from_date)s"
- if self.to_date:
- so_filter += " and so.transaction_date <= %(to_date)s"
- if self.customer:
- so_filter += " and so.customer = %(customer)s"
- if self.project:
- so_filter += " and so.project = %(project)s"
- if self.sales_order_status:
- so_filter += "and so.status = %(sales_order_status)s"
+
+ date_field_mapper = {
+ 'from_date': ('>=', 'so.transaction_date'),
+ 'to_date': ('<=', 'so.transaction_date'),
+ 'from_delivery_date': ('>=', 'so_item.delivery_date'),
+ 'to_delivery_date': ('<=', 'so_item.delivery_date')
+ }
+
+ for field, value in date_field_mapper.items():
+ if self.get(field):
+ so_filter += f" and {value[1]} {value[0]} %({field})s"
+
+ for field in ['customer', 'project', 'sales_order_status']:
+ if self.get(field):
+ so_field = 'status' if field == 'sales_order_status' else field
+ so_filter += f" and so.{so_field} = %({field})s"
if self.item_code and frappe.db.exists('Item', self.item_code):
bom_item = self.get_bom_item() or bom_item
- item_filter += " and so_item.item_code = %(item)s"
+ item_filter += " and so_item.item_code = %(item_code)s"
- open_so = frappe.db.sql("""
+ open_so = frappe.db.sql(f"""
select distinct so.name, so.transaction_date, so.customer, so.base_grand_total
from `tabSales Order` so, `tabSales Order Item` so_item
where so_item.parent = so.name
and so.docstatus = 1 and so.status not in ("Stopped", "Closed")
and so.company = %(company)s
- and so_item.qty > so_item.work_order_qty {0} {1}
- and (exists (select name from `tabBOM` bom where {2}
+ and so_item.qty > so_item.work_order_qty {so_filter} {item_filter}
+ and (exists (select name from `tabBOM` bom where {bom_item}
and bom.is_active = 1)
or exists (select name from `tabPacked Item` pi
where pi.parent = so.name and pi.parent_item = so_item.item_code
and exists (select name from `tabBOM` bom where bom.item=pi.item_code
and bom.is_active = 1)))
- """.format(so_filter, item_filter, bom_item), {
- "from_date": self.from_date,
- "to_date": self.to_date,
- "customer": self.customer,
- "project": self.project,
- "item": self.item_code,
- "company": self.company,
- "sales_order_status": self.sales_order_status
- }, as_dict=1)
+ """, self.as_dict(), as_dict=1)
+
return open_so
@frappe.whitelist()
@@ -769,6 +799,12 @@ def get_bin_details(row, company, for_warehouse=None, all_warehouse=False):
group by item_code, warehouse
""".format(conditions=conditions), { "item_code": row['item_code'] }, as_dict=1)
+@frappe.whitelist()
+def get_so_details(sales_order):
+ return frappe.db.get_value("Sales Order", sales_order,
+ ['transaction_date', 'customer', 'grand_total'], as_dict=1
+ )
+
def get_warehouse_list(warehouses):
warehouse_list = []
@@ -841,10 +877,8 @@ def get_items_for_material_requests(doc, warehouses=None, get_parent_warehouse_d
elif data.get('item_code'):
item_master = frappe.get_doc('Item', data['item_code']).as_dict()
purchase_uom = item_master.purchase_uom or item_master.stock_uom
- conversion_factor = 0
- for d in item_master.get("uoms"):
- if d.uom == purchase_uom:
- conversion_factor = d.conversion_factor
+ conversion_factor = (get_uom_conversion_factor(item_master.name, purchase_uom)
+ if item_master.purchase_uom else 1.0)
item_details[item_master.name] = frappe._dict(
{
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py b/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py
index 52a56af7bce..b4bc3467e46 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'production_plan',
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan_list.js b/erpnext/manufacturing/doctype/production_plan/production_plan_list.js
index c2e3e6d7124..8f946866247 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan_list.js
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan_list.js
@@ -1,4 +1,5 @@
frappe.listview_settings['Production Plan'] = {
+ hide_name_column: true,
add_fields: ["status"],
filters: [["status", "!=", "Closed"]],
get_indicator: function (doc) {
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.js b/erpnext/manufacturing/doctype/production_plan/test_production_plan.js
deleted file mode 100644
index ef7d64c92da..00000000000
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Production Plan", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Production Plan
- () => frappe.tests.make('Production Plan', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index a5b9ff845fc..707b3f62d4e 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -3,15 +3,23 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import nowdate, now_datetime, flt, add_to_date
-from erpnext.stock.doctype.item.test_item import create_item
-from erpnext.manufacturing.doctype.production_plan.production_plan import get_sales_orders
-from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
-from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
-from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests, get_warehouse_list
+
+import frappe
+from frappe.utils import add_to_date, flt, now_datetime, nowdate
+
from erpnext.controllers.item_variant import create_variant
+from erpnext.manufacturing.doctype.production_plan.production_plan import (
+ get_items_for_material_requests,
+ get_sales_orders,
+ get_warehouse_list,
+)
+from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
+from erpnext.stock.doctype.item.test_item import create_item
+from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
+ create_stock_reconciliation,
+)
+
class TestProductionPlan(unittest.TestCase):
def setUp(self):
@@ -288,6 +296,7 @@ class TestProductionPlan(unittest.TestCase):
self.assertEqual(warehouses, expected_warehouses)
def test_get_sales_order_with_variant(self):
+ rm_item = create_item('PIV_RM', valuation_rate = 100)
if not frappe.db.exists('Item', {"item_code": 'PIV'}):
item = create_item('PIV', valuation_rate = 100)
variant_settings = {
@@ -300,20 +309,20 @@ class TestProductionPlan(unittest.TestCase):
}
item.update(variant_settings)
item.save()
- parent_bom = make_bom(item = 'PIV', raw_materials = ['PIV'])
+ parent_bom = make_bom(item = 'PIV', raw_materials = [rm_item.item_code])
if not frappe.db.exists('BOM', {"item": 'PIV'}):
- parent_bom = make_bom(item = 'PIV', raw_materials = ['PIV'])
+ parent_bom = make_bom(item = 'PIV', raw_materials = [rm_item.item_code])
else:
parent_bom = frappe.get_doc('BOM', {"item": 'PIV'})
if not frappe.db.exists('Item', {"item_code": 'PIV-RED'}):
variant = create_variant("PIV", {"Colour": "Red"})
variant.save()
- variant_bom = make_bom(item = variant.item_code, raw_materials = [variant.item_code])
+ variant_bom = make_bom(item = variant.item_code, raw_materials = [rm_item.item_code])
else:
variant = frappe.get_doc('Item', 'PIV-RED')
if not frappe.db.exists('BOM', {"item": 'PIV-RED'}):
- variant_bom = make_bom(item = variant.item_code, raw_materials = [variant.item_code])
+ variant_bom = make_bom(item = variant.item_code, raw_materials = [rm_item.item_code])
"""Testing when item variant has a BOM"""
so = make_sales_order(item_code="PIV-RED", qty=5)
@@ -395,6 +404,7 @@ def make_bom(**args):
'uom': item_doc.stock_uom,
'stock_uom': item_doc.stock_uom,
'rate': item_doc.valuation_rate or args.rate,
+ 'source_warehouse': args.source_warehouse
})
if not args.do_not_save:
diff --git a/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.py b/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.py
index 37cf5a49dc9..24029d8f2ce 100644
--- a/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.py
+++ b/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class ProductionPlanItem(Document):
pass
diff --git a/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.py b/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.py
index 51fbc3633b1..9d25d6fc20f 100644
--- a/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.py
+++ b/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ProductionPlanItemReference(Document):
pass
diff --git a/erpnext/manufacturing/doctype/production_plan_material_request/production_plan_material_request.py b/erpnext/manufacturing/doctype/production_plan_material_request/production_plan_material_request.py
index 44786f8388d..d1d935c955b 100644
--- a/erpnext/manufacturing/doctype/production_plan_material_request/production_plan_material_request.py
+++ b/erpnext/manufacturing/doctype/production_plan_material_request/production_plan_material_request.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ProductionPlanMaterialRequest(Document):
pass
diff --git a/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/production_plan_material_request_warehouse.py b/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/production_plan_material_request_warehouse.py
index f605985ae96..1548bd7b88a 100644
--- a/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/production_plan_material_request_warehouse.py
+++ b/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/production_plan_material_request_warehouse.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ProductionPlanMaterialRequestWarehouse(Document):
pass
diff --git a/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/test_production_plan_material_request_warehouse.py b/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/test_production_plan_material_request_warehouse.py
index ecab5fbae12..905252da604 100644
--- a/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/test_production_plan_material_request_warehouse.py
+++ b/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/test_production_plan_material_request_warehouse.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestProductionPlanMaterialRequestWarehouse(unittest.TestCase):
pass
diff --git a/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.py b/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.py
index 99c7273a640..ea53a986964 100644
--- a/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.py
+++ b/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class ProductionPlanSalesOrder(Document):
pass
diff --git a/erpnext/manufacturing/doctype/production_plan_sub_assembly_item/production_plan_sub_assembly_item.py b/erpnext/manufacturing/doctype/production_plan_sub_assembly_item/production_plan_sub_assembly_item.py
index 6850a2eb4ed..be0ed1b96a8 100644
--- a/erpnext/manufacturing/doctype/production_plan_sub_assembly_item/production_plan_sub_assembly_item.py
+++ b/erpnext/manufacturing/doctype/production_plan_sub_assembly_item/production_plan_sub_assembly_item.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ProductionPlanSubAssemblyItem(Document):
pass
diff --git a/erpnext/manufacturing/doctype/routing/routing.py b/erpnext/manufacturing/doctype/routing/routing.py
index ece0db717a2..20fb370d942 100644
--- a/erpnext/manufacturing/doctype/routing/routing.py
+++ b/erpnext/manufacturing/doctype/routing/routing.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import cint, flt
from frappe import _
from frappe.model.document import Document
+from frappe.utils import cint, flt
+
class Routing(Document):
def validate(self):
diff --git a/erpnext/manufacturing/doctype/routing/routing_dashboard.py b/erpnext/manufacturing/doctype/routing/routing_dashboard.py
index 50a3fe62da5..9ef6ee57523 100644
--- a/erpnext/manufacturing/doctype/routing/routing_dashboard.py
+++ b/erpnext/manufacturing/doctype/routing/routing_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/manufacturing/doctype/routing/test_routing.js b/erpnext/manufacturing/doctype/routing/test_routing.js
deleted file mode 100644
index 6cb65494af2..00000000000
--- a/erpnext/manufacturing/doctype/routing/test_routing.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Routing", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Routing
- () => frappe.tests.make('Routing', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/manufacturing/doctype/routing/test_routing.py b/erpnext/manufacturing/doctype/routing/test_routing.py
index 92f26946ab7..b84b2ba1e6d 100644
--- a/erpnext/manufacturing/doctype/routing/test_routing.py
+++ b/erpnext/manufacturing/doctype/routing/test_routing.py
@@ -4,11 +4,14 @@
from __future__ import unicode_literals
import unittest
+
import frappe
from frappe.test_runner import make_test_records
-from erpnext.stock.doctype.item.test_item import make_item
+
from erpnext.manufacturing.doctype.job_card.job_card import OperationSequenceError
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
+from erpnext.stock.doctype.item.test_item import make_item
+
class TestRouting(unittest.TestCase):
@classmethod
@@ -91,8 +94,8 @@ class TestRouting(unittest.TestCase):
def setup_operations(rows):
- from erpnext.manufacturing.doctype.workstation.test_workstation import make_workstation
from erpnext.manufacturing.doctype.operation.test_operation import make_operation
+ from erpnext.manufacturing.doctype.workstation.test_workstation import make_workstation
for row in rows:
make_workstation(row)
make_operation(row)
diff --git a/erpnext/manufacturing/doctype/sub_operation/sub_operation.py b/erpnext/manufacturing/doctype/sub_operation/sub_operation.py
index f4b27758e9d..37b64f23d29 100644
--- a/erpnext/manufacturing/doctype/sub_operation/sub_operation.py
+++ b/erpnext/manufacturing/doctype/sub_operation/sub_operation.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class SubOperation(Document):
pass
diff --git a/erpnext/manufacturing/doctype/sub_operation/test_sub_operation.py b/erpnext/manufacturing/doctype/sub_operation/test_sub_operation.py
index d3410ca3120..c5749dbc962 100644
--- a/erpnext/manufacturing/doctype/sub_operation/test_sub_operation.py
+++ b/erpnext/manufacturing/doctype/sub_operation/test_sub_operation.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestSubOperation(unittest.TestCase):
pass
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index 3a334a530cd..85b5bfb9bfc 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -1,20 +1,26 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-
-
-from __future__ import unicode_literals
import unittest
+
import frappe
-from frappe.utils import flt, now, add_months, cint, today, add_to_date
-from erpnext.manufacturing.doctype.work_order.work_order import (make_stock_entry,
- ItemHasVariantError, stop_unstop, StockOverProductionError, OverProductionError, CapacityError)
-from erpnext.stock.doctype.stock_entry import test_stock_entry
-from erpnext.stock.utils import get_bin
-from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
-from erpnext.stock.doctype.item.test_item import make_item
-from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
-from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
+from frappe.utils import add_months, cint, flt, now, today
+
from erpnext.manufacturing.doctype.job_card.job_card import JobCardCancelError
+from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
+from erpnext.manufacturing.doctype.work_order.work_order import (
+ CapacityError,
+ ItemHasVariantError,
+ OverProductionError,
+ StockOverProductionError,
+ make_stock_entry,
+ stop_unstop,
+)
+from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
+from erpnext.stock.doctype.item.test_item import create_item, make_item
+from erpnext.stock.doctype.stock_entry import test_stock_entry
+from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
+from erpnext.stock.utils import get_bin
+
class TestWorkOrder(unittest.TestCase):
def setUp(self):
@@ -675,13 +681,18 @@ class TestWorkOrder(unittest.TestCase):
def test_valuation_rate_missing_on_make_stock_entry(self):
item_name = 'Test Valuation Rate Missing'
+ rm_item = '_Test raw material item'
make_item(item_name, {
"is_stock_item": 1,
"include_item_in_manufacturing": 1,
})
+ make_item('_Test raw material item', {
+ "is_stock_item": 1,
+ "include_item_in_manufacturing": 1,
+ })
if not frappe.db.get_value('BOM', {'item': item_name}):
- make_bom(item=item_name, raw_materials=[item_name], rm_qty=1)
+ make_bom(item=item_name, raw_materials=[rm_item], rm_qty=1)
company = "_Test Company with perpetual inventory"
source_warehouse = create_warehouse("Test Valuation Rate Missing Warehouse", company=company)
@@ -691,8 +702,10 @@ class TestWorkOrder(unittest.TestCase):
self.assertRaises(frappe.ValidationError, make_stock_entry, wo.name, 'Material Transfer for Manufacture')
def test_wo_completion_with_pl_bom(self):
- from erpnext.manufacturing.doctype.bom.test_bom import create_process_loss_bom_items
- from erpnext.manufacturing.doctype.bom.test_bom import create_bom_with_process_loss_item
+ from erpnext.manufacturing.doctype.bom.test_bom import (
+ create_bom_with_process_loss_item,
+ create_process_loss_bom_items,
+ )
qty = 4
scrap_qty = 0.25 # bom item qty = 1, consider as 25% of FG
@@ -755,6 +768,60 @@ class TestWorkOrder(unittest.TestCase):
total_pl_qty
)
+ def test_job_card_scrap_item(self):
+ items = ['Test FG Item for Scrap Item Test', 'Test RM Item 1 for Scrap Item Test',
+ 'Test RM Item 2 for Scrap Item Test']
+
+ company = '_Test Company with perpetual inventory'
+ for item_code in items:
+ create_item(item_code = item_code, is_stock_item = 1,
+ is_purchase_item=1, opening_stock=100, valuation_rate=10, company=company, warehouse='Stores - TCP1')
+
+ item = 'Test FG Item for Scrap Item Test'
+ raw_materials = ['Test RM Item 1 for Scrap Item Test', 'Test RM Item 2 for Scrap Item Test']
+ if not frappe.db.get_value('BOM', {'item': item}):
+ bom = make_bom(item=item, source_warehouse='Stores - TCP1', raw_materials=raw_materials, do_not_save=True)
+ bom.with_operations = 1
+ bom.append('operations', {
+ 'operation': '_Test Operation 1',
+ 'workstation': '_Test Workstation 1',
+ 'hour_rate': 20,
+ 'time_in_mins': 60
+ })
+
+ bom.submit()
+
+ wo_order = make_wo_order_test_record(item=item, company=company, planned_start_date=now(), qty=20, skip_transfer=1)
+ job_card = frappe.db.get_value('Job Card', {'work_order': wo_order.name}, 'name')
+ update_job_card(job_card)
+
+ stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 10))
+ for row in stock_entry.items:
+ if row.is_scrap_item:
+ self.assertEqual(row.qty, 1)
+
+def update_job_card(job_card):
+ job_card_doc = frappe.get_doc('Job Card', job_card)
+ job_card_doc.set('scrap_items', [
+ {
+ 'item_code': 'Test RM Item 1 for Scrap Item Test',
+ 'stock_qty': 2
+ },
+ {
+ 'item_code': 'Test RM Item 2 for Scrap Item Test',
+ 'stock_qty': 2
+ },
+ ])
+
+ job_card_doc.append('time_logs', {
+ 'from_time': now(),
+ 'time_in_mins': 60,
+ 'completed_qty': job_card_doc.for_quantity
+ })
+
+ job_card_doc.submit()
+
+
def get_scrap_item_details(bom_no):
scrap_items = {}
for item in frappe.db.sql("""select item_code, stock_qty from `tabBOM Scrap Item`
@@ -797,6 +864,7 @@ def make_wo_order_test_record(**args):
wo_order.get_items_and_operations_from_bom()
wo_order.sales_order = args.sales_order or None
wo_order.planned_start_date = args.planned_start_date or now()
+ wo_order.transfer_material_against = args.transfer_material_against or "Work Order"
if args.source_warehouse:
for item in wo_order.get("required_items"):
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 24b33d523e4..e282dd3ecba 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -1,25 +1,43 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-import frappe
import json
-import math
-from frappe import _
-from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate, get_link_to_form, time_diff_in_hours
-from frappe.model.document import Document
-from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, get_bom_items_as_dict, get_bom_item_rate
+
+import frappe
from dateutil.relativedelta import relativedelta
-from erpnext.stock.doctype.item.item import validate_end_of_life, get_item_defaults
-from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError
-from erpnext.projects.doctype.timesheet.timesheet import OverlapError
-from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
-from erpnext.stock.stock_balance import get_planned_qty, update_bin_qty
-from frappe.utils.csvutils import getlink
-from erpnext.stock.utils import get_bin, validate_warehouse_company, get_latest_stock_qty
-from erpnext.utilities.transaction_base import validate_uom_is_integer
+from frappe import _
+from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
+from frappe.utils import (
+ cint,
+ date_diff,
+ flt,
+ get_datetime,
+ get_link_to_form,
+ getdate,
+ nowdate,
+ time_diff_in_hours,
+)
+
+from erpnext.manufacturing.doctype.bom.bom import (
+ get_bom_item_rate,
+ get_bom_items_as_dict,
+ validate_bom_no,
+)
+from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import (
+ get_mins_between_operations,
+)
from erpnext.stock.doctype.batch.batch import make_batch
-from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, get_auto_serial_nos, auto_make_serial_nos
+from erpnext.stock.doctype.item.item import get_item_defaults, validate_end_of_life
+from erpnext.stock.doctype.serial_no.serial_no import (
+ auto_make_serial_nos,
+ get_auto_serial_nos,
+ get_serial_nos,
+)
+from erpnext.stock.stock_balance import get_planned_qty, update_bin_qty
+from erpnext.stock.utils import get_bin, get_latest_stock_qty, validate_warehouse_company
+from erpnext.utilities.transaction_base import validate_uom_is_integer
+
class OverProductionError(frappe.ValidationError): pass
class CapacityError(frappe.ValidationError): pass
diff --git a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
index 403d46d8d42..f0fc43f1656 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'work_order',
diff --git a/erpnext/manufacturing/doctype/work_order_item/work_order_item.py b/erpnext/manufacturing/doctype/work_order_item/work_order_item.py
index 9aa53b5e3c3..3f2664b16e9 100644
--- a/erpnext/manufacturing/doctype/work_order_item/work_order_item.py
+++ b/erpnext/manufacturing/doctype/work_order_item/work_order_item.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class WorkOrderItem(Document):
pass
diff --git a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.py b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.py
index 3c20d8e88a0..d25c9f21890 100644
--- a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.py
+++ b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.py
@@ -2,8 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class WorkOrderOperation(Document):
pass
diff --git a/erpnext/manufacturing/doctype/workstation/test_workstation.py b/erpnext/manufacturing/doctype/workstation/test_workstation.py
index 9b73aca6010..6c6ab77dd8f 100644
--- a/erpnext/manufacturing/doctype/workstation/test_workstation.py
+++ b/erpnext/manufacturing/doctype/workstation/test_workstation.py
@@ -1,14 +1,20 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
from __future__ import unicode_literals
-from erpnext.manufacturing.doctype.operation.test_operation import make_operation
+
+import unittest
import frappe
-import unittest
-from erpnext.manufacturing.doctype.workstation.workstation import check_if_within_operating_hours, NotInWorkingHoursError, WorkstationHolidayError
-from erpnext.manufacturing.doctype.routing.test_routing import setup_bom, create_routing
from frappe.test_runner import make_test_records
+from erpnext.manufacturing.doctype.operation.test_operation import make_operation
+from erpnext.manufacturing.doctype.routing.test_routing import create_routing, setup_bom
+from erpnext.manufacturing.doctype.workstation.workstation import (
+ NotInWorkingHoursError,
+ WorkstationHolidayError,
+ check_if_within_operating_hours,
+)
+
test_dependencies = ["Warehouse"]
test_records = frappe.get_test_records('Workstation')
make_test_records('Workstation')
diff --git a/erpnext/manufacturing/doctype/workstation/workstation.py b/erpnext/manufacturing/doctype/workstation/workstation.py
index f4483f75472..6daf950c5ff 100644
--- a/erpnext/manufacturing/doctype/workstation/workstation.py
+++ b/erpnext/manufacturing/doctype/workstation/workstation.py
@@ -2,13 +2,23 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from erpnext.support.doctype.issue.issue import get_holidays
-from frappe.utils import (flt, cint, getdate, formatdate,
- comma_and, time_diff_in_seconds, to_timedelta, add_days)
from frappe.model.document import Document
-from dateutil.parser import parse
+from frappe.utils import (
+ add_days,
+ cint,
+ comma_and,
+ flt,
+ formatdate,
+ getdate,
+ time_diff_in_seconds,
+ to_timedelta,
+)
+
+from erpnext.support.doctype.issue.issue import get_holidays
+
class WorkstationHolidayError(frappe.ValidationError): pass
class NotInWorkingHoursError(frappe.ValidationError): pass
diff --git a/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py b/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py
index 3ddbe731700..3e4b38aae85 100644
--- a/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py
+++ b/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'workstation',
diff --git a/erpnext/manufacturing/doctype/workstation_working_hour/workstation_working_hour.py b/erpnext/manufacturing/doctype/workstation_working_hour/workstation_working_hour.py
index 215df4c9b5d..719d83db51a 100644
--- a/erpnext/manufacturing/doctype/workstation_working_hour/workstation_working_hour.py
+++ b/erpnext/manufacturing/doctype/workstation_working_hour/workstation_working_hour.py
@@ -2,8 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class WorkstationWorkingHour(Document):
pass
diff --git a/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.py b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.py
index 2334f8b26d8..f57de916dd1 100644
--- a/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.py
+++ b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.py
@@ -1,6 +1,5 @@
from __future__ import unicode_literals
-import frappe
def get_context(context):
# do your magic here
diff --git a/erpnext/manufacturing/report/bom_explorer/bom_explorer.py b/erpnext/manufacturing/report/bom_explorer/bom_explorer.py
index 858b5546b02..c122fa9b614 100644
--- a/erpnext/manufacturing/report/bom_explorer/bom_explorer.py
+++ b/erpnext/manufacturing/report/bom_explorer/bom_explorer.py
@@ -2,8 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from pprint import pprint
+
def execute(filters=None):
data = []
diff --git a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py
index 8778d9ba557..3c2d2153697 100644
--- a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py
+++ b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
data = get_data(filters)
columns = get_columns(filters)
diff --git a/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py b/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py
index ffd9242e1b8..c085990acc3 100644
--- a/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py
+++ b/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py
@@ -2,12 +2,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils.data import comma_and
+
def execute(filters=None):
-# if not filters: filters = {}
+ # if not filters: filters = {}
columns = get_columns()
summ_data = []
diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py
index ed8b93929a1..b8ef68dbb68 100644
--- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py
+++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/manufacturing/report/bom_variance_report/bom_variance_report.py b/erpnext/manufacturing/report/bom_variance_report/bom_variance_report.py
index dc424b7605c..bbf503718f9 100644
--- a/erpnext/manufacturing/report/bom_variance_report/bom_variance_report.py
+++ b/erpnext/manufacturing/report/bom_variance_report/bom_variance_report.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
columns, data = [], []
columns = get_columns(filters)
diff --git a/erpnext/manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py b/erpnext/manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py
index b4db98c3d7e..0dcad448d79 100644
--- a/erpnext/manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py
+++ b/erpnext/manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py
@@ -2,10 +2,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt
+
def execute(filters=None):
columns, data = [], []
diff --git a/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py b/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py
index 74c794b5dd0..a1c6fd12622 100644
--- a/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py
+++ b/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import flt
from frappe import _
+from frappe.utils import flt
+
def execute(filters=None):
columns, data = [], []
diff --git a/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py b/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py
index 9a6c764c609..f014e7f9b57 100644
--- a/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py
+++ b/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py
@@ -2,12 +2,16 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+
+import frappe
from frappe import _
-from frappe.utils import flt, nowdate, add_years, cint, getdate
+from frappe.utils import add_years, cint, flt, getdate
+
+import erpnext
from erpnext.accounts.report.financial_statements import get_period_list
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
+
def execute(filters=None):
return ForecastingReport(filters).execute_report()
diff --git a/erpnext/manufacturing/report/job_card_summary/job_card_summary.py b/erpnext/manufacturing/report/job_card_summary/job_card_summary.py
index a8939051523..a7aec315ff2 100644
--- a/erpnext/manufacturing/report/job_card_summary/job_card_summary.py
+++ b/erpnext/manufacturing/report/job_card_summary/job_card_summary.py
@@ -2,10 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import getdate, flt
-from erpnext.stock.report.stock_analytics.stock_analytics import (get_period_date_ranges, get_period)
+from frappe.utils import getdate
+
+from erpnext.stock.report.stock_analytics.stock_analytics import get_period, get_period_date_ranges
+
def execute(filters=None):
columns, data = [], []
diff --git a/erpnext/manufacturing/report/production_analytics/production_analytics.py b/erpnext/manufacturing/report/production_analytics/production_analytics.py
index 42c9d97cb5e..9e0978aee7f 100644
--- a/erpnext/manufacturing/report/production_analytics/production_analytics.py
+++ b/erpnext/manufacturing/report/production_analytics/production_analytics.py
@@ -2,10 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _, scrub
from frappe.utils import getdate
-from erpnext.stock.report.stock_analytics.stock_analytics import (get_period_date_ranges, get_period)
+
+from erpnext.stock.report.stock_analytics.stock_analytics import get_period, get_period_date_ranges
+
def execute(filters=None):
columns = get_columns(filters)
diff --git a/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.py b/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.py
index 81b1791ae81..9a4d0c42db4 100644
--- a/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.py
+++ b/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.utils import flt
+
def execute(filters=None):
columns, data = [], []
data = get_data(filters)
diff --git a/erpnext/manufacturing/report/production_planning_report/production_planning_report.py b/erpnext/manufacturing/report/production_planning_report/production_planning_report.py
index 806d268ffde..e27270ae8b9 100644
--- a/erpnext/manufacturing/report/production_planning_report/production_planning_report.py
+++ b/erpnext/manufacturing/report/production_planning_report/production_planning_report.py
@@ -2,8 +2,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
# and bom_no is not null and bom_no !=''
diff --git a/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py b/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py
index a12ac7f9d91..54df208346c 100644
--- a/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py
+++ b/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
columns, data = [], []
data = get_data(filters)
diff --git a/erpnext/manufacturing/report/work_order_stock_report/work_order_stock_report.py b/erpnext/manufacturing/report/work_order_stock_report/work_order_stock_report.py
index 599a738f6f6..5b2e2620fd7 100644
--- a/erpnext/manufacturing/report/work_order_stock_report/work_order_stock_report.py
+++ b/erpnext/manufacturing/report/work_order_stock_report/work_order_stock_report.py
@@ -2,8 +2,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe.utils import cint
+
import frappe
+from frappe.utils import cint
+
def execute(filters=None):
wo_list = get_work_orders()
diff --git a/erpnext/manufacturing/report/work_order_summary/work_order_summary.py b/erpnext/manufacturing/report/work_order_summary/work_order_summary.py
index d0766f9abe5..b65af33cec5 100644
--- a/erpnext/manufacturing/report/work_order_summary/work_order_summary.py
+++ b/erpnext/manufacturing/report/work_order_summary/work_order_summary.py
@@ -2,10 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import date_diff, today, getdate, flt
from frappe import _
-from erpnext.stock.report.stock_analytics.stock_analytics import (get_period_date_ranges, get_period)
+from frappe.utils import date_diff, flt, getdate, today
+
+from erpnext.stock.report.stock_analytics.stock_analytics import get_period, get_period_date_ranges
+
def execute(filters=None):
columns, data = [], []
diff --git a/erpnext/modules.txt b/erpnext/modules.txt
index 62f5dce8460..3ffa5f292cc 100644
--- a/erpnext/modules.txt
+++ b/erpnext/modules.txt
@@ -9,7 +9,6 @@ Manufacturing
Stock
Support
Utilities
-Shopping Cart
Assets
Portal
Maintenance
@@ -26,4 +25,5 @@ Quality Management
Communication
Loan Management
Payroll
-Telephony
\ No newline at end of file
+Telephony
+E-commerce
\ No newline at end of file
diff --git a/erpnext/non_profit/doctype/certification_application/certification_application.py b/erpnext/non_profit/doctype/certification_application/certification_application.py
index d4fc76bbfa5..ff400c81ae3 100644
--- a/erpnext/non_profit/doctype/certification_application/certification_application.py
+++ b/erpnext/non_profit/doctype/certification_application/certification_application.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class CertificationApplication(Document):
pass
diff --git a/erpnext/non_profit/doctype/certification_application/test_certification_application.js b/erpnext/non_profit/doctype/certification_application/test_certification_application.js
deleted file mode 100644
index 40e94864d49..00000000000
--- a/erpnext/non_profit/doctype/certification_application/test_certification_application.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Certification Application", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Certification Application
- () => frappe.tests.make('Certification Application', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/non_profit/doctype/certification_application/test_certification_application.py b/erpnext/non_profit/doctype/certification_application/test_certification_application.py
index 30cb8c0acdf..5e1cbf85961 100644
--- a/erpnext/non_profit/doctype/certification_application/test_certification_application.py
+++ b/erpnext/non_profit/doctype/certification_application/test_certification_application.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestCertificationApplication(unittest.TestCase):
pass
diff --git a/erpnext/non_profit/doctype/certified_consultant/certified_consultant.py b/erpnext/non_profit/doctype/certified_consultant/certified_consultant.py
index 3bc6ed74c26..0cbc2088c96 100644
--- a/erpnext/non_profit/doctype/certified_consultant/certified_consultant.py
+++ b/erpnext/non_profit/doctype/certified_consultant/certified_consultant.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class CertifiedConsultant(Document):
pass
diff --git a/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.js b/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.js
deleted file mode 100644
index f6a72a43271..00000000000
--- a/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Certified Consultant", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Certified Consultant
- () => frappe.tests.make('Certified Consultant', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.py b/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.py
index 19b485db1fb..29a73881a58 100644
--- a/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.py
+++ b/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestCertifiedConsultant(unittest.TestCase):
pass
diff --git a/erpnext/non_profit/doctype/chapter/chapter.py b/erpnext/non_profit/doctype/chapter/chapter.py
index e9554b1f55c..c5c9569e74e 100644
--- a/erpnext/non_profit/doctype/chapter/chapter.py
+++ b/erpnext/non_profit/doctype/chapter/chapter.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.website.website_generator import WebsiteGenerator
+
class Chapter(WebsiteGenerator):
_website = frappe._dict(
condition_field = "published",
diff --git a/erpnext/non_profit/doctype/chapter/test_chapter.js b/erpnext/non_profit/doctype/chapter/test_chapter.js
deleted file mode 100644
index e30d6a5bf9b..00000000000
--- a/erpnext/non_profit/doctype/chapter/test_chapter.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Chapter", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Chapter
- () => frappe.tests.make('Chapter', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/non_profit/doctype/chapter/test_chapter.py b/erpnext/non_profit/doctype/chapter/test_chapter.py
index d757a1f9159..04cdc277475 100644
--- a/erpnext/non_profit/doctype/chapter/test_chapter.py
+++ b/erpnext/non_profit/doctype/chapter/test_chapter.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestChapter(unittest.TestCase):
pass
diff --git a/erpnext/non_profit/doctype/chapter_member/chapter_member.py b/erpnext/non_profit/doctype/chapter_member/chapter_member.py
index a1b25f2d4e2..1638294de12 100644
--- a/erpnext/non_profit/doctype/chapter_member/chapter_member.py
+++ b/erpnext/non_profit/doctype/chapter_member/chapter_member.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class ChapterMember(Document):
pass
diff --git a/erpnext/non_profit/doctype/donation/donation.py b/erpnext/non_profit/doctype/donation/donation.py
index 9aa7e13433c..e4e2b4e7d65 100644
--- a/erpnext/non_profit/doctype/donation/donation.py
+++ b/erpnext/non_profit/doctype/donation/donation.py
@@ -3,15 +3,19 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
+import json
+
import frappe
import six
-import json
-from frappe.model.document import Document
from frappe import _
-from frappe.utils import getdate, flt, get_link_to_form
from frappe.email import sendmail_to_system_managers
+from frappe.model.document import Document
+from frappe.utils import flt, get_link_to_form, getdate
+
from erpnext.non_profit.doctype.membership.membership import verify_signature
+
class Donation(Document):
def validate(self):
if not self.donor or not frappe.db.exists('Donor', self.donor):
diff --git a/erpnext/non_profit/doctype/donation/donation_dashboard.py b/erpnext/non_profit/doctype/donation/donation_dashboard.py
index 3da89423d37..4a16077ef47 100644
--- a/erpnext/non_profit/doctype/donation/donation_dashboard.py
+++ b/erpnext/non_profit/doctype/donation/donation_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'donation',
diff --git a/erpnext/non_profit/doctype/donation/test_donation.py b/erpnext/non_profit/doctype/donation/test_donation.py
index b206f54523e..6b9ade9185c 100644
--- a/erpnext/non_profit/doctype/donation/test_donation.py
+++ b/erpnext/non_profit/doctype/donation/test_donation.py
@@ -3,10 +3,13 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
+
from erpnext.non_profit.doctype.donation.donation import create_donation
+
class TestDonation(unittest.TestCase):
def setUp(self):
create_donor_type()
diff --git a/erpnext/non_profit/doctype/donor/donor.py b/erpnext/non_profit/doctype/donor/donor.py
index ab6a197ed51..a46163a0128 100644
--- a/erpnext/non_profit/doctype/donor/donor.py
+++ b/erpnext/non_profit/doctype/donor/donor.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe.model.document import Document
+
from frappe.contacts.address_and_contact import load_address_and_contact
+from frappe.model.document import Document
+
class Donor(Document):
def onload(self):
diff --git a/erpnext/non_profit/doctype/donor/test_donor.py b/erpnext/non_profit/doctype/donor/test_donor.py
index 3b6724eb63a..5ce01998bc3 100644
--- a/erpnext/non_profit/doctype/donor/test_donor.py
+++ b/erpnext/non_profit/doctype/donor/test_donor.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestDonor(unittest.TestCase):
pass
diff --git a/erpnext/non_profit/doctype/donor_type/donor_type.py b/erpnext/non_profit/doctype/donor_type/donor_type.py
index e9262ac2a52..4d34725d024 100644
--- a/erpnext/non_profit/doctype/donor_type/donor_type.py
+++ b/erpnext/non_profit/doctype/donor_type/donor_type.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class DonorType(Document):
pass
diff --git a/erpnext/non_profit/doctype/donor_type/test_donor_type.js b/erpnext/non_profit/doctype/donor_type/test_donor_type.js
deleted file mode 100644
index 22dc18ed76a..00000000000
--- a/erpnext/non_profit/doctype/donor_type/test_donor_type.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Donor Type", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Member
- () => frappe.tests.make('Donor Type', [
- // values to be set
- {donor_type: 'Test Organization'},
- ]),
- () => {
- assert.equal(cur_frm.doc.donor_type, 'Test Organization');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/non_profit/doctype/donor_type/test_donor_type.py b/erpnext/non_profit/doctype/donor_type/test_donor_type.py
index e7939136b71..7857ec5ad21 100644
--- a/erpnext/non_profit/doctype/donor_type/test_donor_type.py
+++ b/erpnext/non_profit/doctype/donor_type/test_donor_type.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-
import unittest
+
class TestDonorType(unittest.TestCase):
pass
diff --git a/erpnext/non_profit/doctype/grant_application/grant_application.py b/erpnext/non_profit/doctype/grant_application/grant_application.py
index b810fd027af..92a62563ab9 100644
--- a/erpnext/non_profit/doctype/grant_application/grant_application.py
+++ b/erpnext/non_profit/doctype/grant_application/grant_application.py
@@ -3,11 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.website.website_generator import WebsiteGenerator
from frappe.contacts.address_and_contact import load_address_and_contact
from frappe.utils import get_url
+from frappe.website.website_generator import WebsiteGenerator
+
class GrantApplication(WebsiteGenerator):
_website = frappe._dict(
diff --git a/erpnext/non_profit/doctype/grant_application/test_grant_application.py b/erpnext/non_profit/doctype/grant_application/test_grant_application.py
index da16acfaacb..d15809112ab 100644
--- a/erpnext/non_profit/doctype/grant_application/test_grant_application.py
+++ b/erpnext/non_profit/doctype/grant_application/test_grant_application.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestGrantApplication(unittest.TestCase):
pass
diff --git a/erpnext/non_profit/doctype/member/member.py b/erpnext/non_profit/doctype/member/member.py
index 67828d6efc8..f7e7f105d55 100644
--- a/erpnext/non_profit/doctype/member/member.py
+++ b/erpnext/non_profit/doctype/member/member.py
@@ -3,14 +3,17 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.model.document import Document
from frappe.contacts.address_and_contact import load_address_and_contact
-from frappe.utils import cint, get_link_to_form
from frappe.integrations.utils import get_payment_gateway_controller
+from frappe.model.document import Document
+from frappe.utils import cint, get_link_to_form
+
from erpnext.non_profit.doctype.membership_type.membership_type import get_membership_type
+
class Member(Document):
def onload(self):
"""Load address and contacts in `__onload`"""
diff --git a/erpnext/non_profit/doctype/member/member_dashboard.py b/erpnext/non_profit/doctype/member/member_dashboard.py
index 743db2513af..ff929a59093 100644
--- a/erpnext/non_profit/doctype/member/member_dashboard.py
+++ b/erpnext/non_profit/doctype/member/member_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'heatmap': True,
diff --git a/erpnext/non_profit/doctype/member/test_member.py b/erpnext/non_profit/doctype/member/test_member.py
index 748a500deec..38ad87f2f67 100644
--- a/erpnext/non_profit/doctype/member/test_member.py
+++ b/erpnext/non_profit/doctype/member/test_member.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestMember(unittest.TestCase):
pass
diff --git a/erpnext/non_profit/doctype/membership/membership.py b/erpnext/non_profit/doctype/membership/membership.py
index b584116df3c..b65dc8e1e37 100644
--- a/erpnext/non_profit/doctype/membership/membership.py
+++ b/erpnext/non_profit/doctype/membership/membership.py
@@ -3,17 +3,20 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import json
+from datetime import datetime
+
import frappe
import six
-import os
-from datetime import datetime
-from frappe.model.document import Document
-from frappe.email import sendmail_to_system_managers
-from frappe.utils import add_days, add_years, nowdate, getdate, add_months, get_link_to_form
-from erpnext.non_profit.doctype.member.member import create_member
from frappe import _
+from frappe.email import sendmail_to_system_managers
+from frappe.model.document import Document
+from frappe.utils import add_days, add_months, add_years, get_link_to_form, getdate, nowdate
+
import erpnext
+from erpnext.non_profit.doctype.member.member import create_member
+
class Membership(Document):
def validate(self):
@@ -207,7 +210,7 @@ def get_member_based_on_subscription(subscription_id, email=None, customer_id=No
try:
return frappe.get_doc("Member", members[0]["name"])
- except:
+ except Exception:
return None
@@ -393,7 +396,7 @@ def notify_failure(log):
""".format(get_link_to_form("Error Log", log.name))
sendmail_to_system_managers("[Important] [ERPNext] Razorpay membership webhook failed , please check.", content)
- except:
+ except Exception:
pass
@@ -402,7 +405,7 @@ def get_plan_from_razorpay_id(plan_id):
try:
return plan[0]["name"]
- except:
+ except Exception:
return None
diff --git a/erpnext/non_profit/doctype/membership/test_membership.js b/erpnext/non_profit/doctype/membership/test_membership.js
deleted file mode 100644
index 24c85c61576..00000000000
--- a/erpnext/non_profit/doctype/membership/test_membership.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Membership", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Membership
- () => frappe.tests.make('Membership', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/non_profit/doctype/membership/test_membership.py b/erpnext/non_profit/doctype/membership/test_membership.py
index 5ad2088fc31..5f52cdaca81 100644
--- a/erpnext/non_profit/doctype/membership/test_membership.py
+++ b/erpnext/non_profit/doctype/membership/test_membership.py
@@ -2,12 +2,16 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
import frappe
+from frappe.utils import add_months, nowdate
+
import erpnext
from erpnext.non_profit.doctype.member.member import create_member
from erpnext.non_profit.doctype.membership.membership import update_halted_razorpay_subscription
-from frappe.utils import nowdate, add_months
+
class TestMembership(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/non_profit/doctype/membership_type/membership_type.py b/erpnext/non_profit/doctype/membership_type/membership_type.py
index c712b99c3b8..1b847d94b99 100644
--- a/erpnext/non_profit/doctype/membership_type/membership_type.py
+++ b/erpnext/non_profit/doctype/membership_type/membership_type.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe.model.document import Document
+
import frappe
from frappe import _
+from frappe.model.document import Document
+
class MembershipType(Document):
def validate(self):
diff --git a/erpnext/non_profit/doctype/membership_type/test_membership_type.py b/erpnext/non_profit/doctype/membership_type/test_membership_type.py
index d2c9beed0df..2503ba17d1c 100644
--- a/erpnext/non_profit/doctype/membership_type/test_membership_type.py
+++ b/erpnext/non_profit/doctype/membership_type/test_membership_type.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestMembershipType(unittest.TestCase):
pass
diff --git a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py
index 50c93516adc..cb365cb6c10 100644
--- a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py
+++ b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py
@@ -3,11 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.integrations.utils import get_payment_gateway_controller
from frappe.model.document import Document
+
class NonProfitSettings(Document):
@frappe.whitelist()
def generate_webhook_secret(self, field="membership_webhook_secret"):
diff --git a/erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py b/erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py
index 3f0ede32e59..a0a54030cc9 100644
--- a/erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py
+++ b/erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestNonProfitSettings(unittest.TestCase):
pass
diff --git a/erpnext/non_profit/doctype/volunteer/test_volunteer.py b/erpnext/non_profit/doctype/volunteer/test_volunteer.py
index 6f3bee0edd9..346eac56770 100644
--- a/erpnext/non_profit/doctype/volunteer/test_volunteer.py
+++ b/erpnext/non_profit/doctype/volunteer/test_volunteer.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestVolunteer(unittest.TestCase):
pass
diff --git a/erpnext/non_profit/doctype/volunteer/volunteer.py b/erpnext/non_profit/doctype/volunteer/volunteer.py
index 699868aeb79..6c9232b0ea1 100644
--- a/erpnext/non_profit/doctype/volunteer/volunteer.py
+++ b/erpnext/non_profit/doctype/volunteer/volunteer.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe.model.document import Document
+
from frappe.contacts.address_and_contact import load_address_and_contact
+from frappe.model.document import Document
+
class Volunteer(Document):
def onload(self):
diff --git a/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.py b/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.py
index dc9f8231944..3422ec2dec3 100644
--- a/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.py
+++ b/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class VolunteerSkill(Document):
pass
diff --git a/erpnext/non_profit/doctype/volunteer_type/test_volunteer_type.py b/erpnext/non_profit/doctype/volunteer_type/test_volunteer_type.py
index 78f65c731a2..2c64d21bba4 100644
--- a/erpnext/non_profit/doctype/volunteer_type/test_volunteer_type.py
+++ b/erpnext/non_profit/doctype/volunteer_type/test_volunteer_type.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestVolunteerType(unittest.TestCase):
pass
diff --git a/erpnext/non_profit/doctype/volunteer_type/volunteer_type.py b/erpnext/non_profit/doctype/volunteer_type/volunteer_type.py
index 9776402a43f..116f5d8b52f 100644
--- a/erpnext/non_profit/doctype/volunteer_type/volunteer_type.py
+++ b/erpnext/non_profit/doctype/volunteer_type/volunteer_type.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class VolunteerType(Document):
pass
diff --git a/erpnext/non_profit/report/expiring_memberships/expiring_memberships.py b/erpnext/non_profit/report/expiring_memberships/expiring_memberships.py
index 122db45ea4e..2167b651c34 100644
--- a/erpnext/non_profit/report/expiring_memberships/expiring_memberships.py
+++ b/erpnext/non_profit/report/expiring_memberships/expiring_memberships.py
@@ -2,8 +2,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import _,msgprint
+from frappe import _
+
def execute(filters=None):
columns = get_columns(filters)
diff --git a/erpnext/non_profit/web_form/certification_application/certification_application.py b/erpnext/non_profit/web_form/certification_application/certification_application.py
index 2334f8b26d8..f57de916dd1 100644
--- a/erpnext/non_profit/web_form/certification_application/certification_application.py
+++ b/erpnext/non_profit/web_form/certification_application/certification_application.py
@@ -1,6 +1,5 @@
from __future__ import unicode_literals
-import frappe
def get_context(context):
# do your magic here
diff --git a/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.py b/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.py
index 2334f8b26d8..f57de916dd1 100644
--- a/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.py
+++ b/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.py
@@ -1,6 +1,5 @@
from __future__ import unicode_literals
-import frappe
def get_context(context):
# do your magic here
diff --git a/erpnext/non_profit/web_form/grant_application/grant_application.py b/erpnext/non_profit/web_form/grant_application/grant_application.py
index 186722a8bf0..dab0e9fda85 100644
--- a/erpnext/non_profit/web_form/grant_application/grant_application.py
+++ b/erpnext/non_profit/web_form/grant_application/grant_application.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+
def get_context(context):
context.no_cache = True
context.parents = [dict(label='View All ',
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index aeca7df802e..1fde68fcf7a 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -292,6 +292,7 @@ erpnext.patches.v13_0.rename_issue_status_hold_to_on_hold
erpnext.patches.v13_0.bill_for_rejected_quantity_in_purchase_invoice
erpnext.patches.v13_0.update_job_card_details
erpnext.patches.v13_0.update_level_in_bom #1234sswef
+erpnext.patches.v13_0.create_gst_payment_entry_fields
erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
erpnext.patches.v13_0.update_subscription_status_in_memberships
erpnext.patches.v13_0.update_amt_in_work_order_required_items
@@ -303,5 +304,12 @@ erpnext.patches.v13_0.update_recipient_email_digest
erpnext.patches.v13_0.shopify_deprecation_warning
erpnext.patches.v13_0.add_custom_field_for_south_africa #2
erpnext.patches.v13_0.rename_discharge_ordered_date_in_ip_record
+erpnext.patches.v13_0.migrate_stripe_api
+erpnext.patches.v13_0.reset_clearance_date_for_intracompany_payment_entries
+erpnext.patches.v13_0.custom_fields_for_taxjar_integration
erpnext.patches.v13_0.set_operation_time_based_on_operating_cost
erpnext.patches.v13_0.validate_options_for_data_field
+erpnext.patches.v13_0.create_website_items
+erpnext.patches.v13_0.populate_e_commerce_settings
+erpnext.patches.v13_0.make_homepage_products_website_items
+erpnext.patches.v13_0.update_dates_in_tax_withholding_category
diff --git a/erpnext/patches/v10_0/add_default_cash_flow_mappers.py b/erpnext/patches/v10_0/add_default_cash_flow_mappers.py
index d607b2f745e..5c28597faad 100644
--- a/erpnext/patches/v10_0/add_default_cash_flow_mappers.py
+++ b/erpnext/patches/v10_0/add_default_cash_flow_mappers.py
@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
+
from erpnext.setup.install import create_default_cash_flow_mapper_templates
diff --git a/erpnext/patches/v10_0/delete_hub_documents.py b/erpnext/patches/v10_0/delete_hub_documents.py
index f6a14998956..16c7abfc978 100644
--- a/erpnext/patches/v10_0/delete_hub_documents.py
+++ b/erpnext/patches/v10_0/delete_hub_documents.py
@@ -1,7 +1,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.model.utils.rename_field import rename_field
+
def execute():
for dt, dn in (("Page", "Hub"), ("DocType", "Hub Settings"), ("DocType", "Hub Category")):
diff --git a/erpnext/patches/v10_0/fichier_des_ecritures_comptables_for_france.py b/erpnext/patches/v10_0/fichier_des_ecritures_comptables_for_france.py
index 0315ae72a7d..a3e49577a33 100644
--- a/erpnext/patches/v10_0/fichier_des_ecritures_comptables_for_france.py
+++ b/erpnext/patches/v10_0/fichier_des_ecritures_comptables_for_france.py
@@ -2,9 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
from erpnext.setup.doctype.company.company import install_country_fixtures
+
def execute():
frappe.reload_doc('regional', 'report', 'fichier_des_ecritures_comptables_[fec]')
for d in frappe.get_all('Company', filters = {'country': 'France'}):
diff --git a/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py b/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py
index daa258e8825..a3c61a5294a 100644
--- a/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py
+++ b/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py
@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
diff --git a/erpnext/patches/v10_0/rename_offer_letter_to_job_offer.py b/erpnext/patches/v10_0/rename_offer_letter_to_job_offer.py
index f832936b10a..4fc419e302c 100644
--- a/erpnext/patches/v10_0/rename_offer_letter_to_job_offer.py
+++ b/erpnext/patches/v10_0/rename_offer_letter_to_job_offer.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
if frappe.db.table_exists("Offer Letter") and not frappe.db.table_exists("Job Offer"):
frappe.rename_doc("DocType", "Offer Letter", "Job Offer", force=True)
diff --git a/erpnext/patches/v10_0/rename_price_to_rate_in_pricing_rule.py b/erpnext/patches/v10_0/rename_price_to_rate_in_pricing_rule.py
index a9dd3103100..1b8c6fb7ea5 100644
--- a/erpnext/patches/v10_0/rename_price_to_rate_in_pricing_rule.py
+++ b/erpnext/patches/v10_0/rename_price_to_rate_in_pricing_rule.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
frappe.reload_doc("accounts", "doctype", "pricing_rule")
diff --git a/erpnext/patches/v10_0/set_currency_in_pricing_rule.py b/erpnext/patches/v10_0/set_currency_in_pricing_rule.py
index c4139312d9f..2a3f1c03bde 100644
--- a/erpnext/patches/v10_0/set_currency_in_pricing_rule.py
+++ b/erpnext/patches/v10_0/set_currency_in_pricing_rule.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doctype("Pricing Rule")
diff --git a/erpnext/patches/v10_0/update_translatable_fields.py b/erpnext/patches/v10_0/update_translatable_fields.py
index 9d6bda71685..2c55a052173 100644
--- a/erpnext/patches/v10_0/update_translatable_fields.py
+++ b/erpnext/patches/v10_0/update_translatable_fields.py
@@ -4,6 +4,7 @@ from __future__ import unicode_literals
import frappe
+
def execute():
'''
Enable translatable in these fields
diff --git a/erpnext/patches/v10_1/transfer_subscription_to_auto_repeat.py b/erpnext/patches/v10_1/transfer_subscription_to_auto_repeat.py
index 3d1a88e800c..2d5b0c5bd4a 100644
--- a/erpnext/patches/v10_1/transfer_subscription_to_auto_repeat.py
+++ b/erpnext/patches/v10_1/transfer_subscription_to_auto_repeat.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
diff --git a/erpnext/patches/v11_0/add_default_dispatch_notification_template.py b/erpnext/patches/v11_0/add_default_dispatch_notification_template.py
index f4c18955390..197b3b72676 100644
--- a/erpnext/patches/v11_0/add_default_dispatch_notification_template.py
+++ b/erpnext/patches/v11_0/add_default_dispatch_notification_template.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
import os
import frappe
diff --git a/erpnext/patches/v11_0/add_default_email_template_for_leave.py b/erpnext/patches/v11_0/add_default_email_template_for_leave.py
index 0f1e4966231..f8538df2ef2 100644
--- a/erpnext/patches/v11_0/add_default_email_template_for_leave.py
+++ b/erpnext/patches/v11_0/add_default_email_template_for_leave.py
@@ -1,7 +1,11 @@
from __future__ import unicode_literals
-import frappe, os
+
+import os
+
+import frappe
from frappe import _
+
def execute():
frappe.reload_doc("email", "doctype", "email_template")
diff --git a/erpnext/patches/v11_0/add_expense_claim_default_account.py b/erpnext/patches/v11_0/add_expense_claim_default_account.py
index a613bd88497..74b93efbf80 100644
--- a/erpnext/patches/v11_0/add_expense_claim_default_account.py
+++ b/erpnext/patches/v11_0/add_expense_claim_default_account.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("setup", "doctype", "company")
diff --git a/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py b/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py
index a45f39d4340..9bb91dc14c1 100644
--- a/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py
+++ b/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute():
""" assign lft and rgt appropriately """
if "Healthcare" not in frappe.get_active_domains():
diff --git a/erpnext/patches/v11_0/add_index_on_nestedset_doctypes.py b/erpnext/patches/v11_0/add_index_on_nestedset_doctypes.py
index 0243dfb38ed..08ad855e5e2 100644
--- a/erpnext/patches/v11_0/add_index_on_nestedset_doctypes.py
+++ b/erpnext/patches/v11_0/add_index_on_nestedset_doctypes.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("assets", "doctype", "Location")
for dt in ("Account", "Cost Center", "File", "Employee", "Location", "Task", "Customer Group", "Sales Person", "Territory"):
diff --git a/erpnext/patches/v11_0/add_item_group_defaults.py b/erpnext/patches/v11_0/add_item_group_defaults.py
index 2a15ad1e2a3..6849b27feee 100644
--- a/erpnext/patches/v11_0/add_item_group_defaults.py
+++ b/erpnext/patches/v11_0/add_item_group_defaults.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
'''
diff --git a/erpnext/patches/v11_0/add_market_segments.py b/erpnext/patches/v11_0/add_market_segments.py
index a8841ef3a44..e7cc7d1117c 100644
--- a/erpnext/patches/v11_0/add_market_segments.py
+++ b/erpnext/patches/v11_0/add_market_segments.py
@@ -1,9 +1,10 @@
from __future__ import unicode_literals
import frappe
-from frappe import _
+
from erpnext.setup.setup_wizard.operations.install_fixtures import add_market_segments
+
def execute():
frappe.reload_doc('crm', 'doctype', 'market_segment')
diff --git a/erpnext/patches/v11_0/add_permissions_in_gst_settings.py b/erpnext/patches/v11_0/add_permissions_in_gst_settings.py
index 83b2a4cc09e..9df1b586e30 100644
--- a/erpnext/patches/v11_0/add_permissions_in_gst_settings.py
+++ b/erpnext/patches/v11_0/add_permissions_in_gst_settings.py
@@ -1,6 +1,8 @@
import frappe
+
from erpnext.regional.india.setup import add_permissions
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
diff --git a/erpnext/patches/v11_0/add_sales_stages.py b/erpnext/patches/v11_0/add_sales_stages.py
index d06c6889ff7..23e48747b82 100644
--- a/erpnext/patches/v11_0/add_sales_stages.py
+++ b/erpnext/patches/v11_0/add_sales_stages.py
@@ -1,8 +1,10 @@
from __future__ import unicode_literals
+
import frappe
-from frappe import _
+
from erpnext.setup.setup_wizard.operations.install_fixtures import add_sale_stages
+
def execute():
frappe.reload_doc('crm', 'doctype', 'sales_stage')
diff --git a/erpnext/patches/v11_0/check_buying_selling_in_currency_exchange.py b/erpnext/patches/v11_0/check_buying_selling_in_currency_exchange.py
index 0a1a36007e5..5eaf21220bd 100644
--- a/erpnext/patches/v11_0/check_buying_selling_in_currency_exchange.py
+++ b/erpnext/patches/v11_0/check_buying_selling_in_currency_exchange.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('setup', 'doctype', 'currency_exchange')
frappe.db.sql("""update `tabCurrency Exchange` set for_buying = 1, for_selling = 1""")
diff --git a/erpnext/patches/v11_0/create_default_success_action.py b/erpnext/patches/v11_0/create_default_success_action.py
index 31feff25b93..4a598371f82 100644
--- a/erpnext/patches/v11_0/create_default_success_action.py
+++ b/erpnext/patches/v11_0/create_default_success_action.py
@@ -1,7 +1,10 @@
from __future__ import unicode_literals
+
import frappe
+
from erpnext.setup.install import create_default_success_action
+
def execute():
frappe.reload_doc("core", "doctype", "success_action")
create_default_success_action()
diff --git a/erpnext/patches/v11_0/create_department_records_for_each_company.py b/erpnext/patches/v11_0/create_department_records_for_each_company.py
index e9b5950a133..7799a650405 100644
--- a/erpnext/patches/v11_0/create_department_records_for_each_company.py
+++ b/erpnext/patches/v11_0/create_department_records_for_each_company.py
@@ -1,8 +1,10 @@
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils.nestedset import rebuild_tree
+
def execute():
frappe.local.lang = frappe.db.get_default("lang") or 'en'
diff --git a/erpnext/patches/v11_0/create_salary_structure_assignments.py b/erpnext/patches/v11_0/create_salary_structure_assignments.py
index d3ea7a3c1c0..c3cc9b6d309 100644
--- a/erpnext/patches/v11_0/create_salary_structure_assignments.py
+++ b/erpnext/patches/v11_0/create_salary_structure_assignments.py
@@ -2,10 +2,16 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
from datetime import datetime
+
+import frappe
from frappe.utils import getdate
-from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import DuplicateAssignment
+
+from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import (
+ DuplicateAssignment,
+)
+
def execute():
frappe.reload_doc('Payroll', 'doctype', 'Salary Structure')
diff --git a/erpnext/patches/v11_0/drop_column_max_days_allowed.py b/erpnext/patches/v11_0/drop_column_max_days_allowed.py
index 029f75a2258..e45d01cef58 100644
--- a/erpnext/patches/v11_0/drop_column_max_days_allowed.py
+++ b/erpnext/patches/v11_0/drop_column_max_days_allowed.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
if frappe.db.exists("DocType", "Leave Type"):
if 'max_days_allowed' in frappe.db.get_table_columns("Leave Type"):
diff --git a/erpnext/patches/v11_0/ewaybill_fields_gst_india.py b/erpnext/patches/v11_0/ewaybill_fields_gst_india.py
index 4247c788e33..a59291ce420 100644
--- a/erpnext/patches/v11_0/ewaybill_fields_gst_india.py
+++ b/erpnext/patches/v11_0/ewaybill_fields_gst_india.py
@@ -1,7 +1,10 @@
from __future__ import unicode_literals
+
import frappe
+
from erpnext.regional.india.setup import make_custom_fields
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
diff --git a/erpnext/patches/v11_0/hr_ux_cleanups.py b/erpnext/patches/v11_0/hr_ux_cleanups.py
index 8d187965011..b09f4a7e7f2 100644
--- a/erpnext/patches/v11_0/hr_ux_cleanups.py
+++ b/erpnext/patches/v11_0/hr_ux_cleanups.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doctype('Employee')
frappe.db.sql('update tabEmployee set first_name = employee_name')
diff --git a/erpnext/patches/v11_0/inter_state_field_for_gst.py b/erpnext/patches/v11_0/inter_state_field_for_gst.py
index 730eebc01ce..fa83af00655 100644
--- a/erpnext/patches/v11_0/inter_state_field_for_gst.py
+++ b/erpnext/patches/v11_0/inter_state_field_for_gst.py
@@ -1,6 +1,9 @@
from __future__ import unicode_literals
+
import frappe
-from erpnext.regional.india.setup import make_custom_fields
+
+from erpnext.regional.india.setup import make_custom_fields
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
diff --git a/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py b/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py
index dfcf5ab2886..1d3f8c1204d 100644
--- a/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py
+++ b/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py
@@ -2,8 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils.nestedset import rebuild_tree
+
def execute():
frappe.reload_doc('assets', 'doctype', 'asset_finance_book')
diff --git a/erpnext/patches/v11_0/make_italian_localization_fields.py b/erpnext/patches/v11_0/make_italian_localization_fields.py
index 29d25c9a2d4..994df721c25 100644
--- a/erpnext/patches/v11_0/make_italian_localization_fields.py
+++ b/erpnext/patches/v11_0/make_italian_localization_fields.py
@@ -2,10 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-from erpnext.regional.italy.setup import make_custom_fields, setup_report
-from erpnext.regional.italy import state_codes
+
import frappe
+from erpnext.regional.italy import state_codes
+from erpnext.regional.italy.setup import make_custom_fields, setup_report
+
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'Italy'})
if not company:
diff --git a/erpnext/patches/v11_0/make_job_card.py b/erpnext/patches/v11_0/make_job_card.py
index 9c41c0b991f..e361d5a8381 100644
--- a/erpnext/patches/v11_0/make_job_card.py
+++ b/erpnext/patches/v11_0/make_job_card.py
@@ -2,9 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
from erpnext.manufacturing.doctype.work_order.work_order import create_job_card
+
def execute():
frappe.reload_doc('manufacturing', 'doctype', 'work_order')
frappe.reload_doc('manufacturing', 'doctype', 'work_order_item')
diff --git a/erpnext/patches/v11_0/make_location_from_warehouse.py b/erpnext/patches/v11_0/make_location_from_warehouse.py
index 8c92b5180d9..e855b3ee5e1 100644
--- a/erpnext/patches/v11_0/make_location_from_warehouse.py
+++ b/erpnext/patches/v11_0/make_location_from_warehouse.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.utils.nestedset import rebuild_tree
+
def execute():
if not frappe.db.get_value('Asset', {'docstatus': ('<', 2) }, 'name'): return
frappe.reload_doc('assets', 'doctype', 'location')
diff --git a/erpnext/patches/v11_0/make_quality_inspection_template.py b/erpnext/patches/v11_0/make_quality_inspection_template.py
index 9720af41219..1c3d34ee208 100644
--- a/erpnext/patches/v11_0/make_quality_inspection_template.py
+++ b/erpnext/patches/v11_0/make_quality_inspection_template.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('stock', 'doctype', 'quality_inspection_template')
frappe.reload_doc('stock', 'doctype', 'item')
diff --git a/erpnext/patches/v11_0/move_item_defaults_to_child_table_for_multicompany.py b/erpnext/patches/v11_0/move_item_defaults_to_child_table_for_multicompany.py
index 6da70b4ce38..42fdf1358ad 100644
--- a/erpnext/patches/v11_0/move_item_defaults_to_child_table_for_multicompany.py
+++ b/erpnext/patches/v11_0/move_item_defaults_to_child_table_for_multicompany.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
'''
@@ -30,7 +32,7 @@ def execute():
buying_cost_center, selling_cost_center, expense_account, income_account, default_supplier
FROM `tabItem`;
''', companies[0].name)
- except:
+ except Exception:
pass
else:
item_details = frappe.db.sql(""" SELECT name, default_warehouse,
diff --git a/erpnext/patches/v11_0/move_leave_approvers_from_employee.py b/erpnext/patches/v11_0/move_leave_approvers_from_employee.py
index ef703d0ea71..accfa5ecb39 100644
--- a/erpnext/patches/v11_0/move_leave_approvers_from_employee.py
+++ b/erpnext/patches/v11_0/move_leave_approvers_from_employee.py
@@ -1,8 +1,9 @@
from __future__ import unicode_literals
+
import frappe
-from frappe import _
from frappe.model.utils.rename_field import rename_field
+
def execute():
frappe.reload_doc("hr", "doctype", "department_approver")
frappe.reload_doc("hr", "doctype", "employee")
diff --git a/erpnext/patches/v11_0/rebuild_tree_for_company.py b/erpnext/patches/v11_0/rebuild_tree_for_company.py
index 4cb74c7256c..6caca4730c2 100644
--- a/erpnext/patches/v11_0/rebuild_tree_for_company.py
+++ b/erpnext/patches/v11_0/rebuild_tree_for_company.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.utils.nestedset import rebuild_tree
+
def execute():
frappe.reload_doc("setup", "doctype", "company")
rebuild_tree('Company', 'parent_company')
diff --git a/erpnext/patches/v11_0/redesign_healthcare_billing_work_flow.py b/erpnext/patches/v11_0/redesign_healthcare_billing_work_flow.py
index 7c8a822fa22..b1ed0f598c6 100644
--- a/erpnext/patches/v11_0/redesign_healthcare_billing_work_flow.py
+++ b/erpnext/patches/v11_0/redesign_healthcare_billing_work_flow.py
@@ -1,8 +1,10 @@
from __future__ import unicode_literals
+
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+from frappe.modules import get_doctype_module, scrub
+
from erpnext.domains.healthcare import data
-from frappe.modules import scrub, get_doctype_module
sales_invoice_referenced_doc = {
"Patient Appointment": "sales_invoice",
diff --git a/erpnext/patches/v11_0/refactor_erpnext_shopify.py b/erpnext/patches/v11_0/refactor_erpnext_shopify.py
index 340e9fc8bf7..2add7211090 100644
--- a/erpnext/patches/v11_0/refactor_erpnext_shopify.py
+++ b/erpnext/patches/v11_0/refactor_erpnext_shopify.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.installer import remove_from_installed_apps
+
def execute():
frappe.reload_doc('erpnext_integrations', 'doctype', 'shopify_settings')
frappe.reload_doc('erpnext_integrations', 'doctype', 'shopify_tax_account')
diff --git a/erpnext/patches/v11_0/remove_barcodes_field_from_copy_fields_to_variants.py b/erpnext/patches/v11_0/remove_barcodes_field_from_copy_fields_to_variants.py
index 97ddd41ddb6..caf74f578de 100644
--- a/erpnext/patches/v11_0/remove_barcodes_field_from_copy_fields_to_variants.py
+++ b/erpnext/patches/v11_0/remove_barcodes_field_from_copy_fields_to_variants.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
'''Remove barcodes field from "Copy Fields to Variants" table because barcodes must be unique'''
diff --git a/erpnext/patches/v11_0/remove_modules_setup_page.py b/erpnext/patches/v11_0/remove_modules_setup_page.py
index bb0bdf59da1..eab3237878e 100644
--- a/erpnext/patches/v11_0/remove_modules_setup_page.py
+++ b/erpnext/patches/v11_0/remove_modules_setup_page.py
@@ -2,7 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.delete_doc("Page", "modules_setup")
diff --git a/erpnext/patches/v11_0/rename_additional_salary_component_additional_salary.py b/erpnext/patches/v11_0/rename_additional_salary_component_additional_salary.py
index 8eb70167447..5b2c2863f2f 100644
--- a/erpnext/patches/v11_0/rename_additional_salary_component_additional_salary.py
+++ b/erpnext/patches/v11_0/rename_additional_salary_component_additional_salary.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
import frappe
# this patch should have been included with this PR https://github.com/frappe/erpnext/pull/14302
diff --git a/erpnext/patches/v11_0/rename_asset_adjustment_doctype.py b/erpnext/patches/v11_0/rename_asset_adjustment_doctype.py
index 923b23048df..707dff75e24 100644
--- a/erpnext/patches/v11_0/rename_asset_adjustment_doctype.py
+++ b/erpnext/patches/v11_0/rename_asset_adjustment_doctype.py
@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
diff --git a/erpnext/patches/v11_0/rename_bom_wo_fields.py b/erpnext/patches/v11_0/rename_bom_wo_fields.py
index 0e6036b0740..4ad6ea9999d 100644
--- a/erpnext/patches/v11_0/rename_bom_wo_fields.py
+++ b/erpnext/patches/v11_0/rename_bom_wo_fields.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
# updating column value to handle field change from Data to Currency
changed_field = "base_scrap_material_cost"
diff --git a/erpnext/patches/v11_0/rename_duplicate_item_code_values.py b/erpnext/patches/v11_0/rename_duplicate_item_code_values.py
index 00ab562c353..61f3856e8eb 100644
--- a/erpnext/patches/v11_0/rename_duplicate_item_code_values.py
+++ b/erpnext/patches/v11_0/rename_duplicate_item_code_values.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
items = []
items = frappe.db.sql("""select item_code from `tabItem` group by item_code having count(*) > 1""", as_dict=True)
diff --git a/erpnext/patches/v11_0/rename_field_max_days_allowed.py b/erpnext/patches/v11_0/rename_field_max_days_allowed.py
index 4e99fac8224..48f73fb2f41 100644
--- a/erpnext/patches/v11_0/rename_field_max_days_allowed.py
+++ b/erpnext/patches/v11_0/rename_field_max_days_allowed.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
frappe.db.sql("""
UPDATE `tabLeave Type`
diff --git a/erpnext/patches/v11_0/rename_health_insurance.py b/erpnext/patches/v11_0/rename_health_insurance.py
index 06fc6151675..a4f53b078e1 100644
--- a/erpnext/patches/v11_0/rename_health_insurance.py
+++ b/erpnext/patches/v11_0/rename_health_insurance.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.rename_doc('DocType', 'Health Insurance', 'Employee Health Insurance', force=True)
frappe.reload_doc('hr', 'doctype', 'employee_health_insurance')
diff --git a/erpnext/patches/v11_0/rename_healthcare_doctype_and_fields.py b/erpnext/patches/v11_0/rename_healthcare_doctype_and_fields.py
index 9705681b33f..7a8c52f102f 100644
--- a/erpnext/patches/v11_0/rename_healthcare_doctype_and_fields.py
+++ b/erpnext/patches/v11_0/rename_healthcare_doctype_and_fields.py
@@ -1,7 +1,8 @@
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
-from frappe.modules import scrub, get_doctype_module
+from frappe.modules import get_doctype_module, scrub
field_rename_map = {
"Patient Encounter": [
diff --git a/erpnext/patches/v11_0/rename_healthcare_fields.py b/erpnext/patches/v11_0/rename_healthcare_fields.py
index 9aeb433cff8..5c96367a737 100644
--- a/erpnext/patches/v11_0/rename_healthcare_fields.py
+++ b/erpnext/patches/v11_0/rename_healthcare_fields.py
@@ -1,7 +1,8 @@
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
-from frappe.modules import scrub, get_doctype_module
+from frappe.modules import get_doctype_module, scrub
lab_test_name = ["test_name", "lab_test_name"]
lab_test_code = ["test_code", "lab_test_code"]
diff --git a/erpnext/patches/v11_0/rename_members_with_naming_series.py b/erpnext/patches/v11_0/rename_members_with_naming_series.py
index 84f5518926f..a3d7970aa1f 100644
--- a/erpnext/patches/v11_0/rename_members_with_naming_series.py
+++ b/erpnext/patches/v11_0/rename_members_with_naming_series.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("non_profit", "doctype", "member")
old_named_members = frappe.get_all("Member", filters = {"name": ("not like", "MEM-%")})
diff --git a/erpnext/patches/v11_0/rename_overproduction_percent_field.py b/erpnext/patches/v11_0/rename_overproduction_percent_field.py
index fbf925d955c..c7124af2e45 100644
--- a/erpnext/patches/v11_0/rename_overproduction_percent_field.py
+++ b/erpnext/patches/v11_0/rename_overproduction_percent_field.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-from frappe.model.utils.rename_field import rename_field
+
import frappe
+from frappe.model.utils.rename_field import rename_field
+
def execute():
frappe.reload_doc('manufacturing', 'doctype', 'manufacturing_settings')
diff --git a/erpnext/patches/v11_0/rename_production_order_to_work_order.py b/erpnext/patches/v11_0/rename_production_order_to_work_order.py
index 2f620f413ba..995f1affe4e 100644
--- a/erpnext/patches/v11_0/rename_production_order_to_work_order.py
+++ b/erpnext/patches/v11_0/rename_production_order_to_work_order.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
frappe.rename_doc('DocType', 'Production Order', 'Work Order', force=True)
frappe.reload_doc('manufacturing', 'doctype', 'work_order')
diff --git a/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py b/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py
index c4b3838c71d..2e53fb832fe 100644
--- a/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py
+++ b/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py
@@ -1,9 +1,11 @@
from __future__ import unicode_literals
+
import frappe
-from frappe.model.utils.rename_field import rename_field
from frappe import _
+from frappe.model.utils.rename_field import rename_field
from frappe.utils.nestedset import rebuild_tree
+
def execute():
if frappe.db.table_exists("Supplier Group"):
frappe.reload_doc('setup', 'doctype', 'supplier_group')
diff --git a/erpnext/patches/v11_0/renamed_from_to_fields_in_project.py b/erpnext/patches/v11_0/renamed_from_to_fields_in_project.py
index d5ca4cc5749..894aaee5f0b 100644
--- a/erpnext/patches/v11_0/renamed_from_to_fields_in_project.py
+++ b/erpnext/patches/v11_0/renamed_from_to_fields_in_project.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
frappe.reload_doc('projects', 'doctype', 'project')
diff --git a/erpnext/patches/v11_0/reset_publish_in_hub_for_all_items.py b/erpnext/patches/v11_0/reset_publish_in_hub_for_all_items.py
index 56e95e03286..a664baf6dd6 100644
--- a/erpnext/patches/v11_0/reset_publish_in_hub_for_all_items.py
+++ b/erpnext/patches/v11_0/reset_publish_in_hub_for_all_items.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('stock', 'doctype', 'item')
frappe.db.sql("""update `tabItem` set publish_in_hub = 0""")
diff --git a/erpnext/patches/v11_0/set_default_email_template_in_hr.py b/erpnext/patches/v11_0/set_default_email_template_in_hr.py
index 46223761095..ff754247fba 100644
--- a/erpnext/patches/v11_0/set_default_email_template_in_hr.py
+++ b/erpnext/patches/v11_0/set_default_email_template_in_hr.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
-from frappe import _
+
import frappe
+from frappe import _
+
def execute():
hr_settings = frappe.get_single("HR Settings")
diff --git a/erpnext/patches/v11_0/set_department_for_doctypes.py b/erpnext/patches/v11_0/set_department_for_doctypes.py
index 175d2a189f3..c9699655db3 100644
--- a/erpnext/patches/v11_0/set_department_for_doctypes.py
+++ b/erpnext/patches/v11_0/set_department_for_doctypes.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
import frappe
# Set department value based on employee value
diff --git a/erpnext/patches/v11_0/set_missing_gst_hsn_code.py b/erpnext/patches/v11_0/set_missing_gst_hsn_code.py
index 8f8a545c410..7a0a9890252 100644
--- a/erpnext/patches/v11_0/set_missing_gst_hsn_code.py
+++ b/erpnext/patches/v11_0/set_missing_gst_hsn_code.py
@@ -1,7 +1,10 @@
from __future__ import unicode_literals
+
import frappe
+
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_html
+
def execute():
company = frappe.db.sql_list("select name from tabCompany where country = 'India'")
if not company:
diff --git a/erpnext/patches/v11_0/set_salary_component_properties.py b/erpnext/patches/v11_0/set_salary_component_properties.py
index d8ce31f3076..b70dc357aa7 100644
--- a/erpnext/patches/v11_0/set_salary_component_properties.py
+++ b/erpnext/patches/v11_0/set_salary_component_properties.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('Payroll', 'doctype', 'salary_detail')
frappe.reload_doc('Payroll', 'doctype', 'salary_component')
diff --git a/erpnext/patches/v11_0/set_update_field_and_value_in_workflow_state.py b/erpnext/patches/v11_0/set_update_field_and_value_in_workflow_state.py
index d0cabb38359..da4d4bd943a 100644
--- a/erpnext/patches/v11_0/set_update_field_and_value_in_workflow_state.py
+++ b/erpnext/patches/v11_0/set_update_field_and_value_in_workflow_state.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.model.workflow import get_workflow_name
+
def execute():
for doctype in ['Expense Claim', 'Leave Application']:
diff --git a/erpnext/patches/v11_0/set_user_permissions_for_department.py b/erpnext/patches/v11_0/set_user_permissions_for_department.py
index 2f90f14db3e..7840d5e0feb 100644
--- a/erpnext/patches/v11_0/set_user_permissions_for_department.py
+++ b/erpnext/patches/v11_0/set_user_permissions_for_department.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
user_permissions = frappe.db.sql("""select name, for_value from `tabUser Permission`
where allow='Department'""", as_dict=1)
diff --git a/erpnext/patches/v11_0/skip_user_permission_check_for_department.py b/erpnext/patches/v11_0/skip_user_permission_check_for_department.py
index 4e72917547b..66d1b6b40ab 100644
--- a/erpnext/patches/v11_0/skip_user_permission_check_for_department.py
+++ b/erpnext/patches/v11_0/skip_user_permission_check_for_department.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
import frappe
from frappe.desk.form.linked_with import get_linked_doctypes
diff --git a/erpnext/patches/v11_0/uom_conversion_data.py b/erpnext/patches/v11_0/uom_conversion_data.py
index 91470b3558a..a408d86b9a7 100644
--- a/erpnext/patches/v11_0/uom_conversion_data.py
+++ b/erpnext/patches/v11_0/uom_conversion_data.py
@@ -1,5 +1,7 @@
from __future__ import unicode_literals
-import frappe, json
+
+import frappe
+
def execute():
from erpnext.setup.setup_wizard.operations.install_fixtures import add_uom_data
diff --git a/erpnext/patches/v11_0/update_account_type_in_party_type.py b/erpnext/patches/v11_0/update_account_type_in_party_type.py
index dabaeffc94a..e51874f48a0 100644
--- a/erpnext/patches/v11_0/update_account_type_in_party_type.py
+++ b/erpnext/patches/v11_0/update_account_type_in_party_type.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('setup', 'doctype', 'party_type')
party_types = {'Customer': 'Receivable', 'Supplier': 'Payable',
diff --git a/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py b/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py
index 799e91a3e22..bfcfc9f6f44 100644
--- a/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py
+++ b/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('stock', 'doctype', 'item')
frappe.db.sql(""" update `tabItem` set include_item_in_manufacturing = 1
diff --git a/erpnext/patches/v11_0/update_backflush_subcontract_rm_based_on_bom.py b/erpnext/patches/v11_0/update_backflush_subcontract_rm_based_on_bom.py
index 37a616c7021..c3b18bd9817 100644
--- a/erpnext/patches/v11_0/update_backflush_subcontract_rm_based_on_bom.py
+++ b/erpnext/patches/v11_0/update_backflush_subcontract_rm_based_on_bom.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('buying', 'doctype', 'buying_settings')
frappe.db.set_value('Buying Settings', None, 'backflush_raw_materials_of_subcontract_based_on', 'BOM')
diff --git a/erpnext/patches/v11_0/update_brand_in_item_price.py b/erpnext/patches/v11_0/update_brand_in_item_price.py
index 977d84fefe8..a489378895d 100644
--- a/erpnext/patches/v11_0/update_brand_in_item_price.py
+++ b/erpnext/patches/v11_0/update_brand_in_item_price.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('stock', 'doctype', 'item_price')
diff --git a/erpnext/patches/v11_0/update_delivery_trip_status.py b/erpnext/patches/v11_0/update_delivery_trip_status.py
index 42f017e04d2..da259582747 100755
--- a/erpnext/patches/v11_0/update_delivery_trip_status.py
+++ b/erpnext/patches/v11_0/update_delivery_trip_status.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('setup', 'doctype', 'global_defaults', force=True)
frappe.reload_doc('stock', 'doctype', 'delivery_trip')
diff --git a/erpnext/patches/v11_0/update_department_lft_rgt.py b/erpnext/patches/v11_0/update_department_lft_rgt.py
index 2b382037109..f7ecf6e4523 100644
--- a/erpnext/patches/v11_0/update_department_lft_rgt.py
+++ b/erpnext/patches/v11_0/update_department_lft_rgt.py
@@ -4,6 +4,7 @@ import frappe
from frappe import _
from frappe.utils.nestedset import rebuild_tree
+
def execute():
""" assign lft and rgt appropriately """
frappe.reload_doc("hr", "doctype", "department")
diff --git a/erpnext/patches/v11_0/update_hub_url.py b/erpnext/patches/v11_0/update_hub_url.py
index 6c6ca3c5c28..c89b9b50607 100644
--- a/erpnext/patches/v11_0/update_hub_url.py
+++ b/erpnext/patches/v11_0/update_hub_url.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('hub_node', 'doctype', 'Marketplace Settings')
frappe.db.set_value('Marketplace Settings', 'Marketplace Settings', 'marketplace_url', 'https://hubmarket.org')
diff --git a/erpnext/patches/v11_0/update_sales_partner_type.py b/erpnext/patches/v11_0/update_sales_partner_type.py
index b393926b237..1369805349d 100644
--- a/erpnext/patches/v11_0/update_sales_partner_type.py
+++ b/erpnext/patches/v11_0/update_sales_partner_type.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute():
from erpnext.setup.setup_wizard.operations.install_fixtures import default_sales_partner_type
diff --git a/erpnext/patches/v11_0/update_total_qty_field.py b/erpnext/patches/v11_0/update_total_qty_field.py
index 9407256acfa..e79a5f9e6bc 100644
--- a/erpnext/patches/v11_0/update_total_qty_field.py
+++ b/erpnext/patches/v11_0/update_total_qty_field.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('buying', 'doctype', 'purchase_order')
frappe.reload_doc('buying', 'doctype', 'supplier_quotation')
diff --git a/erpnext/patches/v11_1/delete_bom_browser.py b/erpnext/patches/v11_1/delete_bom_browser.py
index 2892674d374..aad3df267c8 100644
--- a/erpnext/patches/v11_1/delete_bom_browser.py
+++ b/erpnext/patches/v11_1/delete_bom_browser.py
@@ -2,7 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.delete_doc_if_exists('Page', 'bom-browser')
diff --git a/erpnext/patches/v11_1/delete_scheduling_tool.py b/erpnext/patches/v11_1/delete_scheduling_tool.py
index b7ad28a3fd6..56d0dbf1a1f 100644
--- a/erpnext/patches/v11_1/delete_scheduling_tool.py
+++ b/erpnext/patches/v11_1/delete_scheduling_tool.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
if frappe.db.exists("DocType", "Scheduling Tool"):
frappe.delete_doc("DocType", "Scheduling Tool", ignore_permissions=True)
diff --git a/erpnext/patches/v11_1/make_job_card_time_logs.py b/erpnext/patches/v11_1/make_job_card_time_logs.py
index b706e5c1ffb..db0c3454c74 100644
--- a/erpnext/patches/v11_1/make_job_card_time_logs.py
+++ b/erpnext/patches/v11_1/make_job_card_time_logs.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('manufacturing', 'doctype', 'job_card_time_log')
diff --git a/erpnext/patches/v11_1/move_customer_lead_to_dynamic_column.py b/erpnext/patches/v11_1/move_customer_lead_to_dynamic_column.py
index fc3ec74083a..9ea6cd82c9c 100644
--- a/erpnext/patches/v11_1/move_customer_lead_to_dynamic_column.py
+++ b/erpnext/patches/v11_1/move_customer_lead_to_dynamic_column.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doctype("Quotation")
frappe.db.sql(""" UPDATE `tabQuotation` set party_name = lead WHERE quotation_to = 'Lead' """)
diff --git a/erpnext/patches/v11_1/rename_depends_on_lwp.py b/erpnext/patches/v11_1/rename_depends_on_lwp.py
index 4c4b14fd4e7..95a8225832c 100644
--- a/erpnext/patches/v11_1/rename_depends_on_lwp.py
+++ b/erpnext/patches/v11_1/rename_depends_on_lwp.py
@@ -2,10 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import scrub
from frappe.model.utils.rename_field import rename_field
+
def execute():
for doctype in ("Salary Component", "Salary Detail"):
if "depends_on_lwp" in frappe.db.get_table_columns(doctype):
diff --git a/erpnext/patches/v11_1/renamed_delayed_item_report.py b/erpnext/patches/v11_1/renamed_delayed_item_report.py
index 8e8725c8af6..21285637c4e 100644
--- a/erpnext/patches/v11_1/renamed_delayed_item_report.py
+++ b/erpnext/patches/v11_1/renamed_delayed_item_report.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
for report in ["Delayed Order Item Summary", "Delayed Order Summary"]:
if frappe.db.exists("Report", report):
diff --git a/erpnext/patches/v11_1/set_default_action_for_quality_inspection.py b/erpnext/patches/v11_1/set_default_action_for_quality_inspection.py
index b13239f7d12..4325490c793 100644
--- a/erpnext/patches/v11_1/set_default_action_for_quality_inspection.py
+++ b/erpnext/patches/v11_1/set_default_action_for_quality_inspection.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
stock_settings = frappe.get_doc('Stock Settings')
if stock_settings.default_warehouse and not frappe.db.exists("Warehouse", stock_settings.default_warehouse):
diff --git a/erpnext/patches/v11_1/set_missing_opportunity_from.py b/erpnext/patches/v11_1/set_missing_opportunity_from.py
index cb444b2e5dd..6569200a14c 100644
--- a/erpnext/patches/v11_1/set_missing_opportunity_from.py
+++ b/erpnext/patches/v11_1/set_missing_opportunity_from.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doctype("Opportunity")
diff --git a/erpnext/patches/v11_1/set_missing_title_for_quotation.py b/erpnext/patches/v11_1/set_missing_title_for_quotation.py
index e2ef3433d3e..93d9f0e7d89 100644
--- a/erpnext/patches/v11_1/set_missing_title_for_quotation.py
+++ b/erpnext/patches/v11_1/set_missing_title_for_quotation.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
frappe.reload_doctype("Quotation")
# update customer_name from Customer document if quotation_to is set to Customer
diff --git a/erpnext/patches/v11_1/set_salary_details_submittable.py b/erpnext/patches/v11_1/set_salary_details_submittable.py
index 6d847ec3d05..4a4cf302575 100644
--- a/erpnext/patches/v11_1/set_salary_details_submittable.py
+++ b/erpnext/patches/v11_1/set_salary_details_submittable.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.db.sql("""
update `tabSalary Structure` ss, `tabSalary Detail` sd
diff --git a/erpnext/patches/v11_1/set_status_for_material_request_type_manufacture.py b/erpnext/patches/v11_1/set_status_for_material_request_type_manufacture.py
index ec01fbb642e..64db97e92bc 100644
--- a/erpnext/patches/v11_1/set_status_for_material_request_type_manufacture.py
+++ b/erpnext/patches/v11_1/set_status_for_material_request_type_manufacture.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.db.sql("""
update `tabMaterial Request`
diff --git a/erpnext/patches/v11_1/set_variant_based_on.py b/erpnext/patches/v11_1/set_variant_based_on.py
index 49a9a177246..b69767d7ea4 100644
--- a/erpnext/patches/v11_1/set_variant_based_on.py
+++ b/erpnext/patches/v11_1/set_variant_based_on.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.db.sql("""update tabItem set variant_based_on = 'Item Attribute'
where ifnull(variant_based_on, '') = ''
diff --git a/erpnext/patches/v11_1/setup_guardian_role.py b/erpnext/patches/v11_1/setup_guardian_role.py
index 6ccfed9617c..bb33f19e9cf 100644
--- a/erpnext/patches/v11_1/setup_guardian_role.py
+++ b/erpnext/patches/v11_1/setup_guardian_role.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
if 'Education' in frappe.get_active_domains() and not frappe.db.exists("Role", "Guardian"):
doc = frappe.new_doc("Role")
diff --git a/erpnext/patches/v11_1/update_bank_transaction_status.py b/erpnext/patches/v11_1/update_bank_transaction_status.py
index 354e636c9b0..33007afcd8c 100644
--- a/erpnext/patches/v11_1/update_bank_transaction_status.py
+++ b/erpnext/patches/v11_1/update_bank_transaction_status.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("accounts", "doctype", "bank_transaction")
diff --git a/erpnext/patches/v11_1/update_default_supplier_in_item_defaults.py b/erpnext/patches/v11_1/update_default_supplier_in_item_defaults.py
index 8c360ad9353..22dabae7d2e 100644
--- a/erpnext/patches/v11_1/update_default_supplier_in_item_defaults.py
+++ b/erpnext/patches/v11_1/update_default_supplier_in_item_defaults.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
'''
default supplier was not set in the item defaults for multi company instance,
diff --git a/erpnext/patches/v11_1/woocommerce_set_creation_user.py b/erpnext/patches/v11_1/woocommerce_set_creation_user.py
index 074b904002c..e7218b1ade5 100644
--- a/erpnext/patches/v11_1/woocommerce_set_creation_user.py
+++ b/erpnext/patches/v11_1/woocommerce_set_creation_user.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.utils import cint
+
def execute():
frappe.reload_doc("erpnext_integrations", "doctype","woocommerce_settings")
doc = frappe.get_doc("Woocommerce Settings")
diff --git a/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py b/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
index 712eb4f61c2..98e7d1db7a6 100644
--- a/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
+++ b/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
diff --git a/erpnext/patches/v12_0/add_default_buying_selling_terms_in_company.py b/erpnext/patches/v12_0/add_default_buying_selling_terms_in_company.py
index 855d21dd992..384a1f5022a 100644
--- a/erpnext/patches/v12_0/add_default_buying_selling_terms_in_company.py
+++ b/erpnext/patches/v12_0/add_default_buying_selling_terms_in_company.py
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
frappe.reload_doc("setup", "doctype", "company")
if frappe.db.has_column('Company', 'default_terms'):
diff --git a/erpnext/patches/v12_0/add_document_type_field_for_italy_einvoicing.py b/erpnext/patches/v12_0/add_document_type_field_for_italy_einvoicing.py
index 6fe578dbd95..7f39dfef59d 100644
--- a/erpnext/patches/v12_0/add_document_type_field_for_italy_einvoicing.py
+++ b/erpnext/patches/v12_0/add_document_type_field_for_italy_einvoicing.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
-from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'Italy'})
diff --git a/erpnext/patches/v12_0/add_einvoice_status_field.py b/erpnext/patches/v12_0/add_einvoice_status_field.py
index 2dfd30714c8..aeff9ca8413 100644
--- a/erpnext/patches/v12_0/add_einvoice_status_field.py
+++ b/erpnext/patches/v12_0/add_einvoice_status_field.py
@@ -1,8 +1,11 @@
from __future__ import unicode_literals
+
import json
+
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
diff --git a/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py b/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py
index c1c11e26006..e837786138f 100644
--- a/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py
+++ b/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
diff --git a/erpnext/patches/v12_0/add_eway_bill_in_delivery_note.py b/erpnext/patches/v12_0/add_eway_bill_in_delivery_note.py
index cf1ed3676bf..973da895623 100644
--- a/erpnext/patches/v12_0/add_eway_bill_in_delivery_note.py
+++ b/erpnext/patches/v12_0/add_eway_bill_in_delivery_note.py
@@ -1,6 +1,7 @@
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
diff --git a/erpnext/patches/v12_0/add_ewaybill_validity_field.py b/erpnext/patches/v12_0/add_ewaybill_validity_field.py
index f29b71437e8..247140d21d0 100644
--- a/erpnext/patches/v12_0/add_ewaybill_validity_field.py
+++ b/erpnext/patches/v12_0/add_ewaybill_validity_field.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
diff --git a/erpnext/patches/v12_0/add_export_type_field_in_party_master.py b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py
index a0b1f87d61b..e05c8211c03 100644
--- a/erpnext/patches/v12_0/add_export_type_field_in_party_master.py
+++ b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py
@@ -1,7 +1,10 @@
from __future__ import unicode_literals
+
import frappe
+
from erpnext.regional.india.setup import make_custom_fields
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
diff --git a/erpnext/patches/v12_0/add_gst_category_in_delivery_note.py b/erpnext/patches/v12_0/add_gst_category_in_delivery_note.py
index c90819238c8..30e47cb333c 100644
--- a/erpnext/patches/v12_0/add_gst_category_in_delivery_note.py
+++ b/erpnext/patches/v12_0/add_gst_category_in_delivery_note.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
diff --git a/erpnext/patches/v12_0/add_permission_in_lower_deduction.py b/erpnext/patches/v12_0/add_permission_in_lower_deduction.py
index 2e42368b152..1d77e5ad3d1 100644
--- a/erpnext/patches/v12_0/add_permission_in_lower_deduction.py
+++ b/erpnext/patches/v12_0/add_permission_in_lower_deduction.py
@@ -1,6 +1,7 @@
import frappe
from frappe.permissions import add_permission, update_permission_property
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
diff --git a/erpnext/patches/v12_0/add_state_code_for_ladakh.py b/erpnext/patches/v12_0/add_state_code_for_ladakh.py
index 29a7b4bd602..6722b7bcef0 100644
--- a/erpnext/patches/v12_0/add_state_code_for_ladakh.py
+++ b/erpnext/patches/v12_0/add_state_code_for_ladakh.py
@@ -1,6 +1,8 @@
import frappe
+
from erpnext.regional.india import states
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
diff --git a/erpnext/patches/v12_0/add_taxjar_integration_field.py b/erpnext/patches/v12_0/add_taxjar_integration_field.py
index 4c823e13bdf..d10a6d79f29 100644
--- a/erpnext/patches/v12_0/add_taxjar_integration_field.py
+++ b/erpnext/patches/v12_0/add_taxjar_integration_field.py
@@ -1,6 +1,7 @@
from __future__ import unicode_literals
import frappe
+
from erpnext.regional.united_states.setup import make_custom_fields
diff --git a/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py b/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py
index 893f7a4909e..c3a422c49e5 100644
--- a/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py
+++ b/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
frappe.reload_doc('stock', 'doctype', 'item_variant_attribute')
frappe.db.sql('''
diff --git a/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py b/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
index f171542df16..02fbe62837a 100644
--- a/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
+++ b/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+
def execute():
frappe.reload_doc('accounts', 'doctype', 'accounting_dimension')
diff --git a/erpnext/patches/v12_0/create_default_energy_point_rules.py b/erpnext/patches/v12_0/create_default_energy_point_rules.py
index 93d2576bb6d..35eaca7f400 100644
--- a/erpnext/patches/v12_0/create_default_energy_point_rules.py
+++ b/erpnext/patches/v12_0/create_default_energy_point_rules.py
@@ -1,6 +1,8 @@
import frappe
+
from erpnext.setup.install import create_default_energy_point_rules
+
def execute():
frappe.reload_doc('social', 'doctype', 'energy_point_rule')
create_default_energy_point_rules()
diff --git a/erpnext/patches/v12_0/create_irs_1099_field_united_states.py b/erpnext/patches/v12_0/create_irs_1099_field_united_states.py
index 23a8f24d780..65265c4c8e8 100644
--- a/erpnext/patches/v12_0/create_irs_1099_field_united_states.py
+++ b/erpnext/patches/v12_0/create_irs_1099_field_united_states.py
@@ -1,7 +1,10 @@
from __future__ import unicode_literals
+
import frappe
+
from erpnext.regional.united_states.setup import make_custom_fields
+
def execute():
frappe.reload_doc('accounts', 'doctype', 'allowed_to_transact_with', force=True)
diff --git a/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py b/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py
index a6230f42771..9267ebffb27 100644
--- a/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py
+++ b/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py
@@ -1,9 +1,12 @@
from __future__ import unicode_literals
+
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
+
from erpnext.regional.india.utils import get_gst_accounts
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'}, fields=['name'])
if not company:
diff --git a/erpnext/patches/v12_0/create_taxable_value_field.py b/erpnext/patches/v12_0/create_taxable_value_field.py
index b9ee81df50e..40de8d8aef2 100644
--- a/erpnext/patches/v12_0/create_taxable_value_field.py
+++ b/erpnext/patches/v12_0/create_taxable_value_field.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
diff --git a/erpnext/patches/v12_0/delete_priority_property_setter.py b/erpnext/patches/v12_0/delete_priority_property_setter.py
index 163855729df..cacc463d4b4 100644
--- a/erpnext/patches/v12_0/delete_priority_property_setter.py
+++ b/erpnext/patches/v12_0/delete_priority_property_setter.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
frappe.db.sql("""
DELETE FROM `tabProperty Setter`
diff --git a/erpnext/patches/v12_0/fix_percent_complete_for_projects.py b/erpnext/patches/v12_0/fix_percent_complete_for_projects.py
index 3622df6bc81..36f51bca60d 100644
--- a/erpnext/patches/v12_0/fix_percent_complete_for_projects.py
+++ b/erpnext/patches/v12_0/fix_percent_complete_for_projects.py
@@ -1,6 +1,7 @@
import frappe
from frappe.utils import flt
+
def execute():
for project in frappe.get_all("Project", fields=["name", "percent_complete_method"]):
total = frappe.db.count('Task', dict(project=project.name))
diff --git a/erpnext/patches/v12_0/fix_quotation_expired_status.py b/erpnext/patches/v12_0/fix_quotation_expired_status.py
index ac7e82d2d0d..e5c4b8c524f 100644
--- a/erpnext/patches/v12_0/fix_quotation_expired_status.py
+++ b/erpnext/patches/v12_0/fix_quotation_expired_status.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
# fixes status of quotations which have status 'Expired' despite having valid sales order created
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index fe072d7eb96..aed56d621b8 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.utils import getdate, today
+
def execute():
""" Generates leave ledger entries for leave allocation/application/encashment
for last allocation """
diff --git a/erpnext/patches/v12_0/make_item_manufacturer.py b/erpnext/patches/v12_0/make_item_manufacturer.py
index ebc28320aea..cfc2472e9e2 100644
--- a/erpnext/patches/v12_0/make_item_manufacturer.py
+++ b/erpnext/patches/v12_0/make_item_manufacturer.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("stock", "doctype", "item_manufacturer")
diff --git a/erpnext/patches/v12_0/move_bank_account_swift_number_to_bank.py b/erpnext/patches/v12_0/move_bank_account_swift_number_to_bank.py
index a670adebfd6..3e9d429ed18 100644
--- a/erpnext/patches/v12_0/move_bank_account_swift_number_to_bank.py
+++ b/erpnext/patches/v12_0/move_bank_account_swift_number_to_bank.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('accounts', 'doctype', 'bank', force=1)
diff --git a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
index c9293b9b63c..2662632b52b 100644
--- a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
+++ b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
''' Move credit limit and bypass credit limit to the child table of customer credit limit '''
frappe.reload_doc("Selling", "doctype", "Customer Credit Limit")
diff --git a/erpnext/patches/v12_0/move_due_advance_amount_to_pending_amount.py b/erpnext/patches/v12_0/move_due_advance_amount_to_pending_amount.py
index 6013eaa29c6..55f5cd52a35 100644
--- a/erpnext/patches/v12_0/move_due_advance_amount_to_pending_amount.py
+++ b/erpnext/patches/v12_0/move_due_advance_amount_to_pending_amount.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
''' Move from due_advance_amount to pending_amount '''
diff --git a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
index 5c3fa5991c9..677a564af0d 100644
--- a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
+++ b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
@@ -1,7 +1,9 @@
-import frappe
import json
-from six import iteritems
+
+import frappe
from frappe.model.naming import make_autoname
+from six import iteritems
+
def execute():
if "tax_type" not in frappe.db.get_table_columns("Item Tax"):
diff --git a/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py b/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py
index d2bcb12070c..dafea280c28 100644
--- a/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py
+++ b/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py
@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
diff --git a/erpnext/patches/v12_0/move_target_distribution_from_parent_to_child.py b/erpnext/patches/v12_0/move_target_distribution_from_parent_to_child.py
index 97badf355d9..72f4df5cabc 100644
--- a/erpnext/patches/v12_0/move_target_distribution_from_parent_to_child.py
+++ b/erpnext/patches/v12_0/move_target_distribution_from_parent_to_child.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("setup", "doctype", "target_detail")
diff --git a/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py b/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py
index 46794bebe70..a19e9a96dba 100644
--- a/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py
+++ b/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py
@@ -1,6 +1,9 @@
from __future__ import unicode_literals
+
import frappe
-from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty
+
+from erpnext.stock.stock_balance import get_indented_qty, update_bin_qty
+
def execute():
bin_details = frappe.db.sql("""
diff --git a/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py b/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py
index be884f94d15..fba41184159 100644
--- a/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py
+++ b/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py
@@ -1,6 +1,7 @@
from __future__ import unicode_literals
+
import frappe
-from erpnext.regional.india.setup import make_custom_fields
+
def execute():
frappe.reload_doc("accounts", "doctype", "tax_category")
diff --git a/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py b/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py
index 4fcffb702a4..f6a1984e17a 100644
--- a/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py
+++ b/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py
@@ -2,8 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import getdate, today
+
def execute():
''' Delete leave ledger entry created
diff --git a/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py b/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py
index 6b1b601db19..6fa1c04dad3 100644
--- a/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
"""Delete duplicate leave ledger entries of type allocation created."""
frappe.reload_doc('hr', 'doctype', 'leave_ledger_entry')
diff --git a/erpnext/patches/v12_0/remove_patient_medical_record_page.py b/erpnext/patches/v12_0/remove_patient_medical_record_page.py
index 904bfe4bf19..bf71c4810ff 100644
--- a/erpnext/patches/v12_0/remove_patient_medical_record_page.py
+++ b/erpnext/patches/v12_0/remove_patient_medical_record_page.py
@@ -1,7 +1,9 @@
# Copyright (c) 2019
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.delete_doc("Page", "medical_record")
diff --git a/erpnext/patches/v12_0/rename_account_type_doctype.py b/erpnext/patches/v12_0/rename_account_type_doctype.py
index 9a08ad45213..27357a8ef15 100644
--- a/erpnext/patches/v12_0/rename_account_type_doctype.py
+++ b/erpnext/patches/v12_0/rename_account_type_doctype.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.rename_doc('DocType', 'Account Type', 'Bank Account Type', force=True)
frappe.rename_doc('DocType', 'Account Subtype', 'Bank Account Subtype', force=True)
diff --git a/erpnext/patches/v12_0/rename_bank_account_field_in_journal_entry_account.py b/erpnext/patches/v12_0/rename_bank_account_field_in_journal_entry_account.py
index 7489ea30a09..7e02fff4d82 100644
--- a/erpnext/patches/v12_0/rename_bank_account_field_in_journal_entry_account.py
+++ b/erpnext/patches/v12_0/rename_bank_account_field_in_journal_entry_account.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
''' Change the fieldname from bank_account_no to bank_account '''
if not frappe.get_meta("Journal Entry Account").has_field("bank_account"):
diff --git a/erpnext/patches/v12_0/rename_bank_reconciliation.py b/erpnext/patches/v12_0/rename_bank_reconciliation.py
index 2efa854fba9..5c79ce2a81b 100644
--- a/erpnext/patches/v12_0/rename_bank_reconciliation.py
+++ b/erpnext/patches/v12_0/rename_bank_reconciliation.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
if frappe.db.table_exists("Bank Reconciliation"):
frappe.rename_doc('DocType', 'Bank Reconciliation', 'Bank Clearance', force=True)
diff --git a/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py b/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py
index 978b1c92b96..629cd5bda66 100644
--- a/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py
+++ b/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py
@@ -3,6 +3,7 @@
import frappe
+
def _rename_single_field(**kwargs):
count = frappe.db.sql("SELECT COUNT(*) FROM tabSingles WHERE doctype='{doctype}' AND field='{new_name}';".format(**kwargs))[0][0] #nosec
if count == 0:
diff --git a/erpnext/patches/v12_0/rename_lost_reason_detail.py b/erpnext/patches/v12_0/rename_lost_reason_detail.py
index c71b91c9256..337302a3c18 100644
--- a/erpnext/patches/v12_0/rename_lost_reason_detail.py
+++ b/erpnext/patches/v12_0/rename_lost_reason_detail.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
if frappe.db.exists("DocType", "Lost Reason Detail"):
frappe.reload_doc("crm", "doctype", "opportunity_lost_reason")
diff --git a/erpnext/patches/v12_0/rename_mws_settings_fields.py b/erpnext/patches/v12_0/rename_mws_settings_fields.py
index e08e3769153..d5bf38d204d 100644
--- a/erpnext/patches/v12_0/rename_mws_settings_fields.py
+++ b/erpnext/patches/v12_0/rename_mws_settings_fields.py
@@ -3,6 +3,7 @@
import frappe
+
def execute():
count = frappe.db.sql("SELECT COUNT(*) FROM `tabSingles` WHERE doctype='Amazon MWS Settings' AND field='enable_sync';")[0][0]
if count == 0:
diff --git a/erpnext/patches/v12_0/rename_pos_closing_doctype.py b/erpnext/patches/v12_0/rename_pos_closing_doctype.py
index 9d8626b8527..e6fb1f31e16 100644
--- a/erpnext/patches/v12_0/rename_pos_closing_doctype.py
+++ b/erpnext/patches/v12_0/rename_pos_closing_doctype.py
@@ -1,8 +1,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
if frappe.db.table_exists("POS Closing Voucher"):
if not frappe.db.exists("DocType", "POS Closing Entry"):
diff --git a/erpnext/patches/v12_0/rename_pricing_rule_child_doctypes.py b/erpnext/patches/v12_0/rename_pricing_rule_child_doctypes.py
index b9ad622b0ea..4bf3840b783 100644
--- a/erpnext/patches/v12_0/rename_pricing_rule_child_doctypes.py
+++ b/erpnext/patches/v12_0/rename_pricing_rule_child_doctypes.py
@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
doctypes = {
diff --git a/erpnext/patches/v12_0/rename_tolerance_fields.py b/erpnext/patches/v12_0/rename_tolerance_fields.py
index 20b096331ed..ca2427bc3dd 100644
--- a/erpnext/patches/v12_0/rename_tolerance_fields.py
+++ b/erpnext/patches/v12_0/rename_tolerance_fields.py
@@ -1,6 +1,7 @@
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
frappe.reload_doc("stock", "doctype", "item")
frappe.reload_doc("stock", "doctype", "stock_settings")
diff --git a/erpnext/patches/v12_0/replace_accounting_with_accounts_in_home_settings.py b/erpnext/patches/v12_0/replace_accounting_with_accounts_in_home_settings.py
index f88a22f6c9d..ff332f771d3 100644
--- a/erpnext/patches/v12_0/replace_accounting_with_accounts_in_home_settings.py
+++ b/erpnext/patches/v12_0/replace_accounting_with_accounts_in_home_settings.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
frappe.db.sql("""UPDATE `tabUser` SET `home_settings` = REPLACE(`home_settings`, 'Accounting', 'Accounts')""")
frappe.cache().delete_key('home_settings')
diff --git a/erpnext/patches/v12_0/repost_stock_ledger_entries_for_target_warehouse.py b/erpnext/patches/v12_0/repost_stock_ledger_entries_for_target_warehouse.py
index c52f380d8c2..5150430dbb9 100644
--- a/erpnext/patches/v12_0/repost_stock_ledger_entries_for_target_warehouse.py
+++ b/erpnext/patches/v12_0/repost_stock_ledger_entries_for_target_warehouse.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
warehouse_perm = frappe.get_all("User Permission",
fields=["count(*) as p_count", "is_default", "user"], filters={"allow": "Warehouse"}, group_by="user")
diff --git a/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py b/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py
index 85202bff4d6..b76e34abe13 100644
--- a/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py
+++ b/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
frappe.reload_doc('selling', 'doctype', 'sales_order_item', force=True)
diff --git a/erpnext/patches/v12_0/set_automatically_process_deferred_accounting_in_accounts_settings.py b/erpnext/patches/v12_0/set_automatically_process_deferred_accounting_in_accounts_settings.py
index b5d7e3dcb9e..849e96e9665 100644
--- a/erpnext/patches/v12_0/set_automatically_process_deferred_accounting_in_accounts_settings.py
+++ b/erpnext/patches/v12_0/set_automatically_process_deferred_accounting_in_accounts_settings.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("accounts", "doctype", "accounts_settings")
diff --git a/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py b/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py
index 4415cfeaba9..d3045a1a576 100644
--- a/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py
+++ b/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py
@@ -1,4 +1,6 @@
import frappe
+
+
def execute():
frappe.reload_doc('hr', 'doctype', 'expense_claim_detail')
frappe.db.sql("""
diff --git a/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py b/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py
index 13110dfe03f..e363c26a86f 100644
--- a/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py
+++ b/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
import frappe
from frappe.utils import cint
diff --git a/erpnext/patches/v12_0/set_default_homepage_type.py b/erpnext/patches/v12_0/set_default_homepage_type.py
index a290e31cf24..1e4333aa466 100644
--- a/erpnext/patches/v12_0/set_default_homepage_type.py
+++ b/erpnext/patches/v12_0/set_default_homepage_type.py
@@ -1,4 +1,5 @@
import frappe
+
def execute():
frappe.db.set_value('Homepage', 'Homepage', 'hero_section_based_on', 'Default')
diff --git a/erpnext/patches/v12_0/set_default_payroll_based_on.py b/erpnext/patches/v12_0/set_default_payroll_based_on.py
index 038bd6d21ae..85112f2a540 100644
--- a/erpnext/patches/v12_0/set_default_payroll_based_on.py
+++ b/erpnext/patches/v12_0/set_default_payroll_based_on.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("hr", "doctype", "hr_settings")
frappe.db.set_value("HR Settings", None, "payroll_based_on", "Leave")
diff --git a/erpnext/patches/v12_0/set_default_shopify_app_type.py b/erpnext/patches/v12_0/set_default_shopify_app_type.py
index 65958a25afd..621564a939d 100644
--- a/erpnext/patches/v12_0/set_default_shopify_app_type.py
+++ b/erpnext/patches/v12_0/set_default_shopify_app_type.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('erpnext_integrations', 'doctype', 'shopify_settings')
frappe.db.set_value('Shopify Settings', None, 'app_type', 'Private')
diff --git a/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py b/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py
index a27c7b24a8c..49b3bff0f82 100644
--- a/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py
+++ b/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from six import iteritems
+
def execute():
frappe.reload_doctype('Landed Cost Taxes and Charges')
diff --git a/erpnext/patches/v12_0/set_gst_category.py b/erpnext/patches/v12_0/set_gst_category.py
index cc093953bf4..094e2a3134b 100644
--- a/erpnext/patches/v12_0/set_gst_category.py
+++ b/erpnext/patches/v12_0/set_gst_category.py
@@ -1,6 +1,8 @@
import frappe
+
from erpnext.regional.india.setup import make_custom_fields
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
diff --git a/erpnext/patches/v12_0/set_italian_import_supplier_invoice_permissions.py b/erpnext/patches/v12_0/set_italian_import_supplier_invoice_permissions.py
index 8fdc73b8ff1..a991b3c15df 100644
--- a/erpnext/patches/v12_0/set_italian_import_supplier_invoice_permissions.py
+++ b/erpnext/patches/v12_0/set_italian_import_supplier_invoice_permissions.py
@@ -2,9 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
from erpnext.regional.italy.setup import add_permissions
+
def execute():
countries = frappe.get_all("Company", fields="country")
countries = [country["country"] for country in countries]
diff --git a/erpnext/patches/v12_0/set_multi_uom_in_rfq.py b/erpnext/patches/v12_0/set_multi_uom_in_rfq.py
index a5c8f7524a7..fada5f08fb0 100644
--- a/erpnext/patches/v12_0/set_multi_uom_in_rfq.py
+++ b/erpnext/patches/v12_0/set_multi_uom_in_rfq.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import flt
-from erpnext.stock.get_item_details import get_conversion_factor
+
def execute():
frappe.reload_doc('buying', 'doctype', 'request_for_quotation_item')
diff --git a/erpnext/patches/v12_0/set_payment_entry_status.py b/erpnext/patches/v12_0/set_payment_entry_status.py
index 84645a38639..f8792952d8b 100644
--- a/erpnext/patches/v12_0/set_payment_entry_status.py
+++ b/erpnext/patches/v12_0/set_payment_entry_status.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
frappe.reload_doctype("Payment Entry")
frappe.db.sql("""update `tabPayment Entry` set status = CASE
diff --git a/erpnext/patches/v12_0/set_permission_einvoicing.py b/erpnext/patches/v12_0/set_permission_einvoicing.py
index e2235105f94..01cab14db9d 100644
--- a/erpnext/patches/v12_0/set_permission_einvoicing.py
+++ b/erpnext/patches/v12_0/set_permission_einvoicing.py
@@ -1,7 +1,9 @@
import frappe
-from erpnext.regional.italy.setup import make_custom_fields
from frappe.permissions import add_permission, update_permission_property
+from erpnext.regional.italy.setup import make_custom_fields
+
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'Italy'})
diff --git a/erpnext/patches/v12_0/set_priority_for_support.py b/erpnext/patches/v12_0/set_priority_for_support.py
index 66696bee541..6d7d0993460 100644
--- a/erpnext/patches/v12_0/set_priority_for_support.py
+++ b/erpnext/patches/v12_0/set_priority_for_support.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
frappe.reload_doc("support", "doctype", "issue_priority")
frappe.reload_doc("support", "doctype", "service_level_priority")
diff --git a/erpnext/patches/v12_0/set_produced_qty_field_in_sales_order_for_work_order.py b/erpnext/patches/v12_0/set_produced_qty_field_in_sales_order_for_work_order.py
index 6c11cb415f9..9c851ddcee1 100644
--- a/erpnext/patches/v12_0/set_produced_qty_field_in_sales_order_for_work_order.py
+++ b/erpnext/patches/v12_0/set_produced_qty_field_in_sales_order_for_work_order.py
@@ -1,7 +1,8 @@
import frappe
-from frappe.utils import flt
+
from erpnext.selling.doctype.sales_order.sales_order import update_produced_qty_in_so_item
+
def execute():
frappe.reload_doctype('Sales Order Item')
frappe.reload_doctype('Sales Order')
diff --git a/erpnext/patches/v12_0/set_production_capacity_in_workstation.py b/erpnext/patches/v12_0/set_production_capacity_in_workstation.py
index babaebeaefc..248d33504e1 100644
--- a/erpnext/patches/v12_0/set_production_capacity_in_workstation.py
+++ b/erpnext/patches/v12_0/set_production_capacity_in_workstation.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("manufacturing", "doctype", "workstation")
diff --git a/erpnext/patches/v12_0/set_published_in_hub_tracked_item.py b/erpnext/patches/v12_0/set_published_in_hub_tracked_item.py
index e54c7f315c6..73c6ce8220e 100644
--- a/erpnext/patches/v12_0/set_published_in_hub_tracked_item.py
+++ b/erpnext/patches/v12_0/set_published_in_hub_tracked_item.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("Hub Node", "doctype", "Hub Tracked Item")
if not frappe.db.a_row_exists("Hub Tracked Item"):
diff --git a/erpnext/patches/v12_0/set_purchase_receipt_delivery_note_detail.py b/erpnext/patches/v12_0/set_purchase_receipt_delivery_note_detail.py
index 52c9a2d7b3c..cad947fadcd 100644
--- a/erpnext/patches/v12_0/set_purchase_receipt_delivery_note_detail.py
+++ b/erpnext/patches/v12_0/set_purchase_receipt_delivery_note_detail.py
@@ -1,7 +1,10 @@
from __future__ import unicode_literals
-import frappe
+
from collections import defaultdict
+import frappe
+
+
def execute():
frappe.reload_doc('stock', 'doctype', 'delivery_note_item', force=True)
diff --git a/erpnext/patches/v12_0/set_quotation_status.py b/erpnext/patches/v12_0/set_quotation_status.py
index 87643a23545..bb172769ebb 100644
--- a/erpnext/patches/v12_0/set_quotation_status.py
+++ b/erpnext/patches/v12_0/set_quotation_status.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.db.sql(""" UPDATE `tabQuotation` set status = 'Open'
diff --git a/erpnext/patches/v12_0/set_received_qty_in_material_request_as_per_stock_uom.py b/erpnext/patches/v12_0/set_received_qty_in_material_request_as_per_stock_uom.py
index 88c3e2e3024..f8b510e3c37 100644
--- a/erpnext/patches/v12_0/set_received_qty_in_material_request_as_per_stock_uom.py
+++ b/erpnext/patches/v12_0/set_received_qty_in_material_request_as_per_stock_uom.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
purchase_receipts = frappe.db.sql("""
SELECT
diff --git a/erpnext/patches/v12_0/set_serial_no_status.py b/erpnext/patches/v12_0/set_serial_no_status.py
index 3b5f5ef3407..9a05e707a65 100644
--- a/erpnext/patches/v12_0/set_serial_no_status.py
+++ b/erpnext/patches/v12_0/set_serial_no_status.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.utils import getdate, nowdate
+
def execute():
frappe.reload_doc('stock', 'doctype', 'serial_no')
diff --git a/erpnext/patches/v12_0/set_task_status.py b/erpnext/patches/v12_0/set_task_status.py
index dbd7e5a8181..1b4955a75be 100644
--- a/erpnext/patches/v12_0/set_task_status.py
+++ b/erpnext/patches/v12_0/set_task_status.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
frappe.reload_doctype('Task')
diff --git a/erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py b/erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py
index 1cc37caba42..21ee23b2072 100644
--- a/erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py
+++ b/erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
+
def execute():
frappe.reload_doc("stock", "doctype", "pick_list")
frappe.db.sql("""UPDATE `tabPick List` set purpose = 'Delivery'
diff --git a/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py b/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py
index 4a6e2288564..72d5521f44d 100644
--- a/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py
+++ b/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("buying", "doctype", "supplier_quotation")
frappe.db.sql("""UPDATE `tabSupplier Quotation`
diff --git a/erpnext/patches/v12_0/setup_einvoice_fields.py b/erpnext/patches/v12_0/setup_einvoice_fields.py
index 82b14fc9d60..c17666add18 100644
--- a/erpnext/patches/v12_0/setup_einvoice_fields.py
+++ b/erpnext/patches/v12_0/setup_einvoice_fields.py
@@ -1,8 +1,11 @@
from __future__ import unicode_literals
+
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
from erpnext.regional.india.setup import add_permissions, add_print_formats
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
diff --git a/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py b/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
index 2319c17b34c..3f90a03020f 100644
--- a/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
+++ b/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
diff --git a/erpnext/patches/v12_0/stock_entry_enhancements.py b/erpnext/patches/v12_0/stock_entry_enhancements.py
index 17fdcd9395a..b99501d942d 100644
--- a/erpnext/patches/v12_0/stock_entry_enhancements.py
+++ b/erpnext/patches/v12_0/stock_entry_enhancements.py
@@ -3,9 +3,11 @@
from __future__ import unicode_literals
+
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
def execute():
create_stock_entry_types()
diff --git a/erpnext/patches/v12_0/unhide_cost_center_field.py b/erpnext/patches/v12_0/unhide_cost_center_field.py
index 3474a34af4b..823dd226372 100644
--- a/erpnext/patches/v12_0/unhide_cost_center_field.py
+++ b/erpnext/patches/v12_0/unhide_cost_center_field.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.db.sql("""
DELETE FROM `tabProperty Setter`
diff --git a/erpnext/patches/v12_0/unset_customer_supplier_based_on_type_of_item_price.py b/erpnext/patches/v12_0/unset_customer_supplier_based_on_type_of_item_price.py
index b8efb210a03..61c4c601b55 100644
--- a/erpnext/patches/v12_0/unset_customer_supplier_based_on_type_of_item_price.py
+++ b/erpnext/patches/v12_0/unset_customer_supplier_based_on_type_of_item_price.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
import frappe
diff --git a/erpnext/patches/v12_0/update_address_template_for_india.py b/erpnext/patches/v12_0/update_address_template_for_india.py
index 0d582da4b5c..d41aae2a876 100644
--- a/erpnext/patches/v12_0/update_address_template_for_india.py
+++ b/erpnext/patches/v12_0/update_address_template_for_india.py
@@ -2,9 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
from erpnext.regional.address_template.setup import set_up_address_templates
+
def execute():
if frappe.db.get_value('Company', {'country': 'India'}, 'name'):
address_template = frappe.db.get_value('Address Template', 'India', 'template')
diff --git a/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py b/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py
index f4516649610..024cb2b7630 100644
--- a/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py
+++ b/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
job = frappe.db.exists('Scheduled Job Type', 'patient_appointment.send_appointment_reminder')
if job:
diff --git a/erpnext/patches/v12_0/update_bom_in_so_mr.py b/erpnext/patches/v12_0/update_bom_in_so_mr.py
index 8a871718133..283407567f2 100644
--- a/erpnext/patches/v12_0/update_bom_in_so_mr.py
+++ b/erpnext/patches/v12_0/update_bom_in_so_mr.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("stock", "doctype", "material_request_item")
frappe.reload_doc("selling", "doctype", "sales_order_item")
diff --git a/erpnext/patches/v12_0/update_due_date_in_gle.py b/erpnext/patches/v12_0/update_due_date_in_gle.py
index 34848725cec..60ad3251146 100644
--- a/erpnext/patches/v12_0/update_due_date_in_gle.py
+++ b/erpnext/patches/v12_0/update_due_date_in_gle.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("accounts", "doctype", "gl_entry")
diff --git a/erpnext/patches/v12_0/update_end_date_and_status_in_email_campaign.py b/erpnext/patches/v12_0/update_end_date_and_status_in_email_campaign.py
index c45f6221f93..208076b1496 100644
--- a/erpnext/patches/v12_0/update_end_date_and_status_in_email_campaign.py
+++ b/erpnext/patches/v12_0/update_end_date_and_status_in_email_campaign.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.utils import add_days, getdate, today
+
def execute():
if frappe.db.exists('DocType', 'Email Campaign'):
email_campaign = frappe.get_all('Email Campaign')
diff --git a/erpnext/patches/v12_0/update_ewaybill_field_position.py b/erpnext/patches/v12_0/update_ewaybill_field_position.py
index 9e5f599d2c8..520b5d04b4b 100644
--- a/erpnext/patches/v12_0/update_ewaybill_field_position.py
+++ b/erpnext/patches/v12_0/update_ewaybill_field_position.py
@@ -1,6 +1,7 @@
from __future__ import unicode_literals
+
import frappe
-from erpnext.regional.india.setup import make_custom_fields
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
diff --git a/erpnext/patches/v12_0/update_gst_category.py b/erpnext/patches/v12_0/update_gst_category.py
index 1a54216b885..bee89199316 100644
--- a/erpnext/patches/v12_0/update_gst_category.py
+++ b/erpnext/patches/v12_0/update_gst_category.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
diff --git a/erpnext/patches/v12_0/update_healthcare_refactored_changes.py b/erpnext/patches/v12_0/update_healthcare_refactored_changes.py
index d0b04433979..bfad3ddcba7 100644
--- a/erpnext/patches/v12_0/update_healthcare_refactored_changes.py
+++ b/erpnext/patches/v12_0/update_healthcare_refactored_changes.py
@@ -1,7 +1,8 @@
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
-from frappe.modules import scrub, get_doctype_module
+from frappe.modules import get_doctype_module, scrub
field_rename_map = {
'Healthcare Settings': [
diff --git a/erpnext/patches/v12_0/update_is_cancelled_field.py b/erpnext/patches/v12_0/update_is_cancelled_field.py
index 4bbec44aa42..3e7c37f0d19 100644
--- a/erpnext/patches/v12_0/update_is_cancelled_field.py
+++ b/erpnext/patches/v12_0/update_is_cancelled_field.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
try:
frappe.db.sql("UPDATE `tabStock Ledger Entry` SET is_cancelled = 0 where is_cancelled in ('', NULL, 'No')")
@@ -11,5 +13,5 @@ def execute():
frappe.reload_doc("stock", "doctype", "stock_ledger_entry")
frappe.reload_doc("stock", "doctype", "serial_no")
- except:
+ except Exception:
pass
diff --git a/erpnext/patches/v12_0/update_item_tax_template_company.py b/erpnext/patches/v12_0/update_item_tax_template_company.py
index e15894df890..3ad983d686f 100644
--- a/erpnext/patches/v12_0/update_item_tax_template_company.py
+++ b/erpnext/patches/v12_0/update_item_tax_template_company.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('accounts', 'doctype', 'item_tax_template')
diff --git a/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py b/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py
index 6ebaf48e0e8..09e2319eb80 100644
--- a/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py
+++ b/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py
@@ -1,6 +1,11 @@
from __future__ import unicode_literals
+
import frappe
-from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_doctypes_with_dimensions
+
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
+ get_doctypes_with_dimensions,
+)
+
def execute():
accounting_dimensions = frappe.db.sql("""select fieldname from
diff --git a/erpnext/patches/v12_0/update_price_list_currency_in_bom.py b/erpnext/patches/v12_0/update_price_list_currency_in_bom.py
index 09f07074299..e4c10089235 100644
--- a/erpnext/patches/v12_0/update_price_list_currency_in_bom.py
+++ b/erpnext/patches/v12_0/update_price_list_currency_in_bom.py
@@ -1,8 +1,11 @@
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import getdate, flt
+from frappe.utils import getdate
+
from erpnext.setup.utils import get_exchange_rate
+
def execute():
frappe.reload_doc("manufacturing", "doctype", "bom")
frappe.reload_doc("manufacturing", "doctype", "bom_item")
diff --git a/erpnext/patches/v12_0/update_price_or_product_discount.py b/erpnext/patches/v12_0/update_price_or_product_discount.py
index 3a8cd43e302..4ff39257688 100644
--- a/erpnext/patches/v12_0/update_price_or_product_discount.py
+++ b/erpnext/patches/v12_0/update_price_or_product_discount.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("accounts", "doctype", "pricing_rule")
diff --git a/erpnext/patches/v12_0/update_pricing_rule_fields.py b/erpnext/patches/v12_0/update_pricing_rule_fields.py
index 985613a9739..6f102e9b42b 100644
--- a/erpnext/patches/v12_0/update_pricing_rule_fields.py
+++ b/erpnext/patches/v12_0/update_pricing_rule_fields.py
@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
parentfield = {
diff --git a/erpnext/patches/v12_0/update_state_code_for_daman_and_diu.py b/erpnext/patches/v12_0/update_state_code_for_daman_and_diu.py
index 8dbfa1866d3..25cf6b97e3b 100644
--- a/erpnext/patches/v12_0/update_state_code_for_daman_and_diu.py
+++ b/erpnext/patches/v12_0/update_state_code_for_daman_and_diu.py
@@ -1,6 +1,8 @@
import frappe
+
from erpnext.regional.india import states
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
diff --git a/erpnext/patches/v12_0/update_uom_conversion_factor.py b/erpnext/patches/v12_0/update_uom_conversion_factor.py
index 24914fd13bc..7c7477a6739 100644
--- a/erpnext/patches/v12_0/update_uom_conversion_factor.py
+++ b/erpnext/patches/v12_0/update_uom_conversion_factor.py
@@ -1,5 +1,7 @@
from __future__ import unicode_literals
-import frappe, json
+
+import frappe
+
def execute():
from erpnext.setup.setup_wizard.operations.install_fixtures import add_uom_data
diff --git a/erpnext/patches/v12_0/update_vehicle_no_reqd_condition.py b/erpnext/patches/v12_0/update_vehicle_no_reqd_condition.py
index 01a4ae04add..69bfaaa2cb1 100644
--- a/erpnext/patches/v12_0/update_vehicle_no_reqd_condition.py
+++ b/erpnext/patches/v12_0/update_vehicle_no_reqd_condition.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
frappe.reload_doc('custom', 'doctype', 'custom_field')
company = frappe.get_all('Company', filters = {'country': 'India'})
diff --git a/erpnext/patches/v13_0/add_custom_field_for_south_africa.py b/erpnext/patches/v13_0/add_custom_field_for_south_africa.py
index 32566b8d21d..b34b5c1801f 100644
--- a/erpnext/patches/v13_0/add_custom_field_for_south_africa.py
+++ b/erpnext/patches/v13_0/add_custom_field_for_south_africa.py
@@ -2,8 +2,9 @@
# License: GNU General Public License v3. See license.txt
import frappe
-
-from erpnext.regional.south_africa.setup import make_custom_fields, add_permissions
+
+from erpnext.regional.south_africa.setup import add_permissions, make_custom_fields
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'South Africa'})
diff --git a/erpnext/patches/v13_0/add_missing_fg_item_for_stock_entry.py b/erpnext/patches/v13_0/add_missing_fg_item_for_stock_entry.py
index 0d8109c41ad..bd18b9bd173 100644
--- a/erpnext/patches/v13_0/add_missing_fg_item_for_stock_entry.py
+++ b/erpnext/patches/v13_0/add_missing_fg_item_for_stock_entry.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
import frappe
-from frappe.utils import cstr, flt, cint
-from erpnext.stock.stock_ledger import make_sl_entries
+from frappe.utils import cint, cstr, flt
+
from erpnext.controllers.stock_controller import create_repost_item_valuation_entry
+from erpnext.stock.stock_ledger import make_sl_entries
+
def execute():
if not frappe.db.has_column('Work Order', 'has_batch_no'):
diff --git a/erpnext/patches/v13_0/add_naming_series_to_old_projects.py b/erpnext/patches/v13_0/add_naming_series_to_old_projects.py
index a7b66f0d2bb..f029f75accd 100644
--- a/erpnext/patches/v13_0/add_naming_series_to_old_projects.py
+++ b/erpnext/patches/v13_0/add_naming_series_to_old_projects.py
@@ -1,6 +1,7 @@
from __future__ import unicode_literals
+
import frappe
-from frappe.custom.doctype.property_setter.property_setter import make_property_setter, delete_property_setter
+
def execute():
frappe.reload_doc("projects", "doctype", "project")
diff --git a/erpnext/patches/v13_0/add_po_to_global_search.py b/erpnext/patches/v13_0/add_po_to_global_search.py
index 1c60b18e5b2..15b7c71dc2c 100644
--- a/erpnext/patches/v13_0/add_po_to_global_search.py
+++ b/erpnext/patches/v13_0/add_po_to_global_search.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
import frappe
diff --git a/erpnext/patches/v13_0/add_standard_navbar_items.py b/erpnext/patches/v13_0/add_standard_navbar_items.py
index d05b258db0c..699c480c872 100644
--- a/erpnext/patches/v13_0/add_standard_navbar_items.py
+++ b/erpnext/patches/v13_0/add_standard_navbar_items.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
# import frappe
from erpnext.setup.install import add_standard_navbar_items
+
def execute():
# Add standard navbar items for ERPNext in Navbar Settings
add_standard_navbar_items()
diff --git a/erpnext/patches/v13_0/bill_for_rejected_quantity_in_purchase_invoice.py b/erpnext/patches/v13_0/bill_for_rejected_quantity_in_purchase_invoice.py
index 7de9fa1e23e..07d1cee64f8 100644
--- a/erpnext/patches/v13_0/bill_for_rejected_quantity_in_purchase_invoice.py
+++ b/erpnext/patches/v13_0/bill_for_rejected_quantity_in_purchase_invoice.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doctype("Buying Settings")
buying_settings = frappe.get_single("Buying Settings")
diff --git a/erpnext/patches/v13_0/change_default_pos_print_format.py b/erpnext/patches/v13_0/change_default_pos_print_format.py
index 1e4f383dda6..5a0320a7eb2 100644
--- a/erpnext/patches/v13_0/change_default_pos_print_format.py
+++ b/erpnext/patches/v13_0/change_default_pos_print_format.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.db.sql(
"""UPDATE `tabPOS Profile` profile
diff --git a/erpnext/patches/v13_0/check_is_income_tax_component.py b/erpnext/patches/v13_0/check_is_income_tax_component.py
index 7a52dc88d21..aac87ba36fa 100644
--- a/erpnext/patches/v13_0/check_is_income_tax_component.py
+++ b/erpnext/patches/v13_0/check_is_income_tax_component.py
@@ -3,9 +3,12 @@
from __future__ import unicode_literals
-import frappe, erpnext
+import frappe
+
+import erpnext
from erpnext.regional.india.setup import setup
+
def execute():
doctypes = ['salary_component',
diff --git a/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py b/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py
index 341955aa35f..66ac62fdc4c 100644
--- a/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py
+++ b/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('stock', 'doctype', 'quality_inspection_parameter')
diff --git a/erpnext/patches/v13_0/create_gst_payment_entry_fields.py b/erpnext/patches/v13_0/create_gst_payment_entry_fields.py
new file mode 100644
index 00000000000..7e6d67ce931
--- /dev/null
+++ b/erpnext/patches/v13_0/create_gst_payment_entry_fields.py
@@ -0,0 +1,32 @@
+# Copyright (c) 2021, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
+
+def execute():
+ frappe.reload_doc('accounts', 'doctype', 'advance_taxes_and_charges')
+ frappe.reload_doc('accounts', 'doctype', 'payment_entry')
+
+ custom_fields = {
+ 'Payment Entry': [
+ dict(fieldname='gst_section', label='GST Details', fieldtype='Section Break', insert_after='deductions',
+ print_hide=1, collapsible=1),
+ dict(fieldname='company_address', label='Company Address', fieldtype='Link', insert_after='gst_section',
+ print_hide=1, options='Address'),
+ dict(fieldname='company_gstin', label='Company GSTIN',
+ fieldtype='Data', insert_after='company_address',
+ fetch_from='company_address.gstin', print_hide=1, read_only=1),
+ dict(fieldname='place_of_supply', label='Place of Supply',
+ fieldtype='Data', insert_after='company_gstin',
+ print_hide=1, read_only=1),
+ dict(fieldname='customer_address', label='Customer Address', fieldtype='Link', insert_after='place_of_supply',
+ print_hide=1, options='Address', depends_on = 'eval:doc.party_type == "Customer"'),
+ dict(fieldname='customer_gstin', label='Customer GSTIN',
+ fieldtype='Data', insert_after='customer_address',
+ fetch_from='customer_address.gstin', print_hide=1, read_only=1)
+ ]
+ }
+
+ create_custom_fields(custom_fields, update=True)
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/create_healthcare_custom_fields_in_stock_entry_detail.py b/erpnext/patches/v13_0/create_healthcare_custom_fields_in_stock_entry_detail.py
index 08d4876c0d1..543faeb74ac 100644
--- a/erpnext/patches/v13_0/create_healthcare_custom_fields_in_stock_entry_detail.py
+++ b/erpnext/patches/v13_0/create_healthcare_custom_fields_in_stock_entry_detail.py
@@ -1,7 +1,9 @@
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
from erpnext.domains.healthcare import data
+
def execute():
if 'Healthcare' not in frappe.get_active_domains():
return
diff --git a/erpnext/patches/v13_0/create_leave_policy_assignment_based_on_employee_current_leave_policy.py b/erpnext/patches/v13_0/create_leave_policy_assignment_based_on_employee_current_leave_policy.py
index 9a354537f7d..b1b5c24adc8 100644
--- a/erpnext/patches/v13_0/create_leave_policy_assignment_based_on_employee_current_leave_policy.py
+++ b/erpnext/patches/v13_0/create_leave_policy_assignment_based_on_employee_current_leave_policy.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
+
def execute():
if "leave_policy" in frappe.db.get_table_columns("Employee"):
employees_with_leave_policy = frappe.db.sql("SELECT name, leave_policy FROM `tabEmployee` WHERE leave_policy IS NOT NULL and leave_policy != ''", as_dict = 1)
diff --git a/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py b/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py
index 6ad3402ba02..3bfa78fa282 100644
--- a/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py
+++ b/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py
@@ -4,8 +4,10 @@
from __future__ import unicode_literals
import frappe
+
from erpnext.regional.united_arab_emirates.setup import make_custom_fields
+
def execute():
company = frappe.get_all('Company', filters = {'country': ['in', ['Saudi Arabia', 'United Arab Emirates']]})
if not company:
diff --git a/erpnext/patches/v13_0/create_website_items.py b/erpnext/patches/v13_0/create_website_items.py
new file mode 100644
index 00000000000..a63dc897f44
--- /dev/null
+++ b/erpnext/patches/v13_0/create_website_items.py
@@ -0,0 +1,74 @@
+import frappe
+
+from erpnext.e_commerce.doctype.website_item.website_item import make_website_item
+
+
+def execute():
+ frappe.reload_doc("e_commerce", "doctype", "website_item")
+ frappe.reload_doc("e_commerce", "doctype", "website_item_tabbed_section")
+ frappe.reload_doc("e_commerce", "doctype", "website_offer")
+ frappe.reload_doc("e_commerce", "doctype", "recommended_items")
+ frappe.reload_doc("e_commerce", "doctype", "e_commerce_settings")
+ frappe.reload_doc("stock", "doctype", "item")
+
+ item_fields = ["item_code", "item_name", "item_group", "stock_uom", "brand", "image",
+ "has_variants", "variant_of", "description", "weightage"]
+ web_fields_to_map = ["route", "slideshow", "website_image_alt",
+ "website_warehouse", "web_long_description", "website_content"]
+
+ item_table_fields = frappe.db.sql("desc `tabItem`", as_dict=1)
+ item_table_fields = [d.get('Field') for d in item_table_fields]
+
+ # prepare fields to query from Item, check if the web field exists in Item master
+ web_query_fields = []
+ for web_field in web_fields_to_map:
+ if web_field in item_table_fields:
+ web_query_fields.append(web_field)
+ item_fields.append(web_field)
+
+ # check if the filter fields exist in Item master
+ or_filters = {}
+ for field in ["show_in_website", "show_variant_in_website"]:
+ if field in item_table_fields:
+ or_filters[field] = 1
+
+ if not web_query_fields or not or_filters:
+ # web fields to map are not present in Item master schema
+ # most likely a fresh installation that doesnt need this patch
+ return
+
+ items = frappe.db.get_all(
+ "Item",
+ fields=item_fields,
+ or_filters=or_filters
+ )
+
+ count = 0
+ for item in items:
+ if frappe.db.exists("Website Item", {"item_code": item.item_code}):
+ continue
+
+ # make website item from item (publish item)
+ website_item = make_website_item(item, save=False)
+ website_item.ranking = item.get("weightage")
+ for field in web_fields_to_map:
+ website_item.update({field: item.get(field)})
+ website_item.save()
+
+ # move Website Item Group & Website Specification table to Website Item
+ for doctype in ("Website Item Group", "Item Website Specification"):
+ web_item, item_code = website_item.name, item.item_code
+ frappe.db.sql(f"""
+ Update
+ `tab{doctype}`
+ set
+ parenttype = 'Website Item',
+ parent = '{web_item}'
+ where
+ parenttype = 'Item'
+ and parent = '{item_code}'
+ """)
+
+ count += 1
+ if count % 20 == 0: # commit after every 20 items
+ frappe.db.commit()
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/custom_fields_for_taxjar_integration.py b/erpnext/patches/v13_0/custom_fields_for_taxjar_integration.py
new file mode 100644
index 00000000000..43a9aeb6fe6
--- /dev/null
+++ b/erpnext/patches/v13_0/custom_fields_for_taxjar_integration.py
@@ -0,0 +1,32 @@
+from __future__ import unicode_literals
+
+import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
+from erpnext.regional.united_states.setup import add_permissions
+
+
+def execute():
+ company = frappe.get_all('Company', filters = {'country': 'United States'}, fields=['name'])
+ if not company:
+ return
+
+ frappe.reload_doc("regional", "doctype", "product_tax_category")
+
+ custom_fields = {
+ 'Sales Invoice Item': [
+ dict(fieldname='product_tax_category', fieldtype='Link', insert_after='description', options='Product Tax Category',
+ label='Product Tax Category', fetch_from='item_code.product_tax_category'),
+ dict(fieldname='tax_collectable', fieldtype='Currency', insert_after='net_amount',
+ label='Tax Collectable', read_only=1),
+ dict(fieldname='taxable_amount', fieldtype='Currency', insert_after='tax_collectable',
+ label='Taxable Amount', read_only=1)
+ ],
+ 'Item': [
+ dict(fieldname='product_tax_category', fieldtype='Link', insert_after='item_group', options='Product Tax Category',
+ label='Product Tax Category')
+ ]
+ }
+ create_custom_fields(custom_fields, update=True)
+ add_permissions()
+ frappe.enqueue('erpnext.regional.united_states.setup.add_product_tax_categories', now=True)
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py b/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py
index 77a23cfc3f8..089bbe3b48f 100644
--- a/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py
+++ b/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
doctypes = [
"Bank Statement Settings",
diff --git a/erpnext/patches/v13_0/delete_old_purchase_reports.py b/erpnext/patches/v13_0/delete_old_purchase_reports.py
index 57620d3e986..3cb7e120d67 100644
--- a/erpnext/patches/v13_0/delete_old_purchase_reports.py
+++ b/erpnext/patches/v13_0/delete_old_purchase_reports.py
@@ -4,8 +4,10 @@
from __future__ import unicode_literals
import frappe
+
from erpnext.accounts.utils import check_and_delete_linked_reports
+
def execute():
reports_to_delete = ["Requested Items To Be Ordered",
"Purchase Order Items To Be Received or Billed","Purchase Order Items To Be Received",
diff --git a/erpnext/patches/v13_0/delete_old_sales_reports.py b/erpnext/patches/v13_0/delete_old_sales_reports.py
index 905a42c0c4c..c9a366655ce 100644
--- a/erpnext/patches/v13_0/delete_old_sales_reports.py
+++ b/erpnext/patches/v13_0/delete_old_sales_reports.py
@@ -4,8 +4,10 @@
from __future__ import unicode_literals
import frappe
+
from erpnext.accounts.utils import check_and_delete_linked_reports
+
def execute():
reports_to_delete = ["Ordered Items To Be Delivered", "Ordered Items To Be Billed"]
diff --git a/erpnext/patches/v13_0/delete_orphaned_tables.py b/erpnext/patches/v13_0/delete_orphaned_tables.py
index 50a4a0efcbe..1ea22d63561 100644
--- a/erpnext/patches/v13_0/delete_orphaned_tables.py
+++ b/erpnext/patches/v13_0/delete_orphaned_tables.py
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import getdate
+
def execute():
frappe.reload_doc('setup', 'doctype', 'transaction_deletion_record')
diff --git a/erpnext/patches/v13_0/delete_report_requested_items_to_order.py b/erpnext/patches/v13_0/delete_report_requested_items_to_order.py
index 8d6340d44ef..87565f0fe42 100644
--- a/erpnext/patches/v13_0/delete_report_requested_items_to_order.py
+++ b/erpnext/patches/v13_0/delete_report_requested_items_to_order.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
""" Check for one or multiple Auto Email Reports and delete """
auto_email_reports = frappe.db.get_values("Auto Email Report", {"report": "Requested Items to Order"}, ["name"])
diff --git a/erpnext/patches/v13_0/drop_razorpay_payload_column.py b/erpnext/patches/v13_0/drop_razorpay_payload_column.py
index 76b8041cd94..a7aee521983 100644
--- a/erpnext/patches/v13_0/drop_razorpay_payload_column.py
+++ b/erpnext/patches/v13_0/drop_razorpay_payload_column.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
if frappe.db.exists("DocType", "Membership"):
if 'webhook_payload' in frappe.db.get_table_columns("Membership"):
diff --git a/erpnext/patches/v13_0/fix_non_unique_represents_company.py b/erpnext/patches/v13_0/fix_non_unique_represents_company.py
index f20c73ae102..e91c1db4dd4 100644
--- a/erpnext/patches/v13_0/fix_non_unique_represents_company.py
+++ b/erpnext/patches/v13_0/fix_non_unique_represents_company.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
frappe.db.sql("""
update tabCustomer
diff --git a/erpnext/patches/v13_0/germany_make_custom_fields.py b/erpnext/patches/v13_0/germany_make_custom_fields.py
index 41ab945eb12..86ad1885990 100644
--- a/erpnext/patches/v13_0/germany_make_custom_fields.py
+++ b/erpnext/patches/v13_0/germany_make_custom_fields.py
@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
+
from erpnext.regional.germany.setup import make_custom_fields
diff --git a/erpnext/patches/v13_0/healthcare_lab_module_rename_doctypes.py b/erpnext/patches/v13_0/healthcare_lab_module_rename_doctypes.py
index 2549a1e91ee..f2976544a40 100644
--- a/erpnext/patches/v13_0/healthcare_lab_module_rename_doctypes.py
+++ b/erpnext/patches/v13_0/healthcare_lab_module_rename_doctypes.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
diff --git a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
index c4ad1b7ff4f..e4cb9ae7cdc 100644
--- a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
+++ b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
@@ -1,8 +1,9 @@
import frappe
-from frappe import _
-from frappe.utils import getdate, get_time, today
-from erpnext.stock.stock_ledger import update_entries_after
+from frappe.utils import get_time, getdate, today
+
from erpnext.accounts.utils import update_gl_entries_after
+from erpnext.stock.stock_ledger import update_entries_after
+
def execute():
for doctype in ('repost_item_valuation', 'stock_entry_detail', 'purchase_receipt_item',
diff --git a/erpnext/patches/v13_0/loyalty_points_entry_for_pos_invoice.py b/erpnext/patches/v13_0/loyalty_points_entry_for_pos_invoice.py
index d2228c3bf31..43c6c4941ea 100644
--- a/erpnext/patches/v13_0/loyalty_points_entry_for_pos_invoice.py
+++ b/erpnext/patches/v13_0/loyalty_points_entry_for_pos_invoice.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
+
def execute():
'''`sales_invoice` field from loyalty point entry is splitted into `invoice_type` & `invoice` fields'''
diff --git a/erpnext/patches/v13_0/make_homepage_products_website_items.py b/erpnext/patches/v13_0/make_homepage_products_website_items.py
new file mode 100644
index 00000000000..d48d54802c4
--- /dev/null
+++ b/erpnext/patches/v13_0/make_homepage_products_website_items.py
@@ -0,0 +1,17 @@
+from __future__ import unicode_literals
+
+import frappe
+
+
+def execute():
+ homepage = frappe.get_doc("Homepage")
+
+ for row in homepage.products:
+ web_item = frappe.db.get_value("Website Item", {"item_code": row.item_code}, "name")
+ if not web_item:
+ continue
+
+ row.item_code = web_item
+
+ homepage.flags.ignore_mandatory = True
+ homepage.save()
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/make_non_standard_user_type.py b/erpnext/patches/v13_0/make_non_standard_user_type.py
index 73361f00262..746e4080b69 100644
--- a/erpnext/patches/v13_0/make_non_standard_user_type.py
+++ b/erpnext/patches/v13_0/make_non_standard_user_type.py
@@ -2,10 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from six import iteritems
+
from erpnext.setup.install import add_non_standard_user_types
+
def execute():
doctype_dict = {
'projects': ['Timesheet'],
diff --git a/erpnext/patches/v13_0/migrate_stripe_api.py b/erpnext/patches/v13_0/migrate_stripe_api.py
new file mode 100644
index 00000000000..355421a1f42
--- /dev/null
+++ b/erpnext/patches/v13_0/migrate_stripe_api.py
@@ -0,0 +1,7 @@
+import frappe
+from frappe.model.utils.rename_field import rename_field
+
+
+def execute():
+ frappe.reload_doc("accounts", "doctype", "subscription_plan")
+ rename_field("Subscription Plan", "payment_plan_id", "product_price_id")
diff --git a/erpnext/patches/v13_0/move_branch_code_to_bank_account.py b/erpnext/patches/v13_0/move_branch_code_to_bank_account.py
index 24d9196d29f..9116f5835a1 100644
--- a/erpnext/patches/v13_0/move_branch_code_to_bank_account.py
+++ b/erpnext/patches/v13_0/move_branch_code_to_bank_account.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
+
def execute():
frappe.reload_doc('accounts', 'doctype', 'bank_account')
diff --git a/erpnext/patches/v13_0/move_doctype_reports_and_notification_from_hr_to_payroll.py b/erpnext/patches/v13_0/move_doctype_reports_and_notification_from_hr_to_payroll.py
index 4d7c85ce2d1..064e8d71a04 100644
--- a/erpnext/patches/v13_0/move_doctype_reports_and_notification_from_hr_to_payroll.py
+++ b/erpnext/patches/v13_0/move_doctype_reports_and_notification_from_hr_to_payroll.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
+
def execute():
frappe.db.sql("""UPDATE `tabPrint Format`
SET module = 'Payroll'
diff --git a/erpnext/patches/v13_0/move_payroll_setting_separately_from_hr_settings.py b/erpnext/patches/v13_0/move_payroll_setting_separately_from_hr_settings.py
index a901064b889..85d5109248d 100644
--- a/erpnext/patches/v13_0/move_payroll_setting_separately_from_hr_settings.py
+++ b/erpnext/patches/v13_0/move_payroll_setting_separately_from_hr_settings.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
+
def execute():
data = frappe.db.sql('''SELECT *
FROM `tabSingles`
diff --git a/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py b/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py
index 1a91d218ba3..e73fa7b9ecd 100644
--- a/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py
+++ b/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.model.utils.rename_field import rename_field
+
def execute():
if not (frappe.db.table_exists("Payroll Period") and frappe.db.table_exists("Taxable Salary Slab")):
@@ -86,7 +86,7 @@ def execute():
try:
employee_other_income.submit()
migrated.append([proof.employee, proof.payroll_period])
- except:
+ except Exception:
pass
if not frappe.db.table_exists("Employee Tax Exemption Declaration"):
@@ -108,5 +108,5 @@ def execute():
try:
employee_other_income.submit()
- except:
+ except Exception:
pass
diff --git a/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py b/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py
index 15aeb76e53f..bb539a7962c 100644
--- a/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py
+++ b/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
import frappe
+
def execute():
if not frappe.db.table_exists("Additional Salary"):
return
diff --git a/erpnext/patches/v13_0/populate_e_commerce_settings.py b/erpnext/patches/v13_0/populate_e_commerce_settings.py
new file mode 100644
index 00000000000..4466de817a7
--- /dev/null
+++ b/erpnext/patches/v13_0/populate_e_commerce_settings.py
@@ -0,0 +1,62 @@
+from __future__ import unicode_literals
+
+import frappe
+from frappe.utils import cint
+
+
+def execute():
+ frappe.reload_doc("e_commerce", "doctype", "e_commerce_settings")
+ frappe.reload_doc("portal", "doctype", "website_filter_field")
+ frappe.reload_doc("portal", "doctype", "website_attribute")
+
+ products_settings_fields = [
+ "hide_variants", "products_per_page",
+ "enable_attribute_filters", "enable_field_filters"
+ ]
+
+ shopping_cart_settings_fields = [
+ "enabled", "show_attachments", "show_price",
+ "show_stock_availability", "enable_variants", "show_contact_us_button",
+ "show_quantity_in_website", "show_apply_coupon_code_in_website",
+ "allow_items_not_in_stock", "company", "price_list", "default_customer_group",
+ "quotation_series", "enable_checkout", "payment_success_url",
+ "payment_gateway_account", "save_quotations_as_draft"
+ ]
+
+ settings = frappe.get_doc("E Commerce Settings")
+
+ def map_into_e_commerce_settings(doctype, fields):
+ data = frappe.db.sql("""
+ Select
+ field, value
+ from `tabSingles`
+ where
+ doctype='{doctype}'
+ and field in ({fields})
+ """.format(
+ doctype=doctype,
+ fields=(",").join(['%s'] * len(fields))
+ ), tuple(fields), as_dict=1)
+
+ # {'enable_attribute_filters': '1', ...}
+ mapper = {row.field: row.value for row in data}
+
+ for key, value in mapper.items():
+ value = cint(value) if (value and value.isdigit()) else value
+ settings.update({key: value})
+
+ settings.save()
+
+ # shift data to E Commerce Settings
+ map_into_e_commerce_settings("Products Settings", products_settings_fields)
+ map_into_e_commerce_settings("Shopping Cart Settings", shopping_cart_settings_fields)
+
+ # move filters and attributes tables to E Commerce Settings from Products Settings
+ for doctype in ("Website Filter Field", "Website Attribute"):
+ frappe.db.sql("""Update `tab{doctype}`
+ set
+ parenttype = 'E Commerce Settings',
+ parent = 'E Commerce Settings'
+ where
+ parent = 'Products Settings'
+ """.format(doctype=doctype))
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/print_uom_after_quantity_patch.py b/erpnext/patches/v13_0/print_uom_after_quantity_patch.py
index 0de3728f5c6..f2022b28b8b 100644
--- a/erpnext/patches/v13_0/print_uom_after_quantity_patch.py
+++ b/erpnext/patches/v13_0/print_uom_after_quantity_patch.py
@@ -3,8 +3,8 @@
from __future__ import unicode_literals
-import frappe
from erpnext.setup.install import create_print_uom_after_qty_custom_field
+
def execute():
create_print_uom_after_qty_custom_field()
diff --git a/erpnext/patches/v13_0/remove_attribute_field_from_item_variant_setting.py b/erpnext/patches/v13_0/remove_attribute_field_from_item_variant_setting.py
index 53da7006b98..bbe3eb5815b 100644
--- a/erpnext/patches/v13_0/remove_attribute_field_from_item_variant_setting.py
+++ b/erpnext/patches/v13_0/remove_attribute_field_from_item_variant_setting.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
"""Remove has_variants and attribute fields from item variant settings."""
frappe.reload_doc("stock", "doctype", "Item Variant Settings")
diff --git a/erpnext/patches/v13_0/rename_discharge_date_in_ip_record.py b/erpnext/patches/v13_0/rename_discharge_date_in_ip_record.py
index 491dc82f784..2a04211a407 100644
--- a/erpnext/patches/v13_0/rename_discharge_date_in_ip_record.py
+++ b/erpnext/patches/v13_0/rename_discharge_date_in_ip_record.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
frappe.reload_doc("Healthcare", "doctype", "Inpatient Record")
if frappe.db.has_column("Inpatient Record", "discharge_date"):
diff --git a/erpnext/patches/v13_0/rename_discharge_ordered_date_in_ip_record.py b/erpnext/patches/v13_0/rename_discharge_ordered_date_in_ip_record.py
index 52a5885fc2f..cf5cae438e6 100644
--- a/erpnext/patches/v13_0/rename_discharge_ordered_date_in_ip_record.py
+++ b/erpnext/patches/v13_0/rename_discharge_ordered_date_in_ip_record.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
frappe.reload_doc("Healthcare", "doctype", "Inpatient Record")
if frappe.db.has_column("Inpatient Record", "discharge_ordered_date"):
diff --git a/erpnext/patches/v13_0/rename_issue_doctype_fields.py b/erpnext/patches/v13_0/rename_issue_doctype_fields.py
index 4885c0b7afa..4aeafeabe74 100644
--- a/erpnext/patches/v13_0/rename_issue_doctype_fields.py
+++ b/erpnext/patches/v13_0/rename_issue_doctype_fields.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
if frappe.db.exists('DocType', 'Issue'):
issues = frappe.db.get_all('Issue', fields=['name', 'response_by_variance', 'resolution_by_variance', 'mins_to_first_response'],
diff --git a/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py
index 4ef04ad9b1b..1d245db4d59 100644
--- a/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py
+++ b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
if frappe.db.exists('DocType', 'Issue'):
frappe.reload_doc("support", "doctype", "issue")
diff --git a/erpnext/patches/v13_0/rename_membership_settings_to_non_profit_settings.py b/erpnext/patches/v13_0/rename_membership_settings_to_non_profit_settings.py
index f60567b6b21..23a782a1e82 100644
--- a/erpnext/patches/v13_0/rename_membership_settings_to_non_profit_settings.py
+++ b/erpnext/patches/v13_0/rename_membership_settings_to_non_profit_settings.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
if frappe.db.table_exists("Membership Settings"):
frappe.rename_doc("DocType", "Membership Settings", "Non Profit Settings")
diff --git a/erpnext/patches/v13_0/rename_stop_to_send_birthday_reminders.py b/erpnext/patches/v13_0/rename_stop_to_send_birthday_reminders.py
index 1787a560254..28054317ad3 100644
--- a/erpnext/patches/v13_0/rename_stop_to_send_birthday_reminders.py
+++ b/erpnext/patches/v13_0/rename_stop_to_send_birthday_reminders.py
@@ -1,23 +1,24 @@
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
frappe.reload_doc('hr', 'doctype', 'hr_settings')
try:
# Rename the field
rename_field('HR Settings', 'stop_birthday_reminders', 'send_birthday_reminders')
-
+
# Reverse the value
old_value = frappe.db.get_single_value('HR Settings', 'send_birthday_reminders')
frappe.db.set_value(
- 'HR Settings',
- 'HR Settings',
- 'send_birthday_reminders',
+ 'HR Settings',
+ 'HR Settings',
+ 'send_birthday_reminders',
1 if old_value == 0 else 0
)
-
+
except Exception as e:
if e.args[0] != 1054:
raise
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/replace_pos_page_with_point_of_sale_page.py b/erpnext/patches/v13_0/replace_pos_page_with_point_of_sale_page.py
index d8bcd7f0775..989f1a0a281 100644
--- a/erpnext/patches/v13_0/replace_pos_page_with_point_of_sale_page.py
+++ b/erpnext/patches/v13_0/replace_pos_page_with_point_of_sale_page.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
if frappe.db.exists("Page", "point-of-sale"):
frappe.rename_doc("Page", "pos", "point-of-sale", 1, 1)
diff --git a/erpnext/patches/v13_0/replace_pos_payment_mode_table.py b/erpnext/patches/v13_0/replace_pos_payment_mode_table.py
index bc1fc98e4da..103c79177f1 100644
--- a/erpnext/patches/v13_0/replace_pos_payment_mode_table.py
+++ b/erpnext/patches/v13_0/replace_pos_payment_mode_table.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
+
def execute():
frappe.reload_doc("accounts", "doctype", "pos_payment_method")
pos_profiles = frappe.get_all("POS Profile")
diff --git a/erpnext/patches/v13_0/reset_clearance_date_for_intracompany_payment_entries.py b/erpnext/patches/v13_0/reset_clearance_date_for_intracompany_payment_entries.py
new file mode 100644
index 00000000000..f8c4c1031a0
--- /dev/null
+++ b/erpnext/patches/v13_0/reset_clearance_date_for_intracompany_payment_entries.py
@@ -0,0 +1,46 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+
+
+def execute():
+ """
+ Reset Clearance Date for Payment Entries of type Internal Transfer that have only been reconciled with one Bank Transaction.
+ This will allow the Payment Entries to be reconciled with the second Bank Transaction using the Bank Reconciliation Tool.
+ """
+
+ intra_company_pe = get_intra_company_payment_entries_with_clearance_dates()
+ reconciled_bank_transactions = get_reconciled_bank_transactions(intra_company_pe)
+
+ for payment_entry in reconciled_bank_transactions:
+ if len(reconciled_bank_transactions[payment_entry]) == 1:
+ frappe.db.set_value('Payment Entry', payment_entry, 'clearance_date', None)
+
+def get_intra_company_payment_entries_with_clearance_dates():
+ return frappe.get_all(
+ 'Payment Entry',
+ filters = {
+ 'payment_type': 'Internal Transfer',
+ 'clearance_date': ["not in", None]
+ },
+ pluck = 'name'
+ )
+
+def get_reconciled_bank_transactions(intra_company_pe):
+ """Returns dictionary where each key:value pair is Payment Entry : List of Bank Transactions reconciled with Payment Entry"""
+
+ reconciled_bank_transactions = {}
+
+ for payment_entry in intra_company_pe:
+ reconciled_bank_transactions[payment_entry] = frappe.get_all(
+ 'Bank Transaction Payments',
+ filters = {
+ 'payment_entry': payment_entry
+ },
+ pluck='parent'
+ )
+
+ return reconciled_bank_transactions
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/set_app_name.py b/erpnext/patches/v13_0/set_app_name.py
index 3f886f1d159..4a88442bcdc 100644
--- a/erpnext/patches/v13_0/set_app_name.py
+++ b/erpnext/patches/v13_0/set_app_name.py
@@ -1,5 +1,5 @@
import frappe
-from frappe import _
+
def execute():
frappe.reload_doctype("System Settings")
diff --git a/erpnext/patches/v13_0/set_company_field_in_healthcare_doctypes.py b/erpnext/patches/v13_0/set_company_field_in_healthcare_doctypes.py
index a5b93f63071..e9396c2df29 100644
--- a/erpnext/patches/v13_0/set_company_field_in_healthcare_doctypes.py
+++ b/erpnext/patches/v13_0/set_company_field_in_healthcare_doctypes.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
company = frappe.db.get_single_value('Global Defaults', 'default_company')
doctypes = ['Clinical Procedure', 'Inpatient Record', 'Lab Test', 'Sample Collection', 'Patient Appointment', 'Patient Encounter', 'Vital Signs', 'Therapy Session', 'Therapy Plan', 'Patient Assessment']
diff --git a/erpnext/patches/v13_0/set_company_in_leave_ledger_entry.py b/erpnext/patches/v13_0/set_company_in_leave_ledger_entry.py
index 13ec41ec55e..c744f35b72f 100644
--- a/erpnext/patches/v13_0/set_company_in_leave_ledger_entry.py
+++ b/erpnext/patches/v13_0/set_company_in_leave_ledger_entry.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
frappe.reload_doc('HR', 'doctype', 'Leave Allocation')
frappe.reload_doc('HR', 'doctype', 'Leave Ledger Entry')
diff --git a/erpnext/patches/v13_0/set_operation_time_based_on_operating_cost.py b/erpnext/patches/v13_0/set_operation_time_based_on_operating_cost.py
index 4acbdd63a00..0366d4902dc 100644
--- a/erpnext/patches/v13_0/set_operation_time_based_on_operating_cost.py
+++ b/erpnext/patches/v13_0/set_operation_time_based_on_operating_cost.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
frappe.reload_doc('manufacturing', 'doctype', 'bom')
frappe.reload_doc('manufacturing', 'doctype', 'bom_operation')
diff --git a/erpnext/patches/v13_0/set_payment_channel_in_payment_gateway_account.py b/erpnext/patches/v13_0/set_payment_channel_in_payment_gateway_account.py
index 7f75946af9f..da889e61bab 100644
--- a/erpnext/patches/v13_0/set_payment_channel_in_payment_gateway_account.py
+++ b/erpnext/patches/v13_0/set_payment_channel_in_payment_gateway_account.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
"""Set the payment gateway account as Email for all the existing payment channel."""
doc_meta = frappe.get_meta("Payment Gateway Account")
diff --git a/erpnext/patches/v13_0/set_pos_closing_as_failed.py b/erpnext/patches/v13_0/set_pos_closing_as_failed.py
index 7968e74f50f..8c7f5088b74 100644
--- a/erpnext/patches/v13_0/set_pos_closing_as_failed.py
+++ b/erpnext/patches/v13_0/set_pos_closing_as_failed.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('accounts', 'doctype', 'pos_closing_entry')
diff --git a/erpnext/patches/v13_0/set_training_event_attendance.py b/erpnext/patches/v13_0/set_training_event_attendance.py
index 3db183fb2ab..4e3d8f5e6a5 100644
--- a/erpnext/patches/v13_0/set_training_event_attendance.py
+++ b/erpnext/patches/v13_0/set_training_event_attendance.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('hr', 'doctype', 'training_event')
frappe.reload_doc('hr', 'doctype', 'training_event_employee')
diff --git a/erpnext/patches/v13_0/set_youtube_video_id.py b/erpnext/patches/v13_0/set_youtube_video_id.py
index f6104d1579f..1594e52e4e5 100644
--- a/erpnext/patches/v13_0/set_youtube_video_id.py
+++ b/erpnext/patches/v13_0/set_youtube_video_id.py
@@ -1,7 +1,10 @@
from __future__ import unicode_literals
+
import frappe
+
from erpnext.utilities.doctype.video.video import get_id_from_url
+
def execute():
frappe.reload_doc("utilities", "doctype","video")
diff --git a/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py b/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py
index c8c160fae71..a6a3ff3be4b 100644
--- a/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py
+++ b/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py
@@ -1,7 +1,10 @@
from __future__ import unicode_literals
+
import frappe
+
from erpnext.regional.india.setup import add_custom_roles_for_reports
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
diff --git a/erpnext/patches/v13_0/setup_fields_for_80g_certificate_and_donation.py b/erpnext/patches/v13_0/setup_fields_for_80g_certificate_and_donation.py
index 833c355d5f8..7a2a2539670 100644
--- a/erpnext/patches/v13_0/setup_fields_for_80g_certificate_and_donation.py
+++ b/erpnext/patches/v13_0/setup_fields_for_80g_certificate_and_donation.py
@@ -1,6 +1,8 @@
import frappe
+
from erpnext.regional.india.setup import make_custom_fields
+
def execute():
if frappe.get_all('Company', filters = {'country': 'India'}):
make_custom_fields()
diff --git a/erpnext/patches/v13_0/setup_gratuity_rule_for_india_and_uae.py b/erpnext/patches/v13_0/setup_gratuity_rule_for_india_and_uae.py
index 01fd6a158e9..01e75a6009b 100644
--- a/erpnext/patches/v13_0/setup_gratuity_rule_for_india_and_uae.py
+++ b/erpnext/patches/v13_0/setup_gratuity_rule_for_india_and_uae.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('payroll', 'doctype', 'gratuity_rule')
frappe.reload_doc('payroll', 'doctype', 'gratuity_rule_slab')
diff --git a/erpnext/patches/v13_0/setup_patient_history_settings_for_standard_doctypes.py b/erpnext/patches/v13_0/setup_patient_history_settings_for_standard_doctypes.py
index 83581dd4144..80622d46096 100644
--- a/erpnext/patches/v13_0/setup_patient_history_settings_for_standard_doctypes.py
+++ b/erpnext/patches/v13_0/setup_patient_history_settings_for_standard_doctypes.py
@@ -1,7 +1,10 @@
from __future__ import unicode_literals
+
import frappe
+
from erpnext.healthcare.setup import setup_patient_history_settings
+
def execute():
if "Healthcare" not in frappe.get_active_domains():
return
diff --git a/erpnext/patches/v13_0/setup_uae_vat_fields.py b/erpnext/patches/v13_0/setup_uae_vat_fields.py
index 1830bab02ba..d89e0521d8d 100644
--- a/erpnext/patches/v13_0/setup_uae_vat_fields.py
+++ b/erpnext/patches/v13_0/setup_uae_vat_fields.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
import frappe
+
from erpnext.regional.united_arab_emirates.setup import setup
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'United Arab Emirates'})
if not company:
diff --git a/erpnext/patches/v13_0/stock_entry_enhancements.py b/erpnext/patches/v13_0/stock_entry_enhancements.py
index 7b93ce35768..5fcd6a3a625 100644
--- a/erpnext/patches/v13_0/stock_entry_enhancements.py
+++ b/erpnext/patches/v13_0/stock_entry_enhancements.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3.See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("stock", "doctype", "stock_entry")
if frappe.db.has_column("Stock Entry", "add_to_transit"):
diff --git a/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py b/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py
index 50f233deef4..dd87a5302d2 100644
--- a/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py
+++ b/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py
@@ -7,6 +7,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import add_to_date
+
def execute():
frappe.reload_doc("manufacturing", "doctype", "work_order")
frappe.reload_doc("manufacturing", "doctype", "work_order_item")
diff --git a/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py b/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py
index dc9ed18eade..dc973a9d451 100644
--- a/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py
+++ b/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
""" Correct amount in child table of required items table."""
diff --git a/erpnext/patches/v13_0/update_custom_fields_for_shopify.py b/erpnext/patches/v13_0/update_custom_fields_for_shopify.py
index f1d2ea2d747..828bde69cf9 100644
--- a/erpnext/patches/v13_0/update_custom_fields_for_shopify.py
+++ b/erpnext/patches/v13_0/update_custom_fields_for_shopify.py
@@ -2,8 +2,13 @@
# MIT License. See license.txt
from __future__ import unicode_literals
+
import frappe
-from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings import setup_custom_fields
+
+from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings import (
+ setup_custom_fields,
+)
+
def execute():
if frappe.db.get_single_value('Shopify Settings', 'enable_shopify'):
diff --git a/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py b/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py
new file mode 100644
index 00000000000..90fb50fb42c
--- /dev/null
+++ b/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py
@@ -0,0 +1,26 @@
+# Copyright (c) 2021, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+import frappe
+
+
+def execute():
+ frappe.reload_doc('accounts', 'doctype', 'Tax Withholding Rate')
+
+ if frappe.db.has_column('Tax Withholding Rate', 'fiscal_year'):
+ tds_category_rates = frappe.get_all('Tax Withholding Rate', fields=['name', 'fiscal_year'])
+
+ fiscal_year_map = {}
+ fiscal_year_details = frappe.get_all('Fiscal Year', fields=['name', 'year_start_date', 'year_end_date'])
+
+ for d in fiscal_year_details:
+ fiscal_year_map.setdefault(d.name, d)
+
+ for rate in tds_category_rates:
+ from_date = fiscal_year_map.get(rate.fiscal_year).get('year_start_date')
+ to_date = fiscal_year_map.get(rate.fiscal_year).get('year_end_date')
+
+ frappe.db.set_value('Tax Withholding Rate', rate.name, {
+ 'from_date': from_date,
+ 'to_date': to_date
+ })
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/update_deferred_settings.py b/erpnext/patches/v13_0/update_deferred_settings.py
index bcc09527a29..54059318c75 100644
--- a/erpnext/patches/v13_0/update_deferred_settings.py
+++ b/erpnext/patches/v13_0/update_deferred_settings.py
@@ -1,8 +1,10 @@
# Copyright (c) 2019, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.book_deferred_entries_based_on = 'Days'
diff --git a/erpnext/patches/v13_0/update_export_type_for_gst.py b/erpnext/patches/v13_0/update_export_type_for_gst.py
index ef70b55d94c..de578612f7d 100644
--- a/erpnext/patches/v13_0/update_export_type_for_gst.py
+++ b/erpnext/patches/v13_0/update_export_type_for_gst.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
diff --git a/erpnext/patches/v13_0/update_job_card_details.py b/erpnext/patches/v13_0/update_job_card_details.py
index 733b3a960cf..a0405e50396 100644
--- a/erpnext/patches/v13_0/update_job_card_details.py
+++ b/erpnext/patches/v13_0/update_job_card_details.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("manufacturing", "doctype", "job_card")
frappe.reload_doc("manufacturing", "doctype", "job_card_item")
diff --git a/erpnext/patches/v13_0/update_level_in_bom.py b/erpnext/patches/v13_0/update_level_in_bom.py
index 0d03c42e980..6223500e6b6 100644
--- a/erpnext/patches/v13_0/update_level_in_bom.py
+++ b/erpnext/patches/v13_0/update_level_in_bom.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
for document in ["bom", "bom_item", "bom_explosion_item"]:
frappe.reload_doc('manufacturing', 'doctype', document)
diff --git a/erpnext/patches/v13_0/update_member_email_address.py b/erpnext/patches/v13_0/update_member_email_address.py
index 4056f84069c..769658e2b8a 100644
--- a/erpnext/patches/v13_0/update_member_email_address.py
+++ b/erpnext/patches/v13_0/update_member_email_address.py
@@ -2,9 +2,11 @@
# MIT License. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
"""add value to email_id column from email"""
diff --git a/erpnext/patches/v13_0/update_old_loans.py b/erpnext/patches/v13_0/update_old_loans.py
index 8cf09aa6925..b01a87722ef 100644
--- a/erpnext/patches/v13_0/update_old_loans.py
+++ b/erpnext/patches/v13_0/update_old_loans.py
@@ -1,12 +1,18 @@
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import nowdate, flt
-from erpnext.accounts.doctype.account.test_account import create_account
-from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans
-from erpnext.loan_management.doctype.loan.loan import make_repayment_entry
-from erpnext.loan_management.doctype.loan_repayment.loan_repayment import get_accrued_interest_entries
from frappe.model.naming import make_autoname
+from frappe.utils import flt, nowdate
+
+from erpnext.accounts.doctype.account.test_account import create_account
+from erpnext.loan_management.doctype.loan_repayment.loan_repayment import (
+ get_accrued_interest_entries,
+)
+from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (
+ process_loan_interest_accrual_for_term_loans,
+)
+
def execute():
diff --git a/erpnext/patches/v13_0/update_payment_terms_outstanding.py b/erpnext/patches/v13_0/update_payment_terms_outstanding.py
index 4816b40250e..c9e920b7cb5 100644
--- a/erpnext/patches/v13_0/update_payment_terms_outstanding.py
+++ b/erpnext/patches/v13_0/update_payment_terms_outstanding.py
@@ -2,8 +2,10 @@
# MIT License. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("accounts", "doctype", "Payment Schedule")
if frappe.db.count('Payment Schedule'):
diff --git a/erpnext/patches/v13_0/update_pos_closing_entry_in_merge_log.py b/erpnext/patches/v13_0/update_pos_closing_entry_in_merge_log.py
index 262e38dd056..71fe9ed6805 100644
--- a/erpnext/patches/v13_0/update_pos_closing_entry_in_merge_log.py
+++ b/erpnext/patches/v13_0/update_pos_closing_entry_in_merge_log.py
@@ -2,8 +2,10 @@
# MIT License. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("accounts", "doctype", "POS Invoice Merge Log")
frappe.reload_doc("accounts", "doctype", "POS Closing Entry")
diff --git a/erpnext/patches/v13_0/update_project_template_tasks.py b/erpnext/patches/v13_0/update_project_template_tasks.py
index b41b74205c7..f0d0a5a7ef5 100644
--- a/erpnext/patches/v13_0/update_project_template_tasks.py
+++ b/erpnext/patches/v13_0/update_project_template_tasks.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("projects", "doctype", "project_template")
frappe.reload_doc("projects", "doctype", "project_template_task")
diff --git a/erpnext/patches/v13_0/update_reason_for_resignation_in_employee.py b/erpnext/patches/v13_0/update_reason_for_resignation_in_employee.py
index ccdc334f306..84075024a47 100644
--- a/erpnext/patches/v13_0/update_reason_for_resignation_in_employee.py
+++ b/erpnext/patches/v13_0/update_reason_for_resignation_in_employee.py
@@ -2,8 +2,10 @@
# MIT License. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("hr", "doctype", "employee")
diff --git a/erpnext/patches/v13_0/update_recipient_email_digest.py b/erpnext/patches/v13_0/update_recipient_email_digest.py
index ed90e126670..6cd27dc609c 100644
--- a/erpnext/patches/v13_0/update_recipient_email_digest.py
+++ b/erpnext/patches/v13_0/update_recipient_email_digest.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc("setup", "doctype", "Email Digest")
frappe.reload_doc("setup", "doctype", "Email Digest Recipient")
diff --git a/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py b/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py
index a5769d2957c..efb3a5961f9 100644
--- a/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py
+++ b/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py
@@ -1,8 +1,10 @@
# Copyright (c) 2021, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
import frappe
+
from erpnext.controllers.status_updater import OverAllowanceError
+
def execute():
frappe.reload_doc('stock', 'doctype', 'purchase_receipt')
frappe.reload_doc('stock', 'doctype', 'purchase_receipt_item')
diff --git a/erpnext/patches/v13_0/update_shipment_status.py b/erpnext/patches/v13_0/update_shipment_status.py
index c425599e26b..f2d7d1d1e3f 100644
--- a/erpnext/patches/v13_0/update_shipment_status.py
+++ b/erpnext/patches/v13_0/update_shipment_status.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
frappe.reload_doc("stock", "doctype", "shipment")
diff --git a/erpnext/patches/v13_0/update_sla_enhancements.py b/erpnext/patches/v13_0/update_sla_enhancements.py
index c156ba95772..bcfbf8b24cb 100644
--- a/erpnext/patches/v13_0/update_sla_enhancements.py
+++ b/erpnext/patches/v13_0/update_sla_enhancements.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
+
def execute():
# add holiday list and employee group fields in SLA
# change response and resolution time in priorities child table
diff --git a/erpnext/patches/v13_0/update_start_end_date_for_old_shift_assignment.py b/erpnext/patches/v13_0/update_start_end_date_for_old_shift_assignment.py
index 0f521cb57a8..bcdf72ec69c 100644
--- a/erpnext/patches/v13_0/update_start_end_date_for_old_shift_assignment.py
+++ b/erpnext/patches/v13_0/update_start_end_date_for_old_shift_assignment.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
+
def execute():
frappe.reload_doc('hr', 'doctype', 'shift_assignment')
if frappe.db.has_column('Shift Assignment', 'date'):
diff --git a/erpnext/patches/v13_0/update_subscription.py b/erpnext/patches/v13_0/update_subscription.py
index d25e9c805b7..e0ea78fa4d9 100644
--- a/erpnext/patches/v13_0/update_subscription.py
+++ b/erpnext/patches/v13_0/update_subscription.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from six import iteritems
+
def execute():
frappe.reload_doc('accounts', 'doctype', 'subscription')
diff --git a/erpnext/patches/v13_0/update_subscription_status_in_memberships.py b/erpnext/patches/v13_0/update_subscription_status_in_memberships.py
index d9c3e453d47..e21fe578212 100644
--- a/erpnext/patches/v13_0/update_subscription_status_in_memberships.py
+++ b/erpnext/patches/v13_0/update_subscription_status_in_memberships.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
if frappe.db.exists('DocType', 'Member'):
frappe.reload_doc('Non Profit', 'doctype', 'Member')
diff --git a/erpnext/patches/v13_0/update_tds_check_field.py b/erpnext/patches/v13_0/update_tds_check_field.py
index 341b0e8e2e2..436d2e6a6da 100644
--- a/erpnext/patches/v13_0/update_tds_check_field.py
+++ b/erpnext/patches/v13_0/update_tds_check_field.py
@@ -1,5 +1,6 @@
import frappe
+
def execute():
if frappe.db.has_table("Tax Withholding Category") \
and frappe.db.has_column("Tax Withholding Category", "round_off_tax_amount"):
diff --git a/erpnext/patches/v13_0/update_timesheet_changes.py b/erpnext/patches/v13_0/update_timesheet_changes.py
index a36c84ea6e2..d993d54191f 100644
--- a/erpnext/patches/v13_0/update_timesheet_changes.py
+++ b/erpnext/patches/v13_0/update_timesheet_changes.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.model.utils.rename_field import rename_field
+
def execute():
frappe.reload_doc("projects", "doctype", "timesheet")
frappe.reload_doc("projects", "doctype", "timesheet_detail")
diff --git a/erpnext/patches/v13_0/updates_for_multi_currency_payroll.py b/erpnext/patches/v13_0/updates_for_multi_currency_payroll.py
index 7d344f9cd7e..c760a6a52f1 100644
--- a/erpnext/patches/v13_0/updates_for_multi_currency_payroll.py
+++ b/erpnext/patches/v13_0/updates_for_multi_currency_payroll.py
@@ -5,6 +5,7 @@ import frappe
from frappe import _
from frappe.model.utils.rename_field import rename_field
+
def execute():
frappe.reload_doc('Accounts', 'doctype', 'Salary Component Account')
diff --git a/erpnext/patches/v13_0/validate_options_for_data_field.py b/erpnext/patches/v13_0/validate_options_for_data_field.py
index 568d1a4b0cb..41a38fe29c1 100644
--- a/erpnext/patches/v13_0/validate_options_for_data_field.py
+++ b/erpnext/patches/v13_0/validate_options_for_data_field.py
@@ -2,12 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model import data_field_options
+from frappe.model import data_field_options
+
def execute():
- for field in frappe.get_all('Custom Field',
+ for field in frappe.get_all('Custom Field',
fields = ['name'],
filters = {
'fieldtype': 'Data',
@@ -16,7 +18,7 @@ def execute():
if field not in data_field_options:
frappe.db.sql("""
- UPDATE
+ UPDATE
`tabCustom Field`
SET
options=NULL
diff --git a/erpnext/patches/v4_2/repost_reserved_qty.py b/erpnext/patches/v4_2/repost_reserved_qty.py
index 36117aad8cc..4fa3b468719 100644
--- a/erpnext/patches/v4_2/repost_reserved_qty.py
+++ b/erpnext/patches/v4_2/repost_reserved_qty.py
@@ -2,8 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from erpnext.stock.stock_balance import update_bin_qty, get_reserved_qty
+
+from erpnext.stock.stock_balance import get_reserved_qty, update_bin_qty
+
def execute():
for doctype in ("Sales Order Item", "Bin"):
diff --git a/erpnext/patches/v4_2/update_requested_and_ordered_qty.py b/erpnext/patches/v4_2/update_requested_and_ordered_qty.py
index 7bb49e64dfe..9330a443bf3 100644
--- a/erpnext/patches/v4_2/update_requested_and_ordered_qty.py
+++ b/erpnext/patches/v4_2/update_requested_and_ordered_qty.py
@@ -2,10 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
- from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty, get_ordered_qty
+ from erpnext.stock.stock_balance import get_indented_qty, get_ordered_qty, update_bin_qty
count=0
for item_code, warehouse in frappe.db.sql("""select distinct item_code, warehouse from
@@ -20,5 +22,5 @@ def execute():
})
if count % 200 == 0:
frappe.db.commit()
- except:
+ except Exception:
frappe.db.rollback()
diff --git a/erpnext/patches/v5_7/update_item_description_based_on_item_master.py b/erpnext/patches/v5_7/update_item_description_based_on_item_master.py
index 2045358ddb2..82b5b1cc2d2 100644
--- a/erpnext/patches/v5_7/update_item_description_based_on_item_master.py
+++ b/erpnext/patches/v5_7/update_item_description_based_on_item_master.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def execute():
name = frappe.db.sql(""" select name from `tabPatch Log` \
where \
diff --git a/erpnext/patches/v8_1/removed_roles_from_gst_report_non_indian_account.py b/erpnext/patches/v8_1/removed_roles_from_gst_report_non_indian_account.py
index 55f5f8201fb..ecfdc41f9b8 100644
--- a/erpnext/patches/v8_1/removed_roles_from_gst_report_non_indian_account.py
+++ b/erpnext/patches/v8_1/removed_roles_from_gst_report_non_indian_account.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute():
frappe.reload_doc('core', 'doctype', 'has_role')
company = frappe.get_all('Company', filters = {'country': 'India'})
diff --git a/erpnext/patches/v8_1/setup_gst_india.py b/erpnext/patches/v8_1/setup_gst_india.py
index c214990693c..140b22656b1 100644
--- a/erpnext/patches/v8_1/setup_gst_india.py
+++ b/erpnext/patches/v8_1/setup_gst_india.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
+
import frappe
from frappe.email import sendmail_to_system_managers
+
def execute():
frappe.reload_doc('stock', 'doctype', 'item')
frappe.reload_doc("stock", "doctype", "customs_tariff_number")
diff --git a/erpnext/patches/v8_7/sync_india_custom_fields.py b/erpnext/patches/v8_7/sync_india_custom_fields.py
index eb24a90f013..65ec14e8826 100644
--- a/erpnext/patches/v8_7/sync_india_custom_fields.py
+++ b/erpnext/patches/v8_7/sync_india_custom_fields.py
@@ -1,6 +1,9 @@
from __future__ import unicode_literals
+
import frappe
-from erpnext.regional.india.setup import make_custom_fields
+
+from erpnext.regional.india.setup import make_custom_fields
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.py b/erpnext/payroll/doctype/additional_salary/additional_salary.py
index 381f399e9fa..ed10f2bc67a 100644
--- a/erpnext/payroll/doctype/additional_salary/additional_salary.py
+++ b/erpnext/payroll/doctype/additional_salary/additional_salary.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
from frappe import _, bold
-from frappe.utils import getdate, date_diff, comma_and, formatdate
+from frappe.model.document import Document
+from frappe.utils import comma_and, date_diff, formatdate, getdate
+
from erpnext.hr.utils import validate_active_employee
+
class AdditionalSalary(Document):
def on_submit(self):
if self.ref_doctype == "Employee Advance" and self.ref_docname:
diff --git a/erpnext/payroll/doctype/additional_salary/test_additional_salary.js b/erpnext/payroll/doctype/additional_salary/test_additional_salary.js
deleted file mode 100644
index c18e1875854..00000000000
--- a/erpnext/payroll/doctype/additional_salary/test_additional_salary.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Additional Salary", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Additional Salary
- () => frappe.tests.make('Additional Salary', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/payroll/doctype/additional_salary/test_additional_salary.py b/erpnext/payroll/doctype/additional_salary/test_additional_salary.py
index 2a9c56179e7..2ad4afef251 100644
--- a/erpnext/payroll/doctype/additional_salary/test_additional_salary.py
+++ b/erpnext/payroll/doctype/additional_salary/test_additional_salary.py
@@ -2,12 +2,19 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
-import frappe, erpnext
-from frappe.utils import nowdate, add_days
+
+import frappe
+from frappe.utils import add_days, nowdate
+
+import erpnext
from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.payroll.doctype.salary_component.test_salary_component import create_salary_component
-from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_employee_salary_slip, setup_test
+from erpnext.payroll.doctype.salary_slip.test_salary_slip import (
+ make_employee_salary_slip,
+ setup_test,
+)
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
diff --git a/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py b/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py
index a1cde08a74c..9983f012875 100644
--- a/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py
+++ b/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py
@@ -3,13 +3,26 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import date_diff, getdate, rounded, add_days, cstr, cint, flt
from frappe.model.document import Document
-from erpnext.payroll.doctype.payroll_period.payroll_period import get_payroll_period_days, get_period_factor
-from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
-from erpnext.hr.utils import get_sal_slip_total_benefit_given, get_holiday_dates_for_employee, get_previous_claimed_amount, validate_active_employee
+from frappe.utils import add_days, cint, cstr, date_diff, getdate, rounded
+
+from erpnext.hr.utils import (
+ get_holiday_dates_for_employee,
+ get_previous_claimed_amount,
+ get_sal_slip_total_benefit_given,
+ validate_active_employee,
+)
+from erpnext.payroll.doctype.payroll_period.payroll_period import (
+ get_payroll_period_days,
+ get_period_factor,
+)
+from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import (
+ get_assigned_salary_structure,
+)
+
class EmployeeBenefitApplication(Document):
def validate(self):
diff --git a/erpnext/payroll/doctype/employee_benefit_application/test_employee_benefit_application.js b/erpnext/payroll/doctype/employee_benefit_application/test_employee_benefit_application.js
deleted file mode 100644
index b355e1c4366..00000000000
--- a/erpnext/payroll/doctype/employee_benefit_application/test_employee_benefit_application.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Benefit Application", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Benefit Application
- () => frappe.tests.make('Employee Benefit Application', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/payroll/doctype/employee_benefit_application/test_employee_benefit_application.py b/erpnext/payroll/doctype/employee_benefit_application/test_employee_benefit_application.py
index 34e1a8fbc1d..ea05e0e0e05 100644
--- a/erpnext/payroll/doctype/employee_benefit_application/test_employee_benefit_application.py
+++ b/erpnext/payroll/doctype/employee_benefit_application/test_employee_benefit_application.py
@@ -2,7 +2,9 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestEmployeeBenefitApplication(unittest.TestCase):
pass
diff --git a/erpnext/payroll/doctype/employee_benefit_application_detail/employee_benefit_application_detail.py b/erpnext/payroll/doctype/employee_benefit_application_detail/employee_benefit_application_detail.py
index 65405feaf19..ddcbaa20619 100644
--- a/erpnext/payroll/doctype/employee_benefit_application_detail/employee_benefit_application_detail.py
+++ b/erpnext/payroll/doctype/employee_benefit_application_detail/employee_benefit_application_detail.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class EmployeeBenefitApplicationDetail(Document):
pass
diff --git a/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.py b/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.py
index c6713f3aa46..7898e04cf44 100644
--- a/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.py
+++ b/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.py
@@ -3,14 +3,21 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt
from frappe.model.document import Document
-from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application import get_max_benefits
+from frappe.utils import flt
+
from erpnext.hr.utils import get_previous_claimed_amount, validate_active_employee
+from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application import (
+ get_max_benefits,
+)
from erpnext.payroll.doctype.payroll_period.payroll_period import get_payroll_period
-from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
+from erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment import (
+ get_assigned_salary_structure,
+)
+
class EmployeeBenefitClaim(Document):
def validate(self):
diff --git a/erpnext/payroll/doctype/employee_benefit_claim/test_employee_benefit_claim.js b/erpnext/payroll/doctype/employee_benefit_claim/test_employee_benefit_claim.js
deleted file mode 100644
index 3c808c0a560..00000000000
--- a/erpnext/payroll/doctype/employee_benefit_claim/test_employee_benefit_claim.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Benefit Claim", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Benefit Claim
- () => frappe.tests.make('Employee Benefit Claim', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/payroll/doctype/employee_benefit_claim/test_employee_benefit_claim.py b/erpnext/payroll/doctype/employee_benefit_claim/test_employee_benefit_claim.py
index aff73e5c816..f3f2229fb2e 100644
--- a/erpnext/payroll/doctype/employee_benefit_claim/test_employee_benefit_claim.py
+++ b/erpnext/payroll/doctype/employee_benefit_claim/test_employee_benefit_claim.py
@@ -2,7 +2,9 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
import unittest
+
class TestEmployeeBenefitClaim(unittest.TestCase):
pass
diff --git a/erpnext/payroll/doctype/employee_incentive/employee_incentive.py b/erpnext/payroll/doctype/employee_incentive/employee_incentive.py
index 6b918ba76d1..74d073668d7 100644
--- a/erpnext/payroll/doctype/employee_incentive/employee_incentive.py
+++ b/erpnext/payroll/doctype/employee_incentive/employee_incentive.py
@@ -3,11 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
from erpnext.hr.utils import validate_active_employee
+
class EmployeeIncentive(Document):
def validate(self):
validate_active_employee(self.employee)
diff --git a/erpnext/payroll/doctype/employee_incentive/test_employee_incentive.js b/erpnext/payroll/doctype/employee_incentive/test_employee_incentive.js
deleted file mode 100644
index 10bc03701fd..00000000000
--- a/erpnext/payroll/doctype/employee_incentive/test_employee_incentive.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Incentive", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Incentive
- () => frappe.tests.make('Employee Incentive', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/payroll/doctype/employee_incentive/test_employee_incentive.py b/erpnext/payroll/doctype/employee_incentive/test_employee_incentive.py
index f7597ad6057..3c95fa80ec0 100644
--- a/erpnext/payroll/doctype/employee_incentive/test_employee_incentive.py
+++ b/erpnext/payroll/doctype/employee_incentive/test_employee_incentive.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestEmployeeIncentive(unittest.TestCase):
pass
diff --git a/erpnext/payroll/doctype/employee_other_income/employee_other_income.py b/erpnext/payroll/doctype/employee_other_income/employee_other_income.py
index ab63c0de623..73a0321c8fe 100644
--- a/erpnext/payroll/doctype/employee_other_income/employee_other_income.py
+++ b/erpnext/payroll/doctype/employee_other_income/employee_other_income.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class EmployeeOtherIncome(Document):
pass
diff --git a/erpnext/payroll/doctype/employee_other_income/test_employee_other_income.py b/erpnext/payroll/doctype/employee_other_income/test_employee_other_income.py
index 2eeca7a23de..5b735b37a16 100644
--- a/erpnext/payroll/doctype/employee_other_income/test_employee_other_income.py
+++ b/erpnext/payroll/doctype/employee_other_income/test_employee_other_income.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestEmployeeOtherIncome(unittest.TestCase):
pass
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_category/employee_tax_exemption_category.py b/erpnext/payroll/doctype/employee_tax_exemption_category/employee_tax_exemption_category.py
index 4f705db22e5..f88f551a2ee 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_category/employee_tax_exemption_category.py
+++ b/erpnext/payroll/doctype/employee_tax_exemption_category/employee_tax_exemption_category.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class EmployeeTaxExemptionCategory(Document):
pass
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_category/test_employee_tax_exemption_category.js b/erpnext/payroll/doctype/employee_tax_exemption_category/test_employee_tax_exemption_category.js
deleted file mode 100644
index e0e43c32e3b..00000000000
--- a/erpnext/payroll/doctype/employee_tax_exemption_category/test_employee_tax_exemption_category.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Tax Exemption Category", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Tax Exemption Category
- () => frappe.tests.make('Employee Tax Exemption Category', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_category/test_employee_tax_exemption_category.py b/erpnext/payroll/doctype/employee_tax_exemption_category/test_employee_tax_exemption_category.py
index 669fb71f46e..e6bc3abf127 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_category/test_employee_tax_exemption_category.py
+++ b/erpnext/payroll/doctype/employee_tax_exemption_category/test_employee_tax_exemption_category.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestEmployeeTaxExemptionCategory(unittest.TestCase):
pass
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py b/erpnext/payroll/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py
index e11d60a4649..099ab0dcde0 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py
+++ b/erpnext/payroll/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py
@@ -3,13 +3,20 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
-from frappe import _
-from frappe.utils import flt
from frappe.model.mapper import get_mapped_doc
-from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, validate_active_employee, \
- calculate_annual_eligible_hra_exemption, validate_duplicate_exemption_for_payroll_period
+from frappe.utils import flt
+
+from erpnext.hr.utils import (
+ calculate_annual_eligible_hra_exemption,
+ get_total_exemption_amount,
+ validate_active_employee,
+ validate_duplicate_exemption_for_payroll_period,
+ validate_tax_declaration,
+)
+
class EmployeeTaxExemptionDeclaration(Document):
def validate(self):
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.js b/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.js
deleted file mode 100644
index 274a3a38603..00000000000
--- a/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Tax Exemption Declaration", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Tax Exemption Declaration
- () => frappe.tests.make('Employee Tax Exemption Declaration', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py b/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py
index 311f3527f6e..b7154a4da15 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py
+++ b/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py
@@ -3,11 +3,15 @@
# See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
import unittest
+
+import frappe
+
+import erpnext
from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.hr.utils import DuplicateDeclarationError
+
class TestEmployeeTaxExemptionDeclaration(unittest.TestCase):
def setUp(self):
make_employee("employee@taxexepmtion.com")
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.py b/erpnext/payroll/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.py
index bff747f90de..2923e57333d 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.py
+++ b/erpnext/payroll/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class EmployeeTaxExemptionDeclarationCategory(Document):
pass
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py
index 8131ae0fa85..f35fd3caf90 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py
+++ b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py
@@ -3,12 +3,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
-from frappe import _
from frappe.utils import flt
-from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, validate_active_employee, \
- calculate_hra_exemption_for_period, validate_duplicate_exemption_for_payroll_period
+
+from erpnext.hr.utils import (
+ calculate_hra_exemption_for_period,
+ get_total_exemption_amount,
+ validate_active_employee,
+ validate_duplicate_exemption_for_payroll_period,
+ validate_tax_declaration,
+)
+
class EmployeeTaxExemptionProofSubmission(Document):
def validate(self):
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.js b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.js
deleted file mode 100644
index cec75087280..00000000000
--- a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Tax Exemption Proof Submission", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Tax Exemption Proof Submission
- () => frappe.tests.make('Employee Tax Exemption Proof Submission', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.py b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.py
index cb9ed5f971c..aafc0a13211 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.py
+++ b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.py
@@ -3,9 +3,15 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from erpnext.payroll.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration import create_exemption_category, create_payroll_period
+
+import frappe
+
+from erpnext.payroll.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration import (
+ create_exemption_category,
+ create_payroll_period,
+)
+
class TestEmployeeTaxExemptionProofSubmission(unittest.TestCase):
def setup(self):
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.py b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.py
index 0244ae66468..e0a11aec162 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.py
+++ b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class EmployeeTaxExemptionProofSubmissionDetail(Document):
pass
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py b/erpnext/payroll/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py
index d3f24c93780..5948ef208bf 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py
+++ b/erpnext/payroll/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt
from frappe.model.document import Document
+from frappe.utils import flt
+
class EmployeeTaxExemptionSubCategory(Document):
def validate(self):
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.js b/erpnext/payroll/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.js
deleted file mode 100644
index 8a1a6d151dd..00000000000
--- a/erpnext/payroll/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Employee Tax Exemption Sub Category", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Employee Tax Exemption Sub Category
- () => frappe.tests.make('Employee Tax Exemption Sub Category', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/payroll/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.py b/erpnext/payroll/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.py
index 5d705567a2d..0086086bde6 100644
--- a/erpnext/payroll/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.py
+++ b/erpnext/payroll/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestEmployeeTaxExemptionSubCategory(unittest.TestCase):
pass
diff --git a/erpnext/payroll/doctype/gratuity/gratuity.py b/erpnext/payroll/doctype/gratuity/gratuity.py
index 8cb804db6fa..1e287729808 100644
--- a/erpnext/payroll/doctype/gratuity/gratuity.py
+++ b/erpnext/payroll/doctype/gratuity/gratuity.py
@@ -3,12 +3,16 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
+from math import floor
+
import frappe
from frappe import _, bold
from frappe.utils import flt, get_datetime, get_link_to_form
+
from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.controllers.accounts_controller import AccountsController
-from math import floor
+
class Gratuity(AccountsController):
def validate(self):
@@ -242,7 +246,11 @@ def get_salary_structure(employee):
order_by = "from_date desc")[0].salary_structure
def get_last_salary_slip(employee):
- return frappe.get_list("Salary Slip", filters = {
+ salary_slips = frappe.get_list("Salary Slip", filters = {
"employee": employee, 'docstatus': 1
},
- order_by = "start_date desc")[0].name
+ order_by = "start_date desc"
+ )
+ if not salary_slips:
+ return
+ return salary_slips[0].name
diff --git a/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py b/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
index 483e346a32d..d0fda57016c 100644
--- a/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
+++ b/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'reference_name',
diff --git a/erpnext/payroll/doctype/gratuity/test_gratuity.py b/erpnext/payroll/doctype/gratuity/test_gratuity.py
index 7daea2da474..66cbbd7d149 100644
--- a/erpnext/payroll/doctype/gratuity/test_gratuity.py
+++ b/erpnext/payroll/doctype/gratuity/test_gratuity.py
@@ -3,15 +3,20 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
+from frappe.utils import add_days, flt, get_datetime, getdate
+
from erpnext.hr.doctype.employee.test_employee import make_employee
-from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_employee_salary_slip, make_earning_salary_component, \
- make_deduction_salary_component
-from erpnext.payroll.doctype.gratuity.gratuity import get_last_salary_slip
-from erpnext.regional.united_arab_emirates.setup import create_gratuity_rule
from erpnext.hr.doctype.expense_claim.test_expense_claim import get_payable_account
-from frappe.utils import getdate, add_days, get_datetime, flt
+from erpnext.payroll.doctype.gratuity.gratuity import get_last_salary_slip
+from erpnext.payroll.doctype.salary_slip.test_salary_slip import (
+ make_deduction_salary_component,
+ make_earning_salary_component,
+ make_employee_salary_slip,
+)
+from erpnext.regional.united_arab_emirates.setup import create_gratuity_rule
test_dependencies = ["Salary Component", "Salary Slip", "Account"]
class TestGratuity(unittest.TestCase):
@@ -24,6 +29,11 @@ class TestGratuity(unittest.TestCase):
frappe.db.sql("DELETE FROM `tabGratuity`")
frappe.db.sql("DELETE FROM `tabAdditional Salary` WHERE ref_doctype = 'Gratuity'")
+ def test_get_last_salary_slip_should_return_none_for_new_employee(self):
+ new_employee = make_employee("new_employee@salary.com", company='_Test Company')
+ salary_slip = get_last_salary_slip(new_employee)
+ assert salary_slip is None
+
def test_check_gratuity_amount_based_on_current_slab_and_additional_salary_creation(self):
employee, sal_slip = create_employee_and_get_last_salary_slip()
diff --git a/erpnext/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.py b/erpnext/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.py
index 23e4340b04f..d76b26d05f6 100644
--- a/erpnext/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.py
+++ b/erpnext/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class GratuityApplicableComponent(Document):
pass
diff --git a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.py b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.py
index 29a6ebe1a6a..95d2929fffa 100644
--- a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.py
+++ b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.py
@@ -3,16 +3,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
from frappe import _
+from frappe.model.document import Document
+
class GratuityRule(Document):
def validate(self):
for current_slab in self.gratuity_rule_slabs:
if (current_slab.from_year > current_slab.to_year) and current_slab.to_year != 0:
- frappe(_("Row {0}: From (Year) can not be greater than To (Year)").format(current_slab.idx))
+ frappe.throw(_("Row {0}: From (Year) can not be greater than To (Year)").format(current_slab.idx))
if current_slab.to_year == 0 and current_slab.from_year == 0 and len(self.gratuity_rule_slabs) > 1:
frappe.throw(_("You can not define multiple slabs if you have a slab with no lower and upper limits."))
diff --git a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py
index 0f27315cfbf..60dcfa45297 100644
--- a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py
+++ b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'gratuity_rule',
diff --git a/erpnext/payroll/doctype/gratuity_rule/test_gratuity_rule.py b/erpnext/payroll/doctype/gratuity_rule/test_gratuity_rule.py
index 1f5dc4e571e..c81d7b7b9e6 100644
--- a/erpnext/payroll/doctype/gratuity_rule/test_gratuity_rule.py
+++ b/erpnext/payroll/doctype/gratuity_rule/test_gratuity_rule.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestGratuityRule(unittest.TestCase):
pass
diff --git a/erpnext/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.py b/erpnext/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.py
index fa468e77beb..dcd7e468655 100644
--- a/erpnext/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.py
+++ b/erpnext/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class GratuityRuleSlab(Document):
pass
diff --git a/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py b/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py
index 81e364778ca..f778fd90e13 100644
--- a/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py
+++ b/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py
@@ -3,9 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
+from frappe.model.document import Document
+
#import frappe
import erpnext
-from frappe.model.document import Document
+
class IncomeTaxSlab(Document):
def validate(self):
diff --git a/erpnext/payroll/doctype/income_tax_slab/test_income_tax_slab.py b/erpnext/payroll/doctype/income_tax_slab/test_income_tax_slab.py
index deaaf650a96..d76299049de 100644
--- a/erpnext/payroll/doctype/income_tax_slab/test_income_tax_slab.py
+++ b/erpnext/payroll/doctype/income_tax_slab/test_income_tax_slab.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestIncomeTaxSlab(unittest.TestCase):
pass
diff --git a/erpnext/payroll/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.py b/erpnext/payroll/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.py
index b4098ecbf3e..3314677485f 100644
--- a/erpnext/payroll/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.py
+++ b/erpnext/payroll/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class IncomeTaxSlabOtherCharges(Document):
pass
diff --git a/erpnext/payroll/doctype/payroll_employee_detail/payroll_employee_detail.py b/erpnext/payroll/doctype/payroll_employee_detail/payroll_employee_detail.py
index aeb11fd7e27..074d2232245 100644
--- a/erpnext/payroll/doctype/payroll_employee_detail/payroll_employee_detail.py
+++ b/erpnext/payroll/doctype/payroll_employee_detail/payroll_employee_detail.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class PayrollEmployeeDetail(Document):
pass
diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
index 13cc423fc2c..f1557c78a37 100644
--- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
+++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
@@ -3,15 +3,30 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-from frappe.model.document import Document
+
+import frappe
from dateutil.relativedelta import relativedelta
-from frappe.utils import cint, flt, add_days, getdate, add_to_date, DATE_FORMAT, date_diff, comma_and
from frappe import _
+from frappe.desk.reportview import get_filters_cond, get_match_cond
+from frappe.model.document import Document
+from frappe.utils import (
+ DATE_FORMAT,
+ add_days,
+ add_to_date,
+ cint,
+ comma_and,
+ date_diff,
+ flt,
+ getdate,
+)
+
+import erpnext
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
+ get_accounting_dimensions,
+)
from erpnext.accounts.utils import get_fiscal_year
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
-from frappe.desk.reportview import get_match_cond, get_filters_cond
-from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
+
class PayrollEntry(Document):
def onload(self):
@@ -529,7 +544,8 @@ def get_end_date(start_date, frequency):
def get_month_details(year, month):
ysd = frappe.db.get_value("Fiscal Year", year, "year_start_date")
if ysd:
- import calendar, datetime
+ import calendar
+ import datetime
diff_mnt = cint(month)-cint(ysd.month)
if diff_mnt<0:
diff_mnt = 12-int(ysd.month)+cint(month)
diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry_dashboard.py b/erpnext/payroll/doctype/payroll_entry/payroll_entry_dashboard.py
index 0346a7cc594..16e44d08684 100644
--- a/erpnext/payroll/doctype/payroll_entry/payroll_entry_dashboard.py
+++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
index b80b32061f3..dd0e1270800 100644
--- a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
+++ b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
@@ -1,19 +1,37 @@
# 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 erpnext
+
import frappe
from dateutil.relativedelta import relativedelta
-from erpnext.accounts.utils import get_fiscal_year, getdate, nowdate
from frappe.utils import add_months
-from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_start_end_dates, get_end_date
+
+import erpnext
+from erpnext.accounts.utils import get_fiscal_year, getdate, nowdate
from erpnext.hr.doctype.employee.test_employee import make_employee
-from erpnext.payroll.doctype.salary_slip.test_salary_slip import get_salary_component_account, \
- make_earning_salary_component, make_deduction_salary_component, create_account, make_employee_salary_slip
-from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure, create_salary_structure_assignment
-from erpnext.loan_management.doctype.loan.test_loan import create_loan, make_loan_disbursement_entry, create_loan_type, create_loan_accounts
-from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans
+from erpnext.loan_management.doctype.loan.test_loan import (
+ create_loan,
+ create_loan_accounts,
+ create_loan_type,
+ make_loan_disbursement_entry,
+)
+from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (
+ process_loan_interest_accrual_for_term_loans,
+)
+from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_end_date, get_start_end_dates
+from erpnext.payroll.doctype.salary_slip.test_salary_slip import (
+ create_account,
+ get_salary_component_account,
+ make_deduction_salary_component,
+ make_earning_salary_component,
+ make_employee_salary_slip,
+)
+from erpnext.payroll.doctype.salary_structure.test_salary_structure import (
+ create_salary_structure_assignment,
+ make_salary_structure,
+)
test_dependencies = ['Holiday List']
diff --git a/erpnext/payroll/doctype/payroll_period/payroll_period.py b/erpnext/payroll/doctype/payroll_period/payroll_period.py
index 66dec075d8f..0de8d63df73 100644
--- a/erpnext/payroll/doctype/payroll_period/payroll_period.py
+++ b/erpnext/payroll/doctype/payroll_period/payroll_period.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import date_diff, getdate, formatdate, cint, month_diff, flt, add_months
from frappe.model.document import Document
+from frappe.utils import add_months, cint, date_diff, flt, formatdate, getdate, month_diff
+
from erpnext.hr.utils import get_holiday_dates_for_employee
+
class PayrollPeriod(Document):
def validate(self):
self.validate_dates()
diff --git a/erpnext/payroll/doctype/payroll_period/payroll_period_dashboard.py b/erpnext/payroll/doctype/payroll_period/payroll_period_dashboard.py
index e33299559cc..4105d8ee928 100644
--- a/erpnext/payroll/doctype/payroll_period/payroll_period_dashboard.py
+++ b/erpnext/payroll/doctype/payroll_period/payroll_period_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/payroll/doctype/payroll_period/test_payroll_period.js b/erpnext/payroll/doctype/payroll_period/test_payroll_period.js
deleted file mode 100644
index 8c4ded96f38..00000000000
--- a/erpnext/payroll/doctype/payroll_period/test_payroll_period.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Payroll Period", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Payroll Period
- () => frappe.tests.make('Payroll Period', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/payroll/doctype/payroll_period/test_payroll_period.py b/erpnext/payroll/doctype/payroll_period/test_payroll_period.py
index d06dc739a6e..e93c0e524de 100644
--- a/erpnext/payroll/doctype/payroll_period/test_payroll_period.py
+++ b/erpnext/payroll/doctype/payroll_period/test_payroll_period.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestPayrollPeriod(unittest.TestCase):
pass
diff --git a/erpnext/payroll/doctype/payroll_period_date/payroll_period_date.py b/erpnext/payroll/doctype/payroll_period_date/payroll_period_date.py
index a3ee269d8e6..fa6835da53b 100644
--- a/erpnext/payroll/doctype/payroll_period_date/payroll_period_date.py
+++ b/erpnext/payroll/doctype/payroll_period_date/payroll_period_date.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class PayrollPeriodDate(Document):
pass
diff --git a/erpnext/payroll/doctype/payroll_settings/payroll_settings.py b/erpnext/payroll/doctype/payroll_settings/payroll_settings.py
index 459b7eacb43..b85d5545d04 100644
--- a/erpnext/payroll/doctype/payroll_settings/payroll_settings.py
+++ b/erpnext/payroll/doctype/payroll_settings/payroll_settings.py
@@ -3,11 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
+from frappe import _
+from frappe.custom.doctype.property_setter.property_setter import make_property_setter
from frappe.model.document import Document
from frappe.utils import cint
-from frappe.custom.doctype.property_setter.property_setter import make_property_setter
-from frappe import _
+
class PayrollSettings(Document):
def validate(self):
diff --git a/erpnext/payroll/doctype/payroll_settings/test_payroll_settings.py b/erpnext/payroll/doctype/payroll_settings/test_payroll_settings.py
index 314866e128e..30a6a332b7c 100644
--- a/erpnext/payroll/doctype/payroll_settings/test_payroll_settings.py
+++ b/erpnext/payroll/doctype/payroll_settings/test_payroll_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestPayrollSettings(unittest.TestCase):
pass
diff --git a/erpnext/payroll/doctype/retention_bonus/retention_bonus.py b/erpnext/payroll/doctype/retention_bonus/retention_bonus.py
index 055bea74108..7e731e7fce1 100644
--- a/erpnext/payroll/doctype/retention_bonus/retention_bonus.py
+++ b/erpnext/payroll/doctype/retention_bonus/retention_bonus.py
@@ -3,11 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
from frappe import _
+from frappe.model.document import Document
from frappe.utils import getdate
+
from erpnext.hr.utils import validate_active_employee
+
+
class RetentionBonus(Document):
def validate(self):
validate_active_employee(self.employee)
diff --git a/erpnext/payroll/doctype/retention_bonus/test_retention_bonus.js b/erpnext/payroll/doctype/retention_bonus/test_retention_bonus.js
deleted file mode 100644
index a4b95d3cb10..00000000000
--- a/erpnext/payroll/doctype/retention_bonus/test_retention_bonus.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Retention Bonus", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Retention Bonus
- () => frappe.tests.make('Retention Bonus', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/payroll/doctype/retention_bonus/test_retention_bonus.py b/erpnext/payroll/doctype/retention_bonus/test_retention_bonus.py
index eef4f1444e1..a380d9fb44a 100644
--- a/erpnext/payroll/doctype/retention_bonus/test_retention_bonus.py
+++ b/erpnext/payroll/doctype/retention_bonus/test_retention_bonus.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestRetentionBonus(unittest.TestCase):
pass
diff --git a/erpnext/payroll/doctype/salary_component/salary_component.js b/erpnext/payroll/doctype/salary_component/salary_component.js
index e9e6f81862c..dbf75140ac1 100644
--- a/erpnext/payroll/doctype/salary_component/salary_component.js
+++ b/erpnext/payroll/doctype/salary_component/salary_component.js
@@ -4,18 +4,11 @@
frappe.ui.form.on('Salary Component', {
setup: function(frm) {
frm.set_query("account", "accounts", function(doc, cdt, cdn) {
- let d = frappe.get_doc(cdt, cdn);
-
- let root_type = "Liability";
- if (frm.doc.type == "Deduction") {
- root_type = "Expense";
- }
-
+ var d = locals[cdt][cdn];
return {
filters: {
"is_group": 0,
- "company": d.company,
- "root_type": root_type
+ "company": d.company
}
};
});
diff --git a/erpnext/payroll/doctype/salary_component/salary_component.py b/erpnext/payroll/doctype/salary_component/salary_component.py
index 7c926314a21..761d4436f37 100644
--- a/erpnext/payroll/doctype/salary_component/salary_component.py
+++ b/erpnext/payroll/doctype/salary_component/salary_component.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
from frappe.model.naming import append_number_if_name_exists
+
class SalaryComponent(Document):
def validate(self):
self.validate_abbr()
diff --git a/erpnext/payroll/doctype/salary_component/test_salary_component.js b/erpnext/payroll/doctype/salary_component/test_salary_component.js
deleted file mode 100644
index c47d32d9965..00000000000
--- a/erpnext/payroll/doctype/salary_component/test_salary_component.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Salary Component", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Salary Component
- () => frappe.tests.make('Salary Component', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/payroll/doctype/salary_component/test_salary_component.py b/erpnext/payroll/doctype/salary_component/test_salary_component.py
index 4f7db0c71ca..939fa4aade1 100644
--- a/erpnext/payroll/doctype/salary_component/test_salary_component.py
+++ b/erpnext/payroll/doctype/salary_component/test_salary_component.py
@@ -3,9 +3,10 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
# test_records = frappe.get_test_records('Salary Component')
class TestSalaryComponent(unittest.TestCase):
diff --git a/erpnext/payroll/doctype/salary_detail/salary_detail.py b/erpnext/payroll/doctype/salary_detail/salary_detail.py
index 0b187543d48..50d1958caec 100644
--- a/erpnext/payroll/doctype/salary_detail/salary_detail.py
+++ b/erpnext/payroll/doctype/salary_detail/salary_detail.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class SalaryDetail(Document):
pass
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.js b/erpnext/payroll/doctype/salary_slip/salary_slip.js
index 5258f3aff9e..3ef9762a839 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.js
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.js
@@ -135,15 +135,15 @@ frappe.ui.form.on("Salary Slip", {
change_form_labels: function(frm, company_currency) {
frm.set_currency_labels(["base_hour_rate", "base_gross_pay", "base_total_deduction",
- "base_net_pay", "base_rounded_total", "base_total_in_words", "base_year_to_date", "base_month_to_date"],
+ "base_net_pay", "base_rounded_total", "base_total_in_words", "base_year_to_date", "base_month_to_date", "gross_base_year_to_date"],
company_currency);
- frm.set_currency_labels(["hour_rate", "gross_pay", "total_deduction", "net_pay", "rounded_total", "total_in_words", "year_to_date", "month_to_date"],
+ frm.set_currency_labels(["hour_rate", "gross_pay", "total_deduction", "net_pay", "rounded_total", "total_in_words", "year_to_date", "month_to_date", "gross_year_to_date"],
frm.doc.currency);
// toggle fields
frm.toggle_display(["exchange_rate", "base_hour_rate", "base_gross_pay", "base_total_deduction",
- "base_net_pay", "base_rounded_total", "base_total_in_words", "base_year_to_date", "base_month_to_date"],
+ "base_net_pay", "base_rounded_total", "base_total_in_words", "base_year_to_date", "base_month_to_date", "base_gross_year_to_date"],
frm.doc.currency != company_currency);
},
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.json b/erpnext/payroll/doctype/salary_slip/salary_slip.json
index 42a0f290cb4..fbbf86c4a98 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.json
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.json
@@ -56,6 +56,8 @@
"totals",
"gross_pay",
"base_gross_pay",
+ "gross_year_to_date",
+ "base_gross_year_to_date",
"column_break_25",
"total_deduction",
"base_total_deduction",
@@ -625,13 +627,27 @@
"label": "Leave Details",
"options": "Salary Slip Leave",
"read_only": 1
+ },
+ {
+ "fieldname": "gross_year_to_date",
+ "fieldtype": "Currency",
+ "label": "Gross Year To Date",
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "base_gross_year_to_date",
+ "fieldtype": "Currency",
+ "label": "Gross Year To Date(Company Currency)",
+ "options": "Company:company:default_currency",
+ "read_only": 1
}
],
"icon": "fa fa-file-text",
"idx": 9,
"is_submittable": 1,
"links": [],
- "modified": "2021-03-31 22:44:09.772331",
+ "modified": "2021-09-01 10:22:52.374549",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Salary Slip",
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index fbe4742e21c..888150f0ae3 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -2,27 +2,51 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-import datetime, math
-from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words, formatdate, get_first_day
+import datetime
+import math
+
+import frappe
+from frappe import _, msgprint
from frappe.model.naming import make_autoname
-
-from frappe import msgprint, _
-from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_start_end_dates
-from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
-from erpnext.hr.utils import get_holiday_dates_for_employee
-from erpnext.utilities.transaction_base import TransactionBase
+from frappe.utils import (
+ add_days,
+ cint,
+ cstr,
+ date_diff,
+ flt,
+ formatdate,
+ get_first_day,
+ getdate,
+ money_in_words,
+ rounded,
+)
from frappe.utils.background_jobs import enqueue
-from erpnext.payroll.doctype.additional_salary.additional_salary import get_additional_salaries
-from erpnext.payroll.doctype.payroll_period.payroll_period import get_period_factor, get_payroll_period
-from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application import get_benefit_component_amount
-from erpnext.payroll.doctype.employee_benefit_claim.employee_benefit_claim import get_benefit_claim_amount, get_last_payroll_period_benefits
-from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts, create_repayment_entry
-from erpnext.accounts.utils import get_fiscal_year
-from erpnext.hr.utils import validate_active_employee
from six import iteritems
+import erpnext
+from erpnext.accounts.utils import get_fiscal_year
+from erpnext.hr.utils import get_holiday_dates_for_employee, validate_active_employee
+from erpnext.loan_management.doctype.loan_repayment.loan_repayment import (
+ calculate_amounts,
+ create_repayment_entry,
+)
+from erpnext.payroll.doctype.additional_salary.additional_salary import get_additional_salaries
+from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application import (
+ get_benefit_component_amount,
+)
+from erpnext.payroll.doctype.employee_benefit_claim.employee_benefit_claim import (
+ get_benefit_claim_amount,
+ get_last_payroll_period_benefits,
+)
+from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_start_end_dates
+from erpnext.payroll.doctype.payroll_period.payroll_period import (
+ get_payroll_period,
+ get_period_factor,
+)
+from erpnext.utilities.transaction_base import TransactionBase
+
+
class SalarySlip(TransactionBase):
def __init__(self, *args, **kwargs):
super(SalarySlip, self).__init__(*args, **kwargs)
@@ -463,7 +487,7 @@ class SalarySlip(TransactionBase):
self.calculate_component_amounts("deductions")
self.set_loan_repayment()
- self.set_component_amounts_based_on_payment_days()
+ self.set_precision_for_component_amounts()
self.set_net_pay()
def set_net_pay(self):
@@ -689,6 +713,17 @@ class SalarySlip(TransactionBase):
component_row.amount = amount
+ self.update_component_amount_based_on_payment_days(component_row)
+
+ def update_component_amount_based_on_payment_days(self, component_row):
+ joining_date, relieving_date = self.get_joining_and_relieving_dates()
+ component_row.amount = self.get_amount_based_on_payment_days(component_row, joining_date, relieving_date)[0]
+
+ def set_precision_for_component_amounts(self):
+ for component_type in ("earnings", "deductions"):
+ for component_row in self.get(component_type):
+ component_row.amount = flt(component_row.amount, component_row.precision("amount"))
+
def calculate_variable_based_on_taxable_salary(self, tax_component, payroll_period):
if not payroll_period:
frappe.msgprint(_("Start and end dates not in a valid Payroll Period, cannot calculate {0}.")
@@ -846,14 +881,7 @@ class SalarySlip(TransactionBase):
return total_tax_paid
def get_taxable_earnings(self, allow_tax_exemption=False, based_on_payment_days=0):
- joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
- ["date_of_joining", "relieving_date"])
-
- if not relieving_date:
- relieving_date = getdate(self.end_date)
-
- if not joining_date:
- frappe.throw(_("Please set the Date Of Joining for employee {0}").format(frappe.bold(self.employee_name)))
+ joining_date, relieving_date = self.get_joining_and_relieving_dates()
taxable_earnings = 0
additional_income = 0
@@ -864,7 +892,10 @@ class SalarySlip(TransactionBase):
if based_on_payment_days:
amount, additional_amount = self.get_amount_based_on_payment_days(earning, joining_date, relieving_date)
else:
- amount, additional_amount = earning.amount, earning.additional_amount
+ if earning.additional_amount:
+ amount, additional_amount = earning.amount, earning.additional_amount
+ else:
+ amount, additional_amount = earning.default_amount, earning.additional_amount
if earning.is_tax_applicable:
if additional_amount:
@@ -1035,7 +1066,7 @@ class SalarySlip(TransactionBase):
total += amount
return total
- def set_component_amounts_based_on_payment_days(self):
+ def get_joining_and_relieving_dates(self):
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
["date_of_joining", "relieving_date"])
@@ -1045,9 +1076,7 @@ class SalarySlip(TransactionBase):
if not joining_date:
frappe.throw(_("Please set the Date Of Joining for employee {0}").format(frappe.bold(self.employee_name)))
- for component_type in ("earnings", "deductions"):
- for d in self.get(component_type):
- d.amount = flt(self.get_amount_based_on_payment_days(d, joining_date, relieving_date)[0], d.precision("amount"))
+ return joining_date, relieving_date
def set_loan_repayment(self):
self.total_loan_repayment = 0
@@ -1218,7 +1247,7 @@ class SalarySlip(TransactionBase):
period_start_date, period_end_date = self.get_year_to_date_period()
salary_slip_sum = frappe.get_list('Salary Slip',
- fields = ['sum(net_pay) as sum'],
+ fields = ['sum(net_pay) as net_sum', 'sum(gross_pay) as gross_sum'],
filters = {'employee_name' : self.employee_name,
'start_date' : ['>=', period_start_date],
'end_date' : ['<', period_end_date],
@@ -1226,10 +1255,13 @@ class SalarySlip(TransactionBase):
'docstatus': 1
})
- year_to_date = flt(salary_slip_sum[0].sum) if salary_slip_sum else 0.0
+ year_to_date = flt(salary_slip_sum[0].net_sum) if salary_slip_sum else 0.0
+ gross_year_to_date = flt(salary_slip_sum[0].gross_sum) if salary_slip_sum else 0.0
year_to_date += self.net_pay
+ gross_year_to_date += self.gross_pay
self.year_to_date = year_to_date
+ self.gross_year_to_date = gross_year_to_date
def compute_month_to_date(self):
month_to_date = 0
diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py
index 6e8d3b3f306..81582cecae3 100644
--- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py
@@ -2,20 +2,35 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import unittest
-import frappe
-import erpnext
import calendar
import random
+import unittest
+
+import frappe
+from frappe.utils import (
+ add_days,
+ add_months,
+ cstr,
+ flt,
+ get_first_day,
+ get_last_day,
+ getdate,
+ nowdate,
+)
+from frappe.utils.make_random import get_random
+
+import erpnext
from erpnext.accounts.utils import get_fiscal_year
-from frappe.utils import getdate, nowdate, add_days, add_months, flt, get_first_day, get_last_day, cstr
-from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
-from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_month_details
from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.hr.doctype.leave_allocation.test_leave_allocation import create_leave_allocation
from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
-from erpnext.payroll.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration \
- import create_payroll_period, create_exemption_category
+from erpnext.payroll.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration import (
+ create_exemption_category,
+ create_payroll_period,
+)
+from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_month_details
+from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
+
class TestSalarySlip(unittest.TestCase):
def setUp(self):
@@ -120,6 +135,65 @@ class TestSalarySlip(unittest.TestCase):
frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave")
+ def test_component_amount_dependent_on_another_payment_days_based_component(self):
+ from erpnext.hr.doctype.attendance.attendance import mark_attendance
+ from erpnext.payroll.doctype.salary_structure.test_salary_structure import (
+ create_salary_structure_assignment,
+ )
+
+ no_of_days = self.get_no_of_days()
+ # Payroll based on attendance
+ frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Attendance")
+
+ salary_structure = make_salary_structure_for_payment_days_based_component_dependency()
+ employee = make_employee("test_payment_days_based_component@salary.com", company="_Test Company")
+
+ # base = 50000
+ create_salary_structure_assignment(employee, salary_structure.name, company="_Test Company", currency="INR")
+
+ # mark employee absent for a day since this case works fine if payment days are equal to working days
+ month_start_date = get_first_day(nowdate())
+ month_end_date = get_last_day(nowdate())
+
+ first_sunday = frappe.db.sql("""
+ select holiday_date from `tabHoliday`
+ where parent = 'Salary Slip Test Holiday List'
+ and holiday_date between %s and %s
+ order by holiday_date
+ """, (month_start_date, month_end_date))[0][0]
+
+ mark_attendance(employee, add_days(first_sunday, 1), 'Absent', ignore_validate=True) # counted as absent
+
+ # make salary slip and assert payment days
+ ss = make_salary_slip_for_payment_days_dependency_test("test_payment_days_based_component@salary.com", salary_structure.name)
+ self.assertEqual(ss.absent_days, 1)
+
+ days_in_month = no_of_days[0]
+ no_of_holidays = no_of_days[1]
+
+ self.assertEqual(ss.payment_days, days_in_month - no_of_holidays - 1)
+
+ ss.reload()
+ payment_days_based_comp_amount = 0
+ for component in ss.earnings:
+ if component.salary_component == "HRA - Payment Days":
+ payment_days_based_comp_amount = flt(component.amount, component.precision("amount"))
+ break
+
+ # check if the dependent component is calculated using the amount updated after payment days
+ actual_amount = 0
+ precision = 0
+ for component in ss.deductions:
+ if component.salary_component == "P - Employee Provident Fund":
+ precision = component.precision("amount")
+ actual_amount = flt(component.amount, precision)
+ break
+
+ expected_amount = flt((flt(ss.gross_pay) - payment_days_based_comp_amount) * 0.12, precision)
+
+ self.assertEqual(actual_amount, expected_amount)
+ frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave")
+
def test_salary_slip_with_holidays_included(self):
no_of_days = self.get_no_of_days()
frappe.db.set_value("Payroll Settings", None, "include_holidays_in_total_working_days", 1)
@@ -154,7 +228,9 @@ class TestSalarySlip(unittest.TestCase):
self.assertEqual(ss.gross_pay, 78000)
def test_payment_days(self):
- from erpnext.payroll.doctype.salary_structure.test_salary_structure import create_salary_structure_assignment
+ from erpnext.payroll.doctype.salary_structure.test_salary_structure import (
+ create_salary_structure_assignment,
+ )
no_of_days = self.get_no_of_days()
# Holidays not included in working days
@@ -231,8 +307,15 @@ class TestSalarySlip(unittest.TestCase):
self.assertTrue(email_queue)
def test_loan_repayment_salary_slip(self):
- from erpnext.loan_management.doctype.loan.test_loan import create_loan_type, create_loan, make_loan_disbursement_entry, create_loan_accounts
- from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans
+ from erpnext.loan_management.doctype.loan.test_loan import (
+ create_loan,
+ create_loan_accounts,
+ create_loan_type,
+ make_loan_disbursement_entry,
+ )
+ from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (
+ process_loan_interest_accrual_for_term_loans,
+ )
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
applicant = make_employee("test_loan_repayment_salary_slip@salary.com", company="_Test Company")
@@ -386,8 +469,7 @@ class TestSalarySlip(unittest.TestCase):
for doc in delete_docs:
frappe.db.sql("delete from `tab%s` where employee='%s'" % (doc, employee))
- from erpnext.payroll.doctype.salary_structure.test_salary_structure import \
- make_salary_structure, create_salary_structure_assignment
+ from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
salary_structure = make_salary_structure("Stucture to test tax", "Monthly",
other_details={"max_benefits": 100000}, test_tax=True,
@@ -829,6 +911,7 @@ def setup_test():
def make_holiday_list():
fiscal_year = get_fiscal_year(nowdate(), company=erpnext.get_default_company())
+ holiday_list = frappe.db.exists("Holiday List", "Salary Slip Test Holiday List")
if not frappe.db.get_value("Holiday List", "Salary Slip Test Holiday List"):
holiday_list = frappe.get_doc({
"doctype": "Holiday List",
@@ -839,3 +922,94 @@ def make_holiday_list():
}).insert()
holiday_list.get_weekly_off_dates()
holiday_list.save()
+ holiday_list = holiday_list.name
+
+ return holiday_list
+
+def make_salary_structure_for_payment_days_based_component_dependency():
+ earnings = [
+ {
+ "salary_component": "Basic Salary - Payment Days",
+ "abbr": "P_BS",
+ "type": "Earning",
+ "formula": "base",
+ "amount_based_on_formula": 1
+ },
+ {
+ "salary_component": "HRA - Payment Days",
+ "abbr": "P_HRA",
+ "type": "Earning",
+ "depends_on_payment_days": 1,
+ "amount_based_on_formula": 1,
+ "formula": "base * 0.20"
+ }
+ ]
+
+ make_salary_component(earnings, False, company_list=["_Test Company"])
+
+ deductions = [
+ {
+ "salary_component": "P - Professional Tax",
+ "abbr": "P_PT",
+ "type": "Deduction",
+ "depends_on_payment_days": 1,
+ "amount": 200.00
+ },
+ {
+ "salary_component": "P - Employee Provident Fund",
+ "abbr": "P_EPF",
+ "type": "Deduction",
+ "exempted_from_income_tax": 1,
+ "amount_based_on_formula": 1,
+ "depends_on_payment_days": 0,
+ "formula": "(gross_pay - P_HRA) * 0.12"
+ }
+ ]
+
+ make_salary_component(deductions, False, company_list=["_Test Company"])
+
+ salary_structure = "Salary Structure with PF"
+ if frappe.db.exists("Salary Structure", salary_structure):
+ frappe.db.delete("Salary Structure", salary_structure)
+
+ details = {
+ "doctype": "Salary Structure",
+ "name": salary_structure,
+ "company": "_Test Company",
+ "payroll_frequency": "Monthly",
+ "payment_account": get_random("Account", filters={"account_currency": "INR"}),
+ "currency": "INR"
+ }
+
+ salary_structure_doc = frappe.get_doc(details)
+
+ for entry in earnings:
+ salary_structure_doc.append("earnings", entry)
+
+ for entry in deductions:
+ salary_structure_doc.append("deductions", entry)
+
+ salary_structure_doc.insert()
+ salary_structure_doc.submit()
+
+ return salary_structure_doc
+
+def make_salary_slip_for_payment_days_dependency_test(employee, salary_structure):
+ employee = frappe.db.get_value("Employee", {
+ "user_id": employee
+ },
+ ["name", "company", "employee_name"],
+ as_dict=True)
+
+ salary_slip_name = frappe.db.get_value("Salary Slip", {"employee": frappe.db.get_value("Employee", {"user_id": employee})})
+
+ if not salary_slip_name:
+ salary_slip = make_salary_slip(salary_structure, employee=employee.name)
+ salary_slip.employee_name = employee.employee_name
+ salary_slip.payroll_frequency = "Monthly"
+ salary_slip.posting_date = nowdate()
+ salary_slip.insert()
+ else:
+ salary_slip = frappe.get_doc("Salary Slip", salary_slip_name)
+
+ return salary_slip
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py b/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py
index 7a92bf18f76..fc8282b82ba 100644
--- a/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py
+++ b/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class SalarySlipLeave(Document):
pass
diff --git a/erpnext/payroll/doctype/salary_slip_timesheet/salary_slip_timesheet.py b/erpnext/payroll/doctype/salary_slip_timesheet/salary_slip_timesheet.py
index 7adb12e83a4..79c4c6e5715 100644
--- a/erpnext/payroll/doctype/salary_slip_timesheet/salary_slip_timesheet.py
+++ b/erpnext/payroll/doctype/salary_slip_timesheet/salary_slip_timesheet.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class SalarySlipTimesheet(Document):
pass
diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.py b/erpnext/payroll/doctype/salary_structure/salary_structure.py
index 6dfb3a57d5d..ef401b2d1a7 100644
--- a/erpnext/payroll/doctype/salary_structure/salary_structure.py
+++ b/erpnext/payroll/doctype/salary_structure/salary_structure.py
@@ -2,13 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-from frappe.utils import flt, cint, cstr
+import frappe
from frappe import _
-from frappe.model.mapper import get_mapped_doc
from frappe.model.document import Document
-from six import iteritems
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import cint, cstr, flt
+
+import erpnext
+
class SalaryStructure(Document):
def validate(self):
diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure_dashboard.py b/erpnext/payroll/doctype/salary_structure/salary_structure_dashboard.py
index 0159e3530fb..11d9a944096 100644
--- a/erpnext/payroll/doctype/salary_structure/salary_structure_dashboard.py
+++ b/erpnext/payroll/doctype/salary_structure/salary_structure_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py
index 3957d834d33..ff4a55e29cf 100644
--- a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py
+++ b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py
@@ -2,17 +2,24 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-import erpnext
-from frappe.utils.make_random import get_random
-from frappe.utils import nowdate, add_years, get_first_day, date_diff
-from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
-from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_earning_salary_component,\
- make_deduction_salary_component, make_employee_salary_slip, create_tax_slab
-from erpnext.hr.doctype.employee.test_employee import make_employee
-from erpnext.payroll.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration import create_payroll_period
+import frappe
+from frappe.utils import add_years, date_diff, get_first_day, nowdate
+from frappe.utils.make_random import get_random
+
+import erpnext
+from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.payroll.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration import (
+ create_payroll_period,
+)
+from erpnext.payroll.doctype.salary_slip.test_salary_slip import (
+ create_tax_slab,
+ make_deduction_salary_component,
+ make_earning_salary_component,
+ make_employee_salary_slip,
+)
+from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
test_dependencies = ["Fiscal Year"]
diff --git a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py
index 5fb3ce2a98e..385cf36b7f5 100644
--- a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py
+++ b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import getdate
from frappe.model.document import Document
+from frappe.utils import getdate
+
class DuplicateAssignment(frappe.ValidationError): pass
diff --git a/erpnext/payroll/doctype/salary_structure_assignment/test_salary_structure_assignment.js b/erpnext/payroll/doctype/salary_structure_assignment/test_salary_structure_assignment.js
deleted file mode 100644
index 2f52576c7a7..00000000000
--- a/erpnext/payroll/doctype/salary_structure_assignment/test_salary_structure_assignment.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Salary Structure Assignment", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Salary Structure Assignment
- () => frappe.tests.make('Salary Structure Assignment', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/payroll/doctype/salary_structure_assignment/test_salary_structure_assignment.py b/erpnext/payroll/doctype/salary_structure_assignment/test_salary_structure_assignment.py
index a9833bf7338..fbb894c43ed 100644
--- a/erpnext/payroll/doctype/salary_structure_assignment/test_salary_structure_assignment.py
+++ b/erpnext/payroll/doctype/salary_structure_assignment/test_salary_structure_assignment.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestSalaryStructureAssignment(unittest.TestCase):
pass
diff --git a/erpnext/payroll/doctype/taxable_salary_slab/taxable_salary_slab.py b/erpnext/payroll/doctype/taxable_salary_slab/taxable_salary_slab.py
index 49c52557dbc..c0827c445db 100644
--- a/erpnext/payroll/doctype/taxable_salary_slab/taxable_salary_slab.py
+++ b/erpnext/payroll/doctype/taxable_salary_slab/taxable_salary_slab.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class TaxableSalarySlab(Document):
pass
diff --git a/erpnext/payroll/notification/retention_bonus/retention_bonus.py b/erpnext/payroll/notification/retention_bonus/retention_bonus.py
index 2334f8b26d8..f57de916dd1 100644
--- a/erpnext/payroll/notification/retention_bonus/retention_bonus.py
+++ b/erpnext/payroll/notification/retention_bonus/retention_bonus.py
@@ -1,6 +1,5 @@
from __future__ import unicode_literals
-import frappe
def get_context(context):
# do your magic here
diff --git a/erpnext/payroll/report/bank_remittance/bank_remittance.py b/erpnext/payroll/report/bank_remittance/bank_remittance.py
index 05a5366a5c1..d55317e71e4 100644
--- a/erpnext/payroll/report/bank_remittance/bank_remittance.py
+++ b/erpnext/payroll/report/bank_remittance/bank_remittance.py
@@ -2,11 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import formatdate
-import itertools
from frappe import _, get_all
+
def execute(filters=None):
columns = [
{
diff --git a/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.py b/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.py
index 8a79416edbf..296a7c233f3 100644
--- a/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.py
+++ b/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.py
@@ -2,9 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+
+import frappe
from frappe import _
+import erpnext
+
+
def execute(filters=None):
data = get_data(filters)
columns = get_columns(filters) if len(data) else []
diff --git a/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.py b/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.py
index a0dab63654e..57ea1b3c283 100644
--- a/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.py
+++ b/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.py
@@ -2,9 +2,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+
+import frappe
from frappe import _
-from erpnext.regional.report.provident_fund_deductions.provident_fund_deductions import get_conditions
+
+import erpnext
+from erpnext.regional.report.provident_fund_deductions.provident_fund_deductions import (
+ get_conditions,
+)
+
def execute(filters=None):
mode_of_payments = get_payment_modes()
diff --git a/erpnext/payroll/report/salary_payments_via_ecs/salary_payments_via_ecs.py b/erpnext/payroll/report/salary_payments_via_ecs/salary_payments_via_ecs.py
index d09745c37bb..bc8fd9d40b2 100644
--- a/erpnext/payroll/report/salary_payments_via_ecs/salary_payments_via_ecs.py
+++ b/erpnext/payroll/report/salary_payments_via_ecs/salary_payments_via_ecs.py
@@ -2,9 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+
+import frappe
from frappe import _
+import erpnext
+
+
def execute(filters=None):
columns = get_columns(filters)
data = get_data(filters)
diff --git a/erpnext/payroll/report/salary_register/salary_register.py b/erpnext/payroll/report/salary_register/salary_register.py
index a1b1a8c56b5..2a9dad66e25 100644
--- a/erpnext/payroll/report/salary_register/salary_register.py
+++ b/erpnext/payroll/report/salary_register/salary_register.py
@@ -2,9 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-from frappe.utils import flt
+
+import frappe
from frappe import _
+from frappe.utils import flt
+
+import erpnext
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/portal/doctype/homepage/homepage.js b/erpnext/portal/doctype/homepage/homepage.js
index c7c66e00556..59f808a3158 100644
--- a/erpnext/portal/doctype/homepage/homepage.js
+++ b/erpnext/portal/doctype/homepage/homepage.js
@@ -3,9 +3,9 @@
frappe.ui.form.on('Homepage', {
setup: function(frm) {
- frm.fields_dict["products"].grid.get_field("item_code").get_query = function(){
+ frm.fields_dict["products"].grid.get_field("item").get_query = function() {
return {
- filters: {'show_in_website': 1}
+ filters: {'published': 1}
}
}
},
@@ -21,11 +21,10 @@ frappe.ui.form.on('Homepage', {
});
frappe.ui.form.on('Homepage Featured Product', {
-
- view: function(frm, cdt, cdn){
- var child= locals[cdt][cdn]
- if(child.item_code && frm.doc.products_url){
- window.location.href = frm.doc.products_url + '/' + encodeURIComponent(child.item_code);
+ view: function(frm, cdt, cdn) {
+ var child= locals[cdt][cdn];
+ if (child.item_code && child.route) {
+ window.open('/' + child.route, '_blank');
}
}
});
diff --git a/erpnext/portal/doctype/homepage/homepage.json b/erpnext/portal/doctype/homepage/homepage.json
index ad27278dc69..73f816d4d49 100644
--- a/erpnext/portal/doctype/homepage/homepage.json
+++ b/erpnext/portal/doctype/homepage/homepage.json
@@ -1,518 +1,143 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "",
+ "actions": [],
"beta": 1,
"creation": "2016-04-22 05:27:52.109319",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
- "editable_grid": 0,
"engine": "InnoDB",
+ "field_order": [
+ "company",
+ "hero_section_based_on",
+ "column_break_2",
+ "title",
+ "section_break_4",
+ "tag_line",
+ "description",
+ "hero_image",
+ "slideshow",
+ "hero_section",
+ "products_section",
+ "products_url",
+ "products"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "company",
"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": "Company",
- "length": 0,
- "no_copy": 0,
"options": "Company",
- "permlevel": 0,
- "precision": "",
- "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,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "hero_section_based_on",
"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": "Hero Section Based On",
- "length": 0,
- "no_copy": 0,
- "options": "Default\nSlideshow\nHomepage Section",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Default\nSlideshow\nHomepage Section"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break_2",
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
"fieldname": "title",
"fieldtype": "Data",
- "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": "Title",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Title"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
"fieldname": "section_break_4",
"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": "Hero Section",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Hero Section"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.hero_section_based_on === 'Default'",
"description": "Company Tagline for website homepage",
"fieldname": "tag_line",
"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": "Tag Line",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.hero_section_based_on === 'Default'",
"description": "Company Description for website homepage",
"fieldname": "description",
"fieldtype": "Text",
- "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": "Description",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.hero_section_based_on === 'Default'",
"fieldname": "hero_image",
"fieldtype": "Attach Image",
- "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": "Hero Image",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Hero Image"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.hero_section_based_on === 'Slideshow'",
- "description": "",
"fieldname": "slideshow",
"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": "Homepage Slideshow",
- "length": 0,
- "no_copy": 0,
- "options": "Website Slideshow",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Website Slideshow"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.hero_section_based_on === 'Homepage Section'",
"fieldname": "hero_section",
"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": "Homepage Section",
- "length": 0,
- "no_copy": 0,
- "options": "Homepage Section",
- "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,
- "translatable": 0,
- "unique": 0
+ "options": "Homepage Section"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
"fieldname": "products_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": "Products",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "Products"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "/products",
+ "default": "/all-products",
"fieldname": "products_url",
"fieldtype": "Data",
- "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": "URL for \"All Products\"",
- "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,
- "translatable": 0,
- "unique": 0
+ "label": "URL for \"All Products\""
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "Products to be shown on website homepage",
"fieldname": "products",
"fieldtype": "Table",
- "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": "Products",
- "length": 0,
- "no_copy": 0,
"options": "Homepage Featured Product",
- "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,
- "translatable": 0,
- "unique": 0,
"width": "40px"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
"issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-03-02 23:12:59.676202",
+ "links": [],
+ "modified": "2021-02-18 13:29:29.531639",
"modified_by": "Administrator",
"module": "Portal",
"name": "Homepage",
- "name_case": "",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
- "report": 0,
"role": "System Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
- "report": 0,
"role": "Administrator",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
}
],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "company",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/portal/doctype/homepage/homepage.py b/erpnext/portal/doctype/homepage/homepage.py
index 54ea7c62df4..74e04894c6f 100644
--- a/erpnext/portal/doctype/homepage/homepage.py
+++ b/erpnext/portal/doctype/homepage/homepage.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
from frappe.website.utils import delete_page_cache
+
class Homepage(Document):
def validate(self):
if not self.description:
@@ -14,12 +16,14 @@ class Homepage(Document):
delete_page_cache('home')
def setup_items(self):
- for d in frappe.get_all('Item', fields=['name', 'item_name', 'description', 'image'],
- filters={'show_in_website': 1}, limit=3):
+ for d in frappe.get_all('Website Item', fields=['name', 'item_name', 'description', 'image', 'route'],
+ filters={'published': 1}, limit=3):
- doc = frappe.get_doc('Item', d.name)
+ doc = frappe.get_doc('Website Item', d.name)
if not doc.route:
# set missing route
doc.save()
self.append('products', dict(item_code=d.name,
- item_name=d.item_name, description=d.description, image=d.image))
+ item_name=d.item_name, description=d.description,
+ image=d.image, route=d.route))
+
diff --git a/erpnext/portal/doctype/homepage/test_homepage.py b/erpnext/portal/doctype/homepage/test_homepage.py
index b717491a821..6f0517867d7 100644
--- a/erpnext/portal/doctype/homepage/test_homepage.py
+++ b/erpnext/portal/doctype/homepage/test_homepage.py
@@ -3,11 +3,13 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
from frappe.utils import set_request
from frappe.website.render import render
+
class TestHomepage(unittest.TestCase):
def test_homepage_load(self):
set_request(method='GET', path='home')
diff --git a/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.json b/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.json
index 01c32efec9d..63789e35b56 100644
--- a/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.json
+++ b/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.json
@@ -25,10 +25,10 @@
"fieldtype": "Link",
"in_filter": 1,
"in_list_view": 1,
- "label": "Item Code",
+ "label": "Item",
"oldfieldname": "item_code",
"oldfieldtype": "Link",
- "options": "Item",
+ "options": "Website Item",
"print_width": "150px",
"reqd": 1,
"search_index": 1,
@@ -63,7 +63,7 @@
"collapsible": 1,
"fieldname": "section_break_5",
"fieldtype": "Section Break",
- "label": "Description"
+ "label": "Details"
},
{
"fetch_from": "item_code.web_long_description",
@@ -89,12 +89,14 @@
"label": "Image"
},
{
+ "fetch_from": "item_code.thumbnail",
"fieldname": "thumbnail",
"fieldtype": "Attach Image",
"hidden": 1,
"label": "Thumbnail"
},
{
+ "fetch_from": "item_code.route",
"fieldname": "route",
"fieldtype": "Small Text",
"label": "route",
@@ -104,7 +106,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-08-25 15:27:49.573537",
+ "modified": "2021-02-18 13:05:50.669311",
"modified_by": "Administrator",
"module": "Portal",
"name": "Homepage Featured Product",
diff --git a/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.py b/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.py
index 936e07d34ea..8e8f77605e6 100644
--- a/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.py
+++ b/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class HomepageFeaturedProduct(Document):
pass
diff --git a/erpnext/portal/doctype/homepage_section/homepage_section.py b/erpnext/portal/doctype/homepage_section/homepage_section.py
index 1ed703050b8..081786126e7 100644
--- a/erpnext/portal/doctype/homepage_section/homepage_section.py
+++ b/erpnext/portal/doctype/homepage_section/homepage_section.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
from frappe.utils import cint
+
class HomepageSection(Document):
@property
def column_value(self):
diff --git a/erpnext/portal/doctype/homepage_section/test_homepage_section.py b/erpnext/portal/doctype/homepage_section/test_homepage_section.py
index f0aa554858a..75aa5b28f11 100644
--- a/erpnext/portal/doctype/homepage_section/test_homepage_section.py
+++ b/erpnext/portal/doctype/homepage_section/test_homepage_section.py
@@ -3,12 +3,14 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
from bs4 import BeautifulSoup
from frappe.utils import set_request
from frappe.website.render import render
+
class TestHomepageSection(unittest.TestCase):
def test_homepage_section_card(self):
try:
diff --git a/erpnext/portal/doctype/homepage_section_card/homepage_section_card.py b/erpnext/portal/doctype/homepage_section_card/homepage_section_card.py
index bd17279f99a..b71045207cc 100644
--- a/erpnext/portal/doctype/homepage_section_card/homepage_section_card.py
+++ b/erpnext/portal/doctype/homepage_section_card/homepage_section_card.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class HomepageSectionCard(Document):
pass
diff --git a/erpnext/portal/doctype/products_settings/products_settings.js b/erpnext/portal/doctype/products_settings/products_settings.js
deleted file mode 100644
index 2f8b0371648..00000000000
--- a/erpnext/portal/doctype/products_settings/products_settings.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Products Settings', {
- refresh: function(frm) {
- frappe.model.with_doctype('Item', () => {
- const item_meta = frappe.get_meta('Item');
-
- const valid_fields = item_meta.fields.filter(
- df => ['Link', 'Table MultiSelect'].includes(df.fieldtype) && !df.hidden
- ).map(df => ({ label: df.label, value: df.fieldname }));
-
- frm.fields_dict.filter_fields.grid.update_docfield_property(
- 'fieldname', 'fieldtype', 'Select'
- );
- frm.fields_dict.filter_fields.grid.update_docfield_property(
- 'fieldname', 'options', valid_fields
- );
- });
- }
-});
diff --git a/erpnext/portal/doctype/products_settings/products_settings.json b/erpnext/portal/doctype/products_settings/products_settings.json
deleted file mode 100644
index 2cf8431497c..00000000000
--- a/erpnext/portal/doctype/products_settings/products_settings.json
+++ /dev/null
@@ -1,389 +0,0 @@
-{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2016-04-22 09:11:55.272398",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 0,
- "engine": "InnoDB",
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "If checked, the Home page will be the default Item Group for the website",
- "fieldname": "home_page_is_products",
- "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": "Home Page is Products",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "show_availability_status",
- "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": "Show Availability Status",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_5",
- "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": "Product Page",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "6",
- "fieldname": "products_per_page",
- "fieldtype": "Int",
- "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": "Products per Page",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "enable_field_filters",
- "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": "Enable Field Filters",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "enable_field_filters",
- "fieldname": "filter_fields",
- "fieldtype": "Table",
- "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": "Item Fields",
- "length": 0,
- "no_copy": 0,
- "options": "Website Filter Field",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "enable_attribute_filters",
- "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": "Enable Attribute Filters",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "enable_attribute_filters",
- "fieldname": "filter_attributes",
- "fieldtype": "Table",
- "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": "Attributes",
- "length": 0,
- "no_copy": 0,
- "options": "Website Attribute",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "hide_variants",
- "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": "Hide Variants",
- "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,
- "translatable": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-03-07 19:18:31.822309",
- "modified_by": "Administrator",
- "module": "Portal",
- "name": "Products Settings",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "Website Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
-}
\ No newline at end of file
diff --git a/erpnext/portal/doctype/products_settings/products_settings.py b/erpnext/portal/doctype/products_settings/products_settings.py
deleted file mode 100644
index 9a708924ae0..00000000000
--- a/erpnext/portal/doctype/products_settings/products_settings.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.utils import cint
-from frappe import _
-from frappe.model.document import Document
-
-class ProductsSettings(Document):
- def validate(self):
- if self.home_page_is_products:
- frappe.db.set_value("Website Settings", None, "home_page", "products")
- elif frappe.db.get_single_value("Website Settings", "home_page") == 'products':
- frappe.db.set_value("Website Settings", None, "home_page", "home")
-
- self.validate_field_filters()
- self.validate_attribute_filters()
- frappe.clear_document_cache("Product Settings", "Product Settings")
-
- def validate_field_filters(self):
- if not (self.enable_field_filters and self.filter_fields): return
-
- item_meta = frappe.get_meta('Item')
- valid_fields = [df.fieldname for df in item_meta.fields if df.fieldtype in ['Link', 'Table MultiSelect']]
-
- for f in self.filter_fields:
- if f.fieldname not in valid_fields:
- frappe.throw(_('Filter Fields Row #{0}: Fieldname
{1} must be of type "Link" or "Table MultiSelect"').format(f.idx, f.fieldname))
-
- def validate_attribute_filters(self):
- if not (self.enable_attribute_filters and self.filter_attributes): return
-
- # if attribute filters are enabled, hide_variants should be disabled
- self.hide_variants = 0
-
-
-def home_page_is_products(doc, method):
- '''Called on saving Website Settings'''
- home_page_is_products = cint(frappe.db.get_single_value('Products Settings', 'home_page_is_products'))
- if home_page_is_products:
- doc.home_page = 'products'
diff --git a/erpnext/portal/doctype/products_settings/test_products_settings.js b/erpnext/portal/doctype/products_settings/test_products_settings.js
deleted file mode 100644
index b7049b37e18..00000000000
--- a/erpnext/portal/doctype/products_settings/test_products_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Products Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Products Settings
- () => frappe.tests.make('Products Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/portal/doctype/products_settings/test_products_settings.py b/erpnext/portal/doctype/products_settings/test_products_settings.py
deleted file mode 100644
index d04a0098829..00000000000
--- a/erpnext/portal/doctype/products_settings/test_products_settings.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import frappe
-import unittest
-
-class TestProductsSettings(unittest.TestCase):
- pass
diff --git a/erpnext/portal/doctype/website_attribute/website_attribute.json b/erpnext/portal/doctype/website_attribute/website_attribute.json
index 2874dc432c7..eed33ec10e4 100644
--- a/erpnext/portal/doctype/website_attribute/website_attribute.json
+++ b/erpnext/portal/doctype/website_attribute/website_attribute.json
@@ -1,76 +1,32 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2019-01-01 13:04:54.479079",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2019-01-01 13:04:54.479079",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "attribute"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "attribute",
- "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": "Attribute",
- "length": 0,
- "no_copy": 0,
- "options": "Item Attribute",
- "permlevel": 0,
- "precision": "",
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldname": "attribute",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Attribute",
+ "options": "Item Attribute",
+ "reqd": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2019-01-01 13:04:59.715572",
- "modified_by": "Administrator",
- "module": "Portal",
- "name": "Website Attribute",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2021-02-18 13:18:57.810536",
+ "modified_by": "Administrator",
+ "module": "Portal",
+ "name": "Website Attribute",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/portal/doctype/website_attribute/website_attribute.py b/erpnext/portal/doctype/website_attribute/website_attribute.py
index b8b667a6135..f9ba733b85d 100644
--- a/erpnext/portal/doctype/website_attribute/website_attribute.py
+++ b/erpnext/portal/doctype/website_attribute/website_attribute.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class WebsiteAttribute(Document):
pass
diff --git a/erpnext/portal/doctype/website_filter_field/website_filter_field.py b/erpnext/portal/doctype/website_filter_field/website_filter_field.py
index 2aa8a6f98d4..335d4575b61 100644
--- a/erpnext/portal/doctype/website_filter_field/website_filter_field.py
+++ b/erpnext/portal/doctype/website_filter_field/website_filter_field.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class WebsiteFilterField(Document):
pass
diff --git a/erpnext/portal/product_configurator/test_product_configurator.py b/erpnext/portal/product_configurator/test_product_configurator.py
deleted file mode 100644
index 28e064218b1..00000000000
--- a/erpnext/portal/product_configurator/test_product_configurator.py
+++ /dev/null
@@ -1,144 +0,0 @@
-from __future__ import unicode_literals
-
-from bs4 import BeautifulSoup
-import frappe, unittest
-from frappe.utils import set_request, get_html_for_route
-from frappe.website.render import render
-from erpnext.portal.product_configurator.utils import get_products_for_website
-from erpnext.stock.doctype.item.test_item import make_item_variant
-
-test_dependencies = ["Item"]
-
-class TestProductConfigurator(unittest.TestCase):
- @classmethod
- def setUpClass(cls):
- cls.create_variant_item()
-
- @classmethod
- def create_variant_item(cls):
- if not frappe.db.exists('Item', '_Test Variant Item - 2XL'):
- frappe.get_doc({
- "description": "_Test Variant Item - 2XL",
- "item_code": "_Test Variant Item - 2XL",
- "item_name": "_Test Variant Item - 2XL",
- "doctype": "Item",
- "is_stock_item": 1,
- "variant_of": "_Test Variant Item",
- "item_group": "_Test Item Group",
- "stock_uom": "_Test UOM",
- "item_defaults": [{
- "company": "_Test Company",
- "default_warehouse": "_Test Warehouse - _TC",
- "expense_account": "_Test Account Cost for Goods Sold - _TC",
- "buying_cost_center": "_Test Cost Center - _TC",
- "selling_cost_center": "_Test Cost Center - _TC",
- "income_account": "Sales - _TC"
- }],
- "attributes": [
- {
- "attribute": "Test Size",
- "attribute_value": "2XL"
- }
- ],
- "show_variant_in_website": 1
- }).insert()
-
- def create_regular_web_item(self, name, item_group=None):
- if not frappe.db.exists('Item', name):
- doc = frappe.get_doc({
- "description": name,
- "item_code": name,
- "item_name": name,
- "doctype": "Item",
- "is_stock_item": 1,
- "item_group": item_group or "_Test Item Group",
- "stock_uom": "_Test UOM",
- "item_defaults": [{
- "company": "_Test Company",
- "default_warehouse": "_Test Warehouse - _TC",
- "expense_account": "_Test Account Cost for Goods Sold - _TC",
- "buying_cost_center": "_Test Cost Center - _TC",
- "selling_cost_center": "_Test Cost Center - _TC",
- "income_account": "Sales - _TC"
- }],
- "show_in_website": 1
- }).insert()
- else:
- doc = frappe.get_doc("Item", name)
- return doc
-
- def test_product_list(self):
- template_items = frappe.get_all('Item', {'show_in_website': 1})
- variant_items = frappe.get_all('Item', {'show_variant_in_website': 1})
-
- products_settings = frappe.get_doc('Products Settings')
- products_settings.enable_field_filters = 1
- products_settings.append('filter_fields', {'fieldname': 'item_group'})
- products_settings.append('filter_fields', {'fieldname': 'stock_uom'})
- products_settings.save()
-
- html = get_html_for_route('all-products')
-
- soup = BeautifulSoup(html, 'html.parser')
- products_list = soup.find(class_='products-list')
- items = products_list.find_all(class_='card')
- self.assertEqual(len(items), len(template_items + variant_items))
-
- items_with_item_group = frappe.get_all('Item', {'item_group': '_Test Item Group Desktops', 'show_in_website': 1})
- variants_with_item_group = frappe.get_all('Item', {'item_group': '_Test Item Group Desktops', 'show_variant_in_website': 1})
-
- # mock query params
- frappe.form_dict = frappe._dict({
- 'field_filters': '{"item_group":["_Test Item Group Desktops"]}'
- })
- html = get_html_for_route('all-products')
- soup = BeautifulSoup(html, 'html.parser')
- products_list = soup.find(class_='products-list')
- items = products_list.find_all(class_='card')
- self.assertEqual(len(items), len(items_with_item_group + variants_with_item_group))
-
-
- def test_get_products_for_website(self):
- items = get_products_for_website(attribute_filters={
- 'Test Size': ['2XL']
- })
- self.assertEqual(len(items), 1)
-
- def test_products_in_multiple_item_groups(self):
- """Check if product is visible on multiple item group pages barring its own."""
- from erpnext.shopping_cart.product_query import ProductQuery
-
- if not frappe.db.exists("Item Group", {"name": "Tech Items"}):
- item_group_doc = frappe.get_doc({
- "doctype": "Item Group",
- "item_group_name": "Tech Items",
- "parent_item_group": "All Item Groups",
- "show_in_website": 1
- }).insert()
- else:
- item_group_doc = frappe.get_doc("Item Group", "Tech Items")
-
- doc = self.create_regular_web_item("Portal Item", item_group="Tech Items")
- if not frappe.db.exists("Website Item Group", {"parent": "Portal Item"}):
- doc.append("website_item_groups", {
- "item_group": "_Test Item Group Desktops"
- })
- doc.save()
-
- # check if item is visible in its own Item Group's page
- engine = ProductQuery()
- items = engine.query({}, {"item_group": "Tech Items"}, None, start=0, item_group="Tech Items")
- self.assertEqual(len(items), 1)
- self.assertEqual(items[0].item_code, "Portal Item")
-
- # check if item is visible in configured foreign Item Group's page
- engine = ProductQuery()
- items = engine.query({}, {"item_group": "_Test Item Group Desktops"}, None, start=0, item_group="_Test Item Group Desktops")
- item_codes = [row.item_code for row in items]
-
- self.assertIn(len(items), [2, 3])
- self.assertIn("Portal Item", item_codes)
-
- # teardown
- doc.delete()
- item_group_doc.delete()
diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py
deleted file mode 100644
index d60b1a2b05e..00000000000
--- a/erpnext/portal/product_configurator/utils.py
+++ /dev/null
@@ -1,444 +0,0 @@
-import frappe
-from frappe.utils import cint
-from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager
-from erpnext.shopping_cart.product_info import get_product_info_for_website
-from erpnext.setup.doctype.item_group.item_group import get_child_groups
-
-def get_field_filter_data():
- product_settings = get_product_settings()
- filter_fields = [row.fieldname for row in product_settings.filter_fields]
-
- meta = frappe.get_meta('Item')
- fields = [df for df in meta.fields if df.fieldname in filter_fields]
-
- filter_data = []
- for f in fields:
- doctype = f.get_link_doctype()
-
- # apply enable/disable/show_in_website filter
- meta = frappe.get_meta(doctype)
- filters = {}
- if meta.has_field('enabled'):
- filters['enabled'] = 1
- if meta.has_field('disabled'):
- filters['disabled'] = 0
- if meta.has_field('show_in_website'):
- filters['show_in_website'] = 1
-
- values = [d.name for d in frappe.get_all(doctype, filters)]
- filter_data.append([f, values])
-
- return filter_data
-
-
-def get_attribute_filter_data():
- product_settings = get_product_settings()
- attributes = [row.attribute for row in product_settings.filter_attributes]
- attribute_docs = [
- frappe.get_doc('Item Attribute', attribute) for attribute in attributes
- ]
-
- # mark attribute values as checked if they are present in the request url
- if frappe.form_dict:
- for attr in attribute_docs:
- if attr.name in frappe.form_dict:
- value = frappe.form_dict[attr.name]
- if value:
- enabled_values = value.split(',')
- else:
- enabled_values = []
-
- for v in enabled_values:
- for item_attribute_row in attr.item_attribute_values:
- if v == item_attribute_row.attribute_value:
- item_attribute_row.checked = True
-
- return attribute_docs
-
-
-def get_products_for_website(field_filters=None, attribute_filters=None, search=None):
- if attribute_filters:
- item_codes = get_item_codes_by_attributes(attribute_filters)
- items_by_attributes = get_items([['name', 'in', item_codes]])
-
- if field_filters:
- items_by_fields = get_items_by_fields(field_filters)
-
- if attribute_filters and not field_filters:
- return items_by_attributes
-
- if field_filters and not attribute_filters:
- return items_by_fields
-
- if field_filters and attribute_filters:
- items_intersection = []
- item_codes_in_attribute = [item.name for item in items_by_attributes]
-
- for item in items_by_fields:
- if item.name in item_codes_in_attribute:
- items_intersection.append(item)
-
- return items_intersection
-
- if search:
- return get_items(search=search)
-
- return get_items()
-
-
-@frappe.whitelist(allow_guest=True)
-def get_products_html_for_website(field_filters=None, attribute_filters=None):
- field_filters = frappe.parse_json(field_filters)
- attribute_filters = frappe.parse_json(attribute_filters)
- set_item_group_filters(field_filters)
-
- items = get_products_for_website(field_filters, attribute_filters)
- html = ''.join(get_html_for_items(items))
-
- if not items:
- html = frappe.render_template('erpnext/www/all-products/not_found.html', {})
-
- return html
-
-def set_item_group_filters(field_filters):
- if field_filters is not None and 'item_group' in field_filters:
- field_filters['item_group'] = [ig[0] for ig in get_child_groups(field_filters['item_group'])]
-
-
-def get_item_codes_by_attributes(attribute_filters, template_item_code=None):
- items = []
-
- for attribute, values in attribute_filters.items():
- attribute_values = values
-
- if not isinstance(attribute_values, list):
- attribute_values = [attribute_values]
-
- if not attribute_values: continue
-
- wheres = []
- query_values = []
- for attribute_value in attribute_values:
- wheres.append('( attribute = %s and attribute_value = %s )')
- query_values += [attribute, attribute_value]
-
- attribute_query = ' or '.join(wheres)
-
- if template_item_code:
- variant_of_query = 'AND t2.variant_of = %s'
- query_values.append(template_item_code)
- else:
- variant_of_query = ''
-
- query = '''
- SELECT
- t1.parent
- FROM
- `tabItem Variant Attribute` t1
- WHERE
- 1 = 1
- AND (
- {attribute_query}
- )
- AND EXISTS (
- SELECT
- 1
- FROM
- `tabItem` t2
- WHERE
- t2.name = t1.parent
- {variant_of_query}
- )
- GROUP BY
- t1.parent
- ORDER BY
- NULL
- '''.format(attribute_query=attribute_query, variant_of_query=variant_of_query)
-
- item_codes = set([r[0] for r in frappe.db.sql(query, query_values)])
- items.append(item_codes)
-
- res = list(set.intersection(*items))
-
- return res
-
-
-@frappe.whitelist(allow_guest=True)
-def get_attributes_and_values(item_code):
- '''Build a list of attributes and their possible values.
- This will ignore the values upon selection of which there cannot exist one item.
- '''
- item_cache = ItemVariantsCacheManager(item_code)
- item_variants_data = item_cache.get_item_variants_data()
-
- attributes = get_item_attributes(item_code)
- attribute_list = [a.attribute for a in attributes]
-
- valid_options = {}
- for item_code, attribute, attribute_value in item_variants_data:
- if attribute in attribute_list:
- valid_options.setdefault(attribute, set()).add(attribute_value)
-
- item_attribute_values = frappe.db.get_all('Item Attribute Value',
- ['parent', 'attribute_value', 'idx'], order_by='parent asc, idx asc')
- ordered_attribute_value_map = frappe._dict()
- for iv in item_attribute_values:
- ordered_attribute_value_map.setdefault(iv.parent, []).append(iv.attribute_value)
-
- # build attribute values in idx order
- for attr in attributes:
- valid_attribute_values = valid_options.get(attr.attribute, [])
- ordered_values = ordered_attribute_value_map.get(attr.attribute, [])
- attr['values'] = [v for v in ordered_values if v in valid_attribute_values]
-
- return attributes
-
-
-@frappe.whitelist(allow_guest=True)
-def get_next_attribute_and_values(item_code, selected_attributes):
- '''Find the count of Items that match the selected attributes.
- Also, find the attribute values that are not applicable for further searching.
- If less than equal to 10 items are found, return item_codes of those items.
- If one item is matched exactly, return item_code of that item.
- '''
- selected_attributes = frappe.parse_json(selected_attributes)
-
- item_cache = ItemVariantsCacheManager(item_code)
- item_variants_data = item_cache.get_item_variants_data()
-
- attributes = get_item_attributes(item_code)
- attribute_list = [a.attribute for a in attributes]
- filtered_items = get_items_with_selected_attributes(item_code, selected_attributes)
-
- next_attribute = None
-
- for attribute in attribute_list:
- if attribute not in selected_attributes:
- next_attribute = attribute
- break
-
- valid_options_for_attributes = frappe._dict({})
-
- for a in attribute_list:
- valid_options_for_attributes[a] = set()
-
- selected_attribute = selected_attributes.get(a, None)
- if selected_attribute:
- # already selected attribute values are valid options
- valid_options_for_attributes[a].add(selected_attribute)
-
- for row in item_variants_data:
- item_code, attribute, attribute_value = row
- if item_code in filtered_items and attribute not in selected_attributes and attribute in attribute_list:
- valid_options_for_attributes[attribute].add(attribute_value)
-
- optional_attributes = item_cache.get_optional_attributes()
- exact_match = []
- # search for exact match if all selected attributes are required attributes
- if len(selected_attributes.keys()) >= (len(attribute_list) - len(optional_attributes)):
- item_attribute_value_map = item_cache.get_item_attribute_value_map()
- for item_code, attr_dict in item_attribute_value_map.items():
- if item_code in filtered_items and set(attr_dict.keys()) == set(selected_attributes.keys()):
- exact_match.append(item_code)
-
- filtered_items_count = len(filtered_items)
-
- # get product info if exact match
- from erpnext.shopping_cart.product_info import get_product_info_for_website
- if exact_match:
- data = get_product_info_for_website(exact_match[0])
- product_info = data.product_info
- if product_info:
- product_info["allow_items_not_in_stock"] = cint(data.cart_settings.allow_items_not_in_stock)
- if not data.cart_settings.show_price:
- product_info = None
- else:
- product_info = None
-
- return {
- 'next_attribute': next_attribute,
- 'valid_options_for_attributes': valid_options_for_attributes,
- 'filtered_items_count': filtered_items_count,
- 'filtered_items': filtered_items if filtered_items_count < 10 else [],
- 'exact_match': exact_match,
- 'product_info': product_info
- }
-
-
-def get_items_with_selected_attributes(item_code, selected_attributes):
- item_cache = ItemVariantsCacheManager(item_code)
- attribute_value_item_map = item_cache.get_attribute_value_item_map()
-
- items = []
- for attribute, value in selected_attributes.items():
- filtered_items = attribute_value_item_map.get((attribute, value), [])
- items.append(set(filtered_items))
-
- return set.intersection(*items)
-
-
-def get_items_by_fields(field_filters):
- meta = frappe.get_meta('Item')
- filters = []
- for fieldname, values in field_filters.items():
- if not values: continue
-
- _doctype = 'Item'
- _fieldname = fieldname
-
- df = meta.get_field(fieldname)
- if df.fieldtype == 'Table MultiSelect':
- child_doctype = df.options
- child_meta = frappe.get_meta(child_doctype)
- fields = child_meta.get("fields", { "fieldtype": "Link", "in_list_view": 1 })
- if fields:
- _doctype = child_doctype
- _fieldname = fields[0].fieldname
-
- if len(values) == 1:
- filters.append([_doctype, _fieldname, '=', values[0]])
- else:
- filters.append([_doctype, _fieldname, 'in', values])
-
- return get_items(filters)
-
-
-def get_items(filters=None, search=None):
- start = frappe.form_dict.get('start', 0)
- products_settings = get_product_settings()
- page_length = products_settings.products_per_page
-
- filters = filters or []
- # convert to list of filters
- if isinstance(filters, dict):
- filters = [['Item', fieldname, '=', value] for fieldname, value in filters.items()]
-
- enabled_items_filter = get_conditions({ 'disabled': 0 }, 'and')
-
- show_in_website_condition = ''
- if products_settings.hide_variants:
- show_in_website_condition = get_conditions({'show_in_website': 1 }, 'and')
- else:
- show_in_website_condition = get_conditions([
- ['show_in_website', '=', 1],
- ['show_variant_in_website', '=', 1]
- ], 'or')
-
- search_condition = ''
- if search:
- # Default fields to search from
- default_fields = {'name', 'item_name', 'description', 'item_group'}
-
- # Get meta search fields
- meta = frappe.get_meta("Item")
- meta_fields = set(meta.get_search_fields())
-
- # Join the meta fields and default fields set
- search_fields = default_fields.union(meta_fields)
- try:
- if frappe.db.count('Item', cache=True) > 50000:
- search_fields.remove('description')
- except KeyError:
- pass
-
- # Build or filters for query
- search = '%{}%'.format(search)
- or_filters = [[field, 'like', search] for field in search_fields]
-
- search_condition = get_conditions(or_filters, 'or')
-
- filter_condition = get_conditions(filters, 'and')
-
- where_conditions = ' and '.join(
- [condition for condition in [enabled_items_filter, show_in_website_condition, \
- search_condition, filter_condition] if condition]
- )
-
- left_joins = []
- for f in filters:
- if len(f) == 4 and f[0] != 'Item':
- left_joins.append(f[0])
-
- left_join = ' '.join(['LEFT JOIN `tab{0}` on (`tab{0}`.parent = `tabItem`.name)'.format(l) for l in left_joins])
-
- results = frappe.db.sql('''
- SELECT
- `tabItem`.`name`, `tabItem`.`item_name`, `tabItem`.`item_code`,
- `tabItem`.`website_image`, `tabItem`.`image`,
- `tabItem`.`web_long_description`, `tabItem`.`description`,
- `tabItem`.`route`, `tabItem`.`item_group`
- FROM
- `tabItem`
- {left_join}
- WHERE
- {where_conditions}
- GROUP BY
- `tabItem`.`name`
- ORDER BY
- `tabItem`.`weightage` DESC
- LIMIT
- {page_length}
- OFFSET
- {start}
- '''.format(
- where_conditions=where_conditions,
- start=start,
- page_length=page_length,
- left_join=left_join
- )
- , as_dict=1)
-
- for r in results:
- r.description = r.web_long_description or r.description
- r.image = r.website_image or r.image
- product_info = get_product_info_for_website(r.item_code, skip_quotation_creation=True).get('product_info')
- if product_info:
- r.formatted_price = product_info['price'].get('formatted_price') if product_info['price'] else None
-
- return results
-
-
-def get_conditions(filter_list, and_or='and'):
- from frappe.model.db_query import DatabaseQuery
-
- if not filter_list:
- return ''
-
- conditions = []
- DatabaseQuery('Item').build_filter_conditions(filter_list, conditions, ignore_permissions=True)
- join_by = ' {0} '.format(and_or)
-
- return '(' + join_by.join(conditions) + ')'
-
-# utilities
-
-def get_item_attributes(item_code):
- attributes = frappe.db.get_all('Item Variant Attribute',
- fields=['attribute'],
- filters={
- 'parenttype': 'Item',
- 'parent': item_code
- },
- order_by='idx asc'
- )
-
- optional_attributes = ItemVariantsCacheManager(item_code).get_optional_attributes()
-
- for a in attributes:
- if a.attribute in optional_attributes:
- a.optional = True
-
- return attributes
-
-def get_html_for_items(items):
- html = []
- for item in items:
- html.append(frappe.render_template('erpnext/www/all-products/item_row.html', {
- 'item': item
- }))
- return html
-
-def get_product_settings():
- doc = frappe.get_cached_doc('Products Settings')
- doc.products_per_page = doc.products_per_page or 20
- return doc
diff --git a/erpnext/portal/utils.py b/erpnext/portal/utils.py
index d6d44694203..84c862b052a 100644
--- a/erpnext/portal/utils.py
+++ b/erpnext/portal/utils.py
@@ -1,9 +1,14 @@
from __future__ import unicode_literals
+
import frappe
-from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import get_shopping_cart_settings
-from erpnext.shopping_cart.cart import get_debtors_account
from frappe.utils.nestedset import get_root_of
+from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import (
+ get_shopping_cart_settings,
+)
+from erpnext.e_commerce.shopping_cart.cart import get_debtors_account
+
+
def set_default_role(doc, method):
'''Set customer, supplier, student, guardian based on email'''
if frappe.flags.setting_role or frappe.flags.in_migrate:
diff --git a/erpnext/projects/doctype/activity_cost/activity_cost.py b/erpnext/projects/doctype/activity_cost/activity_cost.py
index 99226ea581c..e210324862b 100644
--- a/erpnext/projects/doctype/activity_cost/activity_cost.py
+++ b/erpnext/projects/doctype/activity_cost/activity_cost.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
class DuplicationError(frappe.ValidationError): pass
class ActivityCost(Document):
diff --git a/erpnext/projects/doctype/activity_cost/test_activity_cost.py b/erpnext/projects/doctype/activity_cost/test_activity_cost.py
index 5f35f299b36..c031f3cedab 100644
--- a/erpnext/projects/doctype/activity_cost/test_activity_cost.py
+++ b/erpnext/projects/doctype/activity_cost/test_activity_cost.py
@@ -3,11 +3,13 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
from erpnext.projects.doctype.activity_cost.activity_cost import DuplicationError
+
class TestActivityCost(unittest.TestCase):
def test_duplication(self):
frappe.db.sql("delete from `tabActivity Cost`")
diff --git a/erpnext/projects/doctype/activity_type/activity_type.py b/erpnext/projects/doctype/activity_type/activity_type.py
index 50e18ef4de9..4c94fe45650 100644
--- a/erpnext/projects/doctype/activity_type/activity_type.py
+++ b/erpnext/projects/doctype/activity_type/activity_type.py
@@ -2,7 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class ActivityType(Document):
pass
diff --git a/erpnext/projects/doctype/activity_type/test_activity_type.py b/erpnext/projects/doctype/activity_type/test_activity_type.py
index dcb01018de0..02619af7abd 100644
--- a/erpnext/projects/doctype/activity_type/test_activity_type.py
+++ b/erpnext/projects/doctype/activity_type/test_activity_type.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Activity Type')
diff --git a/erpnext/projects/doctype/dependent_task/dependent_task.py b/erpnext/projects/doctype/dependent_task/dependent_task.py
index 90a96ac1b7c..3f62cef7056 100644
--- a/erpnext/projects/doctype/dependent_task/dependent_task.py
+++ b/erpnext/projects/doctype/dependent_task/dependent_task.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class DependentTask(Document):
pass
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index c8fbe0bf7be..59488e60123 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -2,18 +2,19 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import _
-from six import iteritems
from email_reply_parser import EmailReplyParser
-from frappe.utils import (flt, getdate, get_url, now,
- nowtime, get_time, today, get_datetime, add_days)
-from erpnext.controllers.queries import get_filters_cond
+from frappe import _
from frappe.desk.reportview import get_match_cond
+from frappe.model.document import Document
+from frappe.utils import add_days, flt, get_datetime, get_time, get_url, nowtime, today
+
+from erpnext.controllers.queries import get_filters_cond
+from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
from erpnext.hr.doctype.daily_work_summary.daily_work_summary import get_users_email
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
-from frappe.model.document import Document
-from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
+
class Project(Document):
def get_feed(self):
diff --git a/erpnext/projects/doctype/project/project_dashboard.py b/erpnext/projects/doctype/project/project_dashboard.py
index 39cf016d61f..64fbbf5ebab 100644
--- a/erpnext/projects/doctype/project/project_dashboard.py
+++ b/erpnext/projects/doctype/project/project_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'heatmap': True,
diff --git a/erpnext/projects/doctype/project/test_project.js b/erpnext/projects/doctype/project/test_project.js
deleted file mode 100644
index 16494f62b60..00000000000
--- a/erpnext/projects/doctype/project/test_project.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Project", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Project
- () => frappe.tests.make('Project', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/projects/doctype/project/test_project.py b/erpnext/projects/doctype/project/test_project.py
index 70139c6da84..ebc132626ca 100644
--- a/erpnext/projects/doctype/project/test_project.py
+++ b/erpnext/projects/doctype/project/test_project.py
@@ -2,9 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+import unittest
-import frappe, unittest
-from frappe.utils import getdate, nowdate, add_days
+import frappe
+from frappe.utils import add_days, getdate, nowdate
from erpnext.projects.doctype.project_template.test_project_template import make_project_template
from erpnext.projects.doctype.task.test_task import create_task
diff --git a/erpnext/projects/doctype/project_template/project_template.py b/erpnext/projects/doctype/project_template/project_template.py
index 2426fd2af89..493ce5b07cb 100644
--- a/erpnext/projects/doctype/project_template/project_template.py
+++ b/erpnext/projects/doctype/project_template/project_template.py
@@ -3,11 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
from frappe import _
+from frappe.model.document import Document
from frappe.utils import get_link_to_form
+
class ProjectTemplate(Document):
def validate(self):
diff --git a/erpnext/projects/doctype/project_template/project_template_dashboard.py b/erpnext/projects/doctype/project_template/project_template_dashboard.py
index 67f74f54f06..8eeaa8d6bd8 100644
--- a/erpnext/projects/doctype/project_template/project_template_dashboard.py
+++ b/erpnext/projects/doctype/project_template/project_template_dashboard.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+
def get_data():
return {
'fieldname': 'project_template',
diff --git a/erpnext/projects/doctype/project_template/test_project_template.py b/erpnext/projects/doctype/project_template/test_project_template.py
index d546fd09a30..f71984f3a41 100644
--- a/erpnext/projects/doctype/project_template/test_project_template.py
+++ b/erpnext/projects/doctype/project_template/test_project_template.py
@@ -3,10 +3,13 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
+
from erpnext.projects.doctype.task.test_task import create_task
+
class TestProjectTemplate(unittest.TestCase):
pass
diff --git a/erpnext/projects/doctype/project_template_task/project_template_task.py b/erpnext/projects/doctype/project_template_task/project_template_task.py
index 57bc4f1835e..e0861419886 100644
--- a/erpnext/projects/doctype/project_template_task/project_template_task.py
+++ b/erpnext/projects/doctype/project_template_task/project_template_task.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ProjectTemplateTask(Document):
pass
diff --git a/erpnext/projects/doctype/project_type/project_type.py b/erpnext/projects/doctype/project_type/project_type.py
index 36137ca0186..1089483cb3f 100644
--- a/erpnext/projects/doctype/project_type/project_type.py
+++ b/erpnext/projects/doctype/project_type/project_type.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe.model.document import Document
+
import frappe
from frappe import _
+from frappe.model.document import Document
+
class ProjectType(Document):
def on_trash(self):
diff --git a/erpnext/projects/doctype/project_type/test_project_type.js b/erpnext/projects/doctype/project_type/test_project_type.js
deleted file mode 100644
index c2198c452c0..00000000000
--- a/erpnext/projects/doctype/project_type/test_project_type.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Project Type", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially('Project Type', [
- // insert a new Project Type
- () => frappe.tests.make([
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/projects/doctype/project_type/test_project_type.py b/erpnext/projects/doctype/project_type/test_project_type.py
index ee23390f53f..a79020f14ff 100644
--- a/erpnext/projects/doctype/project_type/test_project_type.py
+++ b/erpnext/projects/doctype/project_type/test_project_type.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestProjectType(unittest.TestCase):
pass
diff --git a/erpnext/projects/doctype/project_update/project_update.py b/erpnext/projects/doctype/project_update/project_update.py
index 2e1ec746ed6..147e591f8fd 100644
--- a/erpnext/projects/doctype/project_update/project_update.py
+++ b/erpnext/projects/doctype/project_update/project_update.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class ProjectUpdate(Document):
pass
diff --git a/erpnext/projects/doctype/project_update/test_project_update.js b/erpnext/projects/doctype/project_update/test_project_update.js
deleted file mode 100644
index bda510b921a..00000000000
--- a/erpnext/projects/doctype/project_update/test_project_update.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Project Update", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Project Update
- () => frappe.tests.make('Project Update', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/projects/doctype/project_update/test_project_update.py b/erpnext/projects/doctype/project_update/test_project_update.py
index 2edd2f85a31..15966039799 100644
--- a/erpnext/projects/doctype/project_update/test_project_update.py
+++ b/erpnext/projects/doctype/project_update/test_project_update.py
@@ -3,9 +3,11 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
+
class TestProjectUpdate(unittest.TestCase):
pass
diff --git a/erpnext/projects/doctype/project_user/project_user.py b/erpnext/projects/doctype/project_user/project_user.py
index 3198f3b0893..7abe9459f24 100644
--- a/erpnext/projects/doctype/project_user/project_user.py
+++ b/erpnext/projects/doctype/project_user/project_user.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ProjectUser(Document):
pass
diff --git a/erpnext/projects/doctype/projects_settings/projects_settings.py b/erpnext/projects/doctype/projects_settings/projects_settings.py
index 9dcac14f9ad..88bb247a3c6 100644
--- a/erpnext/projects/doctype/projects_settings/projects_settings.py
+++ b/erpnext/projects/doctype/projects_settings/projects_settings.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ProjectsSettings(Document):
pass
diff --git a/erpnext/projects/doctype/projects_settings/test_projects_settings.js b/erpnext/projects/doctype/projects_settings/test_projects_settings.js
deleted file mode 100644
index f6feaa48049..00000000000
--- a/erpnext/projects/doctype/projects_settings/test_projects_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Projects Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Projects Settings
- () => frappe.tests.make('Projects Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/projects/doctype/projects_settings/test_projects_settings.py b/erpnext/projects/doctype/projects_settings/test_projects_settings.py
index d671da73b77..326624686da 100644
--- a/erpnext/projects/doctype/projects_settings/test_projects_settings.py
+++ b/erpnext/projects/doctype/projects_settings/test_projects_settings.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestProjectsSettings(unittest.TestCase):
pass
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index 39a6024e2cc..e0f32811645 100755
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -9,7 +9,7 @@ import frappe
from frappe import _, throw
from frappe.desk.form.assign_to import clear, close_all_assignments
from frappe.model.mapper import get_mapped_doc
-from frappe.utils import add_days, cstr, date_diff, get_link_to_form, getdate, today, flt
+from frappe.utils import add_days, cstr, date_diff, flt, get_link_to_form, getdate, today
from frappe.utils.nestedset import NestedSet
diff --git a/erpnext/projects/doctype/task/test_task.py b/erpnext/projects/doctype/task/test_task.py
index 0fad5e88074..41a9c168dfa 100644
--- a/erpnext/projects/doctype/task/test_task.py
+++ b/erpnext/projects/doctype/task/test_task.py
@@ -1,12 +1,15 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import unittest
-from frappe.utils import getdate, nowdate, add_days
+
+import frappe
+from frappe.utils import add_days, getdate, nowdate
from erpnext.projects.doctype.task.task import CircularReferenceError
+
class TestTask(unittest.TestCase):
def test_circular_reference(self):
task1 = create_task("_Test Task 1", add_days(nowdate(), -15), add_days(nowdate(), -10))
diff --git a/erpnext/projects/doctype/task_depends_on/task_depends_on.py b/erpnext/projects/doctype/task_depends_on/task_depends_on.py
index 723a0fc339b..ddb67ee30cb 100644
--- a/erpnext/projects/doctype/task_depends_on/task_depends_on.py
+++ b/erpnext/projects/doctype/task_depends_on/task_depends_on.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class TaskDependsOn(Document):
pass
diff --git a/erpnext/projects/doctype/task_type/task_type.py b/erpnext/projects/doctype/task_type/task_type.py
index 9c0b5325c64..5aacf8a2395 100644
--- a/erpnext/projects/doctype/task_type/task_type.py
+++ b/erpnext/projects/doctype/task_type/task_type.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class TaskType(Document):
pass
diff --git a/erpnext/projects/doctype/task_type/test_task_type.py b/erpnext/projects/doctype/task_type/test_task_type.py
index 1db6e27ed74..7690c3775af 100644
--- a/erpnext/projects/doctype/task_type/test_task_type.py
+++ b/erpnext/projects/doctype/task_type/test_task_type.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestTaskType(unittest.TestCase):
pass
diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.js b/erpnext/projects/doctype/timesheet/test_timesheet.js
deleted file mode 100644
index c081d6f8ea4..00000000000
--- a/erpnext/projects/doctype/timesheet/test_timesheet.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Timesheet", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Timesheet
- () => frappe.tests.make('Timesheet', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py
index 2b0c3abdd77..6b32c66dfe5 100644
--- a/erpnext/projects/doctype/timesheet/test_timesheet.py
+++ b/erpnext/projects/doctype/timesheet/test_timesheet.py
@@ -3,21 +3,28 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
-import unittest
import datetime
-from frappe.utils.make_random import get_random
-from frappe.utils import now_datetime, nowdate, add_days, add_months
-from erpnext.projects.doctype.timesheet.timesheet import OverlapError
-from erpnext.projects.doctype.timesheet.timesheet import make_salary_slip, make_sales_invoice
+import unittest
+
+import frappe
+from frappe.utils import add_months, now_datetime, nowdate
+
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
-from erpnext.payroll.doctype.salary_structure.test_salary_structure \
- import make_salary_structure, create_salary_structure_assignment
-from erpnext.payroll.doctype.salary_slip.test_salary_slip import (
- make_earning_salary_component,
- make_deduction_salary_component
-)
from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.payroll.doctype.salary_slip.test_salary_slip import (
+ make_deduction_salary_component,
+ make_earning_salary_component,
+)
+from erpnext.payroll.doctype.salary_structure.test_salary_structure import (
+ create_salary_structure_assignment,
+ make_salary_structure,
+)
+from erpnext.projects.doctype.timesheet.timesheet import (
+ OverlapError,
+ make_salary_slip,
+ make_sales_invoice,
+)
+
class TestTimesheet(unittest.TestCase):
@classmethod
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index 5f569d6bcd4..a20c70a6dac 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -3,19 +3,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe import _
import json
-from datetime import timedelta
-from erpnext.controllers.queries import get_match_cond
-from frappe.utils import flt, time_diff_in_hours, get_datetime, getdate, cint, date_diff, add_to_date
+
+import frappe
+from frappe import _
from frappe.model.document import Document
-from erpnext.manufacturing.doctype.workstation.workstation import (check_if_within_operating_hours,
- WorkstationHolidayError)
-from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
-from erpnext.setup.utils import get_exchange_rate
+from frappe.utils import flt, getdate, time_diff_in_hours
+
+from erpnext.controllers.queries import get_match_cond
from erpnext.hr.utils import validate_active_employee
+from erpnext.setup.utils import get_exchange_rate
+
class OverlapError(frappe.ValidationError): pass
class OverWorkLoggedError(frappe.ValidationError): pass
@@ -216,25 +215,53 @@ class Timesheet(Document):
@frappe.whitelist()
def get_projectwise_timesheet_data(project=None, parent=None, from_time=None, to_time=None):
- condition = ''
+ condition = ""
if project:
- condition += "and tsd.project = %(project)s"
+ condition += "AND tsd.project = %(project)s "
if parent:
- condition += "AND tsd.parent = %(parent)s"
+ condition += "AND tsd.parent = %(parent)s "
if from_time and to_time:
condition += "AND CAST(tsd.from_time as DATE) BETWEEN %(from_time)s AND %(to_time)s"
- return frappe.db.sql("""SELECT tsd.name as name,
- tsd.parent as parent, tsd.billing_hours as billing_hours,
- tsd.billing_amount as billing_amount, tsd.activity_type as activity_type,
- tsd.description as description, ts.currency as currency,
- tsd.project_name as project_name
- FROM `tabTimesheet Detail` tsd
- INNER JOIN `tabTimesheet` ts ON ts.name = tsd.parent
- WHERE tsd.parenttype = 'Timesheet'
- and tsd.docstatus=1 {0}
- and tsd.is_billable = 1
- and tsd.sales_invoice is null""".format(condition), {'project': project, 'parent': parent, 'from_time': from_time, 'to_time': to_time}, as_dict=1)
+ query = f"""
+ SELECT
+
+ tsd.name as name,
+ tsd.parent as time_sheet,
+ tsd.from_time as from_time,
+ tsd.to_time as to_time,
+ tsd.billing_hours as billing_hours,
+ tsd.billing_amount as billing_amount,
+ tsd.activity_type as activity_type,
+ tsd.description as description,
+ ts.currency as currency,
+ tsd.project_name as project_name
+
+ FROM `tabTimesheet Detail` tsd
+
+ INNER JOIN `tabTimesheet` ts
+ ON ts.name = tsd.parent
+
+ WHERE
+
+ tsd.parenttype = 'Timesheet'
+ AND tsd.docstatus = 1
+ AND tsd.is_billable = 1
+ AND tsd.sales_invoice is NULL
+ {condition}
+
+ ORDER BY tsd.from_time ASC
+ """
+
+ filters = {
+ "project": project,
+ "parent": parent,
+ "from_time": from_time,
+ "to_time": to_time
+ }
+
+ return frappe.db.sql(query, filters, as_dict=1)
+
@frappe.whitelist()
def get_timesheet_detail_rate(timelog, currency):
diff --git a/erpnext/projects/doctype/timesheet/timesheet_dashboard.py b/erpnext/projects/doctype/timesheet/timesheet_dashboard.py
index 088d98c4d5f..3ef1d92dcdb 100644
--- a/erpnext/projects/doctype/timesheet/timesheet_dashboard.py
+++ b/erpnext/projects/doctype/timesheet/timesheet_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'time_sheet',
diff --git a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.py b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.py
index 7da94b77772..4fd233ebb21 100644
--- a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.py
+++ b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class TimesheetDetail(Document):
pass
diff --git a/erpnext/projects/report/billing_summary.py b/erpnext/projects/report/billing_summary.py
index a22ed7b8338..dec2824fcc0 100644
--- a/erpnext/projects/report/billing_summary.py
+++ b/erpnext/projects/report/billing_summary.py
@@ -3,9 +3,11 @@
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import time_diff_in_hours, flt
+from frappe.utils import flt, time_diff_in_hours
+
def get_columns():
return [
diff --git a/erpnext/projects/report/daily_timesheet_summary/daily_timesheet_summary.py b/erpnext/projects/report/daily_timesheet_summary/daily_timesheet_summary.py
index 3dcae5b1b53..3a33b4b1a7e 100644
--- a/erpnext/projects/report/daily_timesheet_summary/daily_timesheet_summary.py
+++ b/erpnext/projects/report/daily_timesheet_summary/daily_timesheet_summary.py
@@ -2,10 +2,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.desk.reportview import build_match_conditions
+
def execute(filters=None):
if not filters:
filters = {}
diff --git a/erpnext/projects/report/delayed_tasks_summary/delayed_tasks_summary.py b/erpnext/projects/report/delayed_tasks_summary/delayed_tasks_summary.py
index cdabe6487ea..301639015c3 100644
--- a/erpnext/projects/report/delayed_tasks_summary/delayed_tasks_summary.py
+++ b/erpnext/projects/report/delayed_tasks_summary/delayed_tasks_summary.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.utils import date_diff, nowdate
+
def execute(filters=None):
columns, data = [], []
data = get_data(filters)
diff --git a/erpnext/projects/report/delayed_tasks_summary/test_delayed_tasks_summary.py b/erpnext/projects/report/delayed_tasks_summary/test_delayed_tasks_summary.py
index 78291b2d781..88c77c88b43 100644
--- a/erpnext/projects/report/delayed_tasks_summary/test_delayed_tasks_summary.py
+++ b/erpnext/projects/report/delayed_tasks_summary/test_delayed_tasks_summary.py
@@ -1,10 +1,14 @@
from __future__ import unicode_literals
+
import unittest
+
import frappe
-from frappe.utils import nowdate, add_days, add_months
+from frappe.utils import add_days, add_months, nowdate
+
from erpnext.projects.doctype.task.test_task import create_task
from erpnext.projects.report.delayed_tasks_summary.delayed_tasks_summary import execute
+
class TestDelayedTasksSummary(unittest.TestCase):
@classmethod
def setUp(self):
diff --git a/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py
index 17c92c234d5..30bd9f0182f 100644
--- a/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py
+++ b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py
@@ -2,10 +2,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import _
+
from erpnext.projects.report.billing_summary import get_columns, get_data
+
def execute(filters=None):
filters = frappe._dict(filters or {})
columns = get_columns()
diff --git a/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/employee_hours_utilization_based_on_timesheet.py b/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/employee_hours_utilization_based_on_timesheet.py
index 4d22f462463..d59a2ac52a6 100644
--- a/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/employee_hours_utilization_based_on_timesheet.py
+++ b/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/employee_hours_utilization_based_on_timesheet.py
@@ -2,11 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt, getdate
from six import iteritems
+
def execute(filters=None):
return EmployeeHoursReport(filters).run()
diff --git a/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/test_employee_util.py b/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/test_employee_util.py
index 969fc556e8d..f456c84a588 100644
--- a/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/test_employee_util.py
+++ b/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/test_employee_util.py
@@ -1,11 +1,16 @@
from __future__ import unicode_literals
-import unittest
-import frappe
+import unittest
+
+import frappe
from frappe.utils.make_random import get_random
-from erpnext.projects.report.employee_hours_utilization_based_on_timesheet.employee_hours_utilization_based_on_timesheet import execute
+
from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.projects.doctype.project.test_project import make_project
+from erpnext.projects.report.employee_hours_utilization_based_on_timesheet.employee_hours_utilization_based_on_timesheet import (
+ execute,
+)
+
class TestEmployeeUtilization(unittest.TestCase):
@classmethod
diff --git a/erpnext/projects/report/project_billing_summary/project_billing_summary.py b/erpnext/projects/report/project_billing_summary/project_billing_summary.py
index 17c92c234d5..30bd9f0182f 100644
--- a/erpnext/projects/report/project_billing_summary/project_billing_summary.py
+++ b/erpnext/projects/report/project_billing_summary/project_billing_summary.py
@@ -2,10 +2,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import _
+
from erpnext.projects.report.billing_summary import get_columns, get_data
+
def execute(filters=None):
filters = frappe._dict(filters or {})
columns = get_columns()
diff --git a/erpnext/projects/report/project_profitability/project_profitability.py b/erpnext/projects/report/project_profitability/project_profitability.py
index 0a52f7bf904..13e02c89355 100644
--- a/erpnext/projects/report/project_profitability/project_profitability.py
+++ b/erpnext/projects/report/project_profitability/project_profitability.py
@@ -2,10 +2,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt
+
def execute(filters=None):
columns, data = [], []
data = get_data(filters)
diff --git a/erpnext/projects/report/project_profitability/test_project_profitability.py b/erpnext/projects/report/project_profitability/test_project_profitability.py
index 180926fe258..8cf169b38f4 100644
--- a/erpnext/projects/report/project_profitability/test_project_profitability.py
+++ b/erpnext/projects/report/project_profitability/test_project_profitability.py
@@ -1,12 +1,19 @@
from __future__ import unicode_literals
+
import unittest
+
import frappe
-from frappe.utils import getdate, nowdate, add_days
+from frappe.utils import add_days, getdate, nowdate
+
from erpnext.hr.doctype.employee.test_employee import make_employee
-from erpnext.projects.doctype.timesheet.test_timesheet import make_salary_structure_for_timesheet, make_timesheet
+from erpnext.projects.doctype.timesheet.test_timesheet import (
+ make_salary_structure_for_timesheet,
+ make_timesheet,
+)
from erpnext.projects.doctype.timesheet.timesheet import make_salary_slip, make_sales_invoice
from erpnext.projects.report.project_profitability.project_profitability import execute
+
class TestProjectProfitability(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/projects/report/project_summary/project_summary.py b/erpnext/projects/report/project_summary/project_summary.py
index 98dd617f9b3..dbb4e848578 100644
--- a/erpnext/projects/report/project_summary/project_summary.py
+++ b/erpnext/projects/report/project_summary/project_summary.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
columns = get_columns()
data = []
diff --git a/erpnext/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py b/erpnext/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py
index c13d7cf3344..5d2b7dbc5be 100644
--- a/erpnext/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py
+++ b/erpnext/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
+
def execute(filters=None):
columns = get_columns()
proj_details = get_project_details()
diff --git a/erpnext/projects/utils.py b/erpnext/projects/utils.py
index c39f908e43e..69264704b4b 100644
--- a/erpnext/projects/utils.py
+++ b/erpnext/projects/utils.py
@@ -4,8 +4,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
+
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def query_task(doctype, txt, searchfield, start, page_len, filters):
diff --git a/erpnext/projects/web_form/tasks/tasks.py b/erpnext/projects/web_form/tasks/tasks.py
index e5a94048be1..aed794261ea 100644
--- a/erpnext/projects/web_form/tasks/tasks.py
+++ b/erpnext/projects/web_form/tasks/tasks.py
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
import frappe
+
def get_context(context):
if frappe.form_dict.project:
context.parents = [{'title': frappe.form_dict.project, 'route': '/projects?project='+ frappe.form_dict.project}]
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index 6b70dab8037..4cf9bb11eff 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -11,7 +11,8 @@
],
"js/erpnext-web.min.js": [
"public/js/website_utils.js",
- "public/js/shopping_cart.js"
+ "public/js/shopping_cart.js",
+ "public/js/wishlist.js"
],
"css/erpnext-web.css": [
"public/scss/website.scss",
@@ -70,6 +71,12 @@
"public/js/bank_reconciliation_tool/number_card.js",
"public/js/bank_reconciliation_tool/dialog_manager.js"
],
+ "js/e-commerce.min.js": [
+ "e_commerce/product_ui/views.js",
+ "e_commerce/product_ui/grid.js",
+ "e_commerce/product_ui/list.js",
+ "e_commerce/product_ui/search.js"
+ ],
"js/hierarchy-chart.min.js": [
"public/js/hierarchy_chart/hierarchy_chart_desktop.js",
"public/js/hierarchy_chart/hierarchy_chart_mobile.js"
diff --git a/erpnext/public/js/conf.js b/erpnext/public/js/conf.js
index eb709e5e85e..a0f56a2d07f 100644
--- a/erpnext/public/js/conf.js
+++ b/erpnext/public/js/conf.js
@@ -21,6 +21,6 @@ $.extend(frappe.breadcrumbs.module_map, {
'Geo': 'Settings',
'Portal': 'Website',
'Utilities': 'Settings',
- 'Shopping Cart': 'Website',
+ 'E-commerce': 'Website',
'Contacts': 'CRM'
});
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 0e99b43befa..6c1d5f9898e 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -487,6 +487,10 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
var me = this;
var item = frappe.get_doc(cdt, cdn);
var update_stock = 0, show_batch_dialog = 0;
+
+ item.weight_per_unit = 0;
+ item.weight_uom = '';
+
if(['Sales Invoice'].includes(this.frm.doc.doctype)) {
update_stock = cint(me.frm.doc.update_stock);
show_batch_dialog = update_stock;
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 23ec2fdb849..62867327537 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -67,8 +67,6 @@ erpnext.HierarchyChart = class {
}
show() {
- frappe.breadcrumbs.add('HR');
-
this.setup_actions();
if ($(`[data-fieldname="company"]`).length) return;
let me = this;
@@ -83,8 +81,9 @@ erpnext.HierarchyChart = class {
reqd: 1,
change: () => {
me.company = undefined;
+ $('#hierarchy-chart-wrapper').remove();
- if (company.get_value() && me.company != company.get_value()) {
+ if (company.get_value()) {
me.company = company.get_value();
// svg for connectors
@@ -92,6 +91,8 @@ erpnext.HierarchyChart = class {
me.setup_hierarchy();
me.render_root_nodes();
me.all_nodes_expanded = false;
+ } else {
+ frappe.throw(__('Please select a company first.'));
}
}
});
@@ -172,11 +173,11 @@ erpnext.HierarchyChart = class {
`);
this.page.main
- .find('#hierarchy-chart-wrapper')
+ .find('#hierarchy-chart')
+ .empty()
.append(this.$hierarchy);
this.nodes = {};
- this.all_nodes_expanded = false;
}
make_svg_markers() {
@@ -203,6 +204,8 @@ erpnext.HierarchyChart = class {
+
+
`);
}
@@ -219,7 +222,10 @@ erpnext.HierarchyChart = class {
let expand_node = undefined;
let node = undefined;
- $.each(r.message, (i, data) => {
+ $.each(r.message, (_i, data) => {
+ if ($(`#${data.id}`).length)
+ return;
+
node = new me.Node({
id: data.id,
parent: $('
').appendTo(me.$hierarchy.find('.node-children')),
@@ -290,7 +296,7 @@ erpnext.HierarchyChart = class {
() => frappe.dom.freeze(),
() => this.setup_hierarchy(),
() => this.render_root_nodes(true),
- () => this.get_all_nodes(node.id, node.name),
+ () => this.get_all_nodes(),
(data_list) => this.render_children_of_all_nodes(data_list),
() => frappe.dom.unfreeze()
]);
@@ -341,15 +347,13 @@ erpnext.HierarchyChart = class {
node.expanded = true;
}
- get_all_nodes(node_id, node_name) {
+ get_all_nodes() {
return new Promise(resolve => {
frappe.call({
method: 'erpnext.utilities.hierarchy_chart.get_all_nodes',
args: {
method: this.method,
- company: this.company,
- parent: node_id,
- parent_name: node_name
+ company: this.company
},
callback: (r) => {
resolve(r.message);
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
index b1b78c05174..b1a88795572 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js
@@ -59,8 +59,6 @@ erpnext.HierarchyChartMobile = class {
}
show() {
- frappe.breadcrumbs.add('HR');
-
let me = this;
if ($(`[data-fieldname="company"]`).length) return;
diff --git a/erpnext/public/js/shopping_cart.js b/erpnext/public/js/shopping_cart.js
index 6a923ae4234..d14740c1060 100644
--- a/erpnext/public/js/shopping_cart.js
+++ b/erpnext/public/js/shopping_cart.js
@@ -2,8 +2,8 @@
// License: GNU General Public License v3. See license.txt
// shopping cart
-frappe.provide("erpnext.shopping_cart");
-var shopping_cart = erpnext.shopping_cart;
+frappe.provide("erpnext.e_commerce.shopping_cart");
+var shopping_cart = erpnext.e_commerce.shopping_cart;
var getParams = function (url) {
var params = [];
@@ -51,10 +51,10 @@ frappe.ready(function() {
if (referral_sales_partner) {
$(".txtreferral_sales_partner").val(referral_sales_partner);
}
+
// update login
shopping_cart.show_shoppingcart_dropdown();
shopping_cart.set_cart_count();
- shopping_cart.bind_dropdown_cart_buttons();
shopping_cart.show_cart_navbar();
});
@@ -63,7 +63,7 @@ $.extend(shopping_cart, {
$(".shopping-cart").on('shown.bs.dropdown', function() {
if (!$('.shopping-cart-menu .cart-container').length) {
return frappe.call({
- method: 'erpnext.shopping_cart.cart.get_shopping_cart_menu',
+ method: 'erpnext.e_commerce.shopping_cart.cart.get_shopping_cart_menu',
callback: function(r) {
if (r.message) {
$('.shopping-cart-menu').html(r.message);
@@ -75,15 +75,18 @@ $.extend(shopping_cart, {
},
update_cart: function(opts) {
- if(frappe.session.user==="Guest") {
- if(localStorage) {
+ if (frappe.session.user==="Guest") {
+ if (localStorage) {
localStorage.setItem("last_visited", window.location.pathname);
}
- window.location.href = "/login";
+ frappe.call('erpnext.e_commerce.api.get_guest_redirect_on_action').then((res) => {
+ window.location.href = res.message || "/login";
+ });
} else {
+ shopping_cart.freeze();
return frappe.call({
type: "POST",
- method: "erpnext.shopping_cart.cart.update_cart",
+ method: "erpnext.e_commerce.shopping_cart.cart.update_cart",
args: {
item_code: opts.item_code,
qty: opts.qty,
@@ -92,10 +95,8 @@ $.extend(shopping_cart, {
},
btn: opts.btn,
callback: function(r) {
- shopping_cart.set_cart_count();
- if (r.message.shopping_cart_menu) {
- $('.shopping-cart-menu').html(r.message.shopping_cart_menu);
- }
+ shopping_cart.unfreeze();
+ shopping_cart.set_cart_count(true);
if(opts.callback)
opts.callback(r);
}
@@ -103,7 +104,9 @@ $.extend(shopping_cart, {
}
},
- set_cart_count: function() {
+ set_cart_count: function(animate=false) {
+ $(".intermediate-empty-cart").remove();
+
var cart_count = frappe.get_cookie("cart_count");
if(frappe.session.user==="Guest") {
cart_count = 0;
@@ -118,24 +121,37 @@ $.extend(shopping_cart, {
if(parseInt(cart_count) === 0 || cart_count === undefined) {
$cart.css("display", "none");
- $(".cart-items").html('Cart is Empty');
$(".cart-tax-items").hide();
$(".btn-place-order").hide();
- $(".cart-addresses").hide();
+ $(".cart-payment-addresses").hide();
+
+ let intermediate_empty_cart_msg = `
+
+ ${ __("Cart is Empty") }
+
+ `;
+ $(".cart-table").after(intermediate_empty_cart_msg);
}
else {
$cart.css("display", "inline");
+ $("#cart-count").text(cart_count);
}
if(cart_count) {
$badge.html(cart_count);
+
+ if (animate) {
+ $cart.addClass("cart-animate");
+ setTimeout(() => {
+ $cart.removeClass("cart-animate");
+ }, 500);
+ }
} else {
$badge.remove();
}
},
shopping_cart_update: function({item_code, qty, cart_dropdown, additional_notes}) {
- frappe.freeze();
shopping_cart.update_cart({
item_code,
qty,
@@ -143,10 +159,12 @@ $.extend(shopping_cart, {
with_items: 1,
btn: this,
callback: function(r) {
- frappe.unfreeze();
if(!r.exc) {
$(".cart-items").html(r.message.items);
- $(".cart-tax-items").html(r.message.taxes);
+ $(".cart-tax-items").html(r.message.total);
+ $(".payment-summary").html(r.message.taxes_and_totals);
+ shopping_cart.set_cart_count();
+
if (cart_dropdown != true) {
$(".cart-icon").hide();
}
@@ -155,35 +173,71 @@ $.extend(shopping_cart, {
});
},
-
- bind_dropdown_cart_buttons: function () {
- $(".cart-icon").on('click', '.number-spinner button', function () {
- var btn = $(this),
- input = btn.closest('.number-spinner').find('input'),
- oldValue = input.val().trim(),
- newVal = 0;
-
- if (btn.attr('data-dir') == 'up') {
- newVal = parseInt(oldValue) + 1;
- } else {
- if (oldValue > 1) {
- newVal = parseInt(oldValue) - 1;
- }
- }
- input.val(newVal);
- var item_code = input.attr("data-item-code");
- shopping_cart.shopping_cart_update({item_code, qty: newVal, cart_dropdown: true});
- return false;
- });
-
- },
-
show_cart_navbar: function () {
frappe.call({
- method: "erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings.is_cart_enabled",
+ method: "erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings.is_cart_enabled",
callback: function(r) {
$(".shopping-cart").toggleClass('hidden', r.message ? false : true);
}
});
+ },
+
+ toggle_button_class(button, remove, add) {
+ button.removeClass(remove);
+ button.addClass(add);
+ },
+
+ bind_add_to_cart_action() {
+ $('.page_content').on('click', '.btn-add-to-cart-list', (e) => {
+ const $btn = $(e.currentTarget);
+ $btn.prop('disabled', true);
+
+ if (frappe.session.user==="Guest") {
+ if (localStorage) {
+ localStorage.setItem("last_visited", window.location.pathname);
+ }
+ frappe.call('erpnext.e_commerce.api.get_guest_redirect_on_action').then((res) => {
+ window.location.href = res.message || "/login";
+ });
+ return;
+ }
+
+ $btn.addClass('hidden');
+ $btn.closest('.cart-action-container').addClass('d-flex');
+ $btn.parent().find('.go-to-cart').removeClass('hidden');
+ $btn.parent().find('.go-to-cart-grid').removeClass('hidden');
+ $btn.parent().find('.cart-indicator').removeClass('hidden');
+
+ const item_code = $btn.data('item-code');
+ erpnext.e_commerce.shopping_cart.update_cart({
+ item_code,
+ qty: 1
+ });
+
+ });
+ },
+
+ freeze() {
+ if (window.location.pathname !== "/cart") return;
+
+ if (!$('#freeze').length) {
+ let freeze = $('
')
+ .appendTo("body");
+
+ setTimeout(function() {
+ freeze.addClass("show");
+ }, 1);
+ } else {
+ $("#freeze").addClass("show");
+ }
+ },
+
+ unfreeze() {
+ if ($('#freeze').length) {
+ let freeze = $('#freeze').removeClass("show");
+ setTimeout(function() {
+ freeze.remove();
+ }, 1);
+ }
}
});
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 85c1693657f..ee8a516a148 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -86,9 +86,9 @@ $.extend(erpnext, {
proceed_save_with_reminders_frequency_change: () => {
frappe.ui.hide_open_dialog();
-
+
frappe.call({
- method: 'erpnext.hr.doctype.hr_settings.hr_settings.set_proceed_with_frequency_change',
+ method: 'erpnext.hr.doctype.hr_settings.hr_settings.set_proceed_with_frequency_change',
callback: () => {
cur_frm.save();
}
@@ -709,6 +709,9 @@ erpnext.utils.map_current_doc = function(opts) {
setters: opts.setters,
get_query: opts.get_query,
add_filters_group: 1,
+ allow_child_item_selection: opts.allow_child_item_selection,
+ child_fieldname: opts.child_fielname,
+ child_columns: opts.child_columns,
action: function(selections, args) {
let values = selections;
if(values.length === 0){
@@ -716,7 +719,7 @@ erpnext.utils.map_current_doc = function(opts) {
return;
}
opts.source_name = values;
- opts.setters = args;
+ opts.args = args;
d.dialog.hide();
_map();
},
diff --git a/erpnext/public/js/wishlist.js b/erpnext/public/js/wishlist.js
new file mode 100644
index 00000000000..f6599e9f6d1
--- /dev/null
+++ b/erpnext/public/js/wishlist.js
@@ -0,0 +1,204 @@
+frappe.provide("erpnext.e_commerce.wishlist");
+var wishlist = erpnext.e_commerce.wishlist;
+
+frappe.provide("erpnext.e_commerce.shopping_cart");
+var shopping_cart = erpnext.e_commerce.shopping_cart;
+
+$.extend(wishlist, {
+ set_wishlist_count: function(animate=false) {
+ // set badge count for wishlist icon
+ var wish_count = frappe.get_cookie("wish_count");
+ if (frappe.session.user==="Guest") {
+ wish_count = 0;
+ }
+
+ if (wish_count) {
+ $(".wishlist").toggleClass('hidden', false);
+ }
+
+ var $wishlist = $('.wishlist-icon');
+ var $badge = $wishlist.find("#wish-count");
+
+ if (parseInt(wish_count) === 0 || wish_count === undefined) {
+ $wishlist.css("display", "none");
+ } else {
+ $wishlist.css("display", "inline");
+ }
+ if (wish_count) {
+ $badge.html(wish_count);
+ if (animate) {
+ $wishlist.addClass('cart-animate');
+ setTimeout(() => {
+ $wishlist.removeClass('cart-animate');
+ }, 500);
+ }
+ } else {
+ $badge.remove();
+ }
+ },
+
+ bind_move_to_cart_action: function() {
+ // move item to cart from wishlist
+ $('.page_content').on("click", ".btn-add-to-cart", (e) => {
+ const $move_to_cart_btn = $(e.currentTarget);
+ let item_code = $move_to_cart_btn.data("item-code");
+
+ shopping_cart.shopping_cart_update({
+ item_code,
+ qty: 1,
+ cart_dropdown: true
+ });
+
+ let success_action = function() {
+ const $card_wrapper = $move_to_cart_btn.closest(".wishlist-card");
+ $card_wrapper.addClass("wish-removed");
+ };
+ let args = { item_code: item_code };
+ this.add_remove_from_wishlist("remove", args, success_action, null, true);
+ });
+ },
+
+ bind_remove_action: function() {
+ // remove item from wishlist
+ let me = this;
+
+ $('.page_content').on("click", ".remove-wish", (e) => {
+ const $remove_wish_btn = $(e.currentTarget);
+ let item_code = $remove_wish_btn.data("item-code");
+
+ let success_action = function() {
+ const $card_wrapper = $remove_wish_btn.closest(".wishlist-card");
+ $card_wrapper.addClass("wish-removed");
+ if (frappe.get_cookie("wish_count") == 0) {
+ $(".page_content").empty();
+ me.render_empty_state();
+ }
+ };
+ let args = { item_code: item_code };
+ this.add_remove_from_wishlist("remove", args, success_action);
+ });
+ },
+
+ bind_wishlist_action() {
+ // 'wish'('like') or 'unwish' item in product listing
+ $('.page_content').on('click', '.like-action, .like-action-list', (e) => {
+ const $btn = $(e.currentTarget);
+ this.wishlist_action($btn);
+ });
+ },
+
+ wishlist_action(btn) {
+ const $wish_icon = btn.find('.wish-icon');
+ let me = this;
+
+ if (frappe.session.user==="Guest") {
+ if (localStorage) {
+ localStorage.setItem("last_visited", window.location.pathname);
+ }
+ this.redirect_guest();
+ return;
+ }
+
+ let success_action = function() {
+ erpnext.e_commerce.wishlist.set_wishlist_count(true);
+ };
+
+ if ($wish_icon.hasClass('wished')) {
+ // un-wish item
+ btn.removeClass("like-animate");
+ btn.addClass("like-action-wished");
+ this.toggle_button_class($wish_icon, 'wished', 'not-wished');
+
+ let args = { item_code: btn.data('item-code') };
+ let failure_action = function() {
+ me.toggle_button_class($wish_icon, 'not-wished', 'wished');
+ };
+ this.add_remove_from_wishlist("remove", args, success_action, failure_action);
+ } else {
+ // wish item
+ btn.addClass("like-animate");
+ btn.addClass("like-action-wished");
+ this.toggle_button_class($wish_icon, 'not-wished', 'wished');
+
+ let args = {item_code: btn.data('item-code')};
+ let failure_action = function() {
+ me.toggle_button_class($wish_icon, 'wished', 'not-wished');
+ };
+ this.add_remove_from_wishlist("add", args, success_action, failure_action);
+ }
+ },
+
+ toggle_button_class(button, remove, add) {
+ button.removeClass(remove);
+ button.addClass(add);
+ },
+
+ add_remove_from_wishlist(action, args, success_action, failure_action, async=false) {
+ /* AJAX call to add or remove Item from Wishlist
+ action: "add" or "remove"
+ args: args for method (item_code, price, formatted_price),
+ success_action: method to execute on successs,
+ failure_action: method to execute on failure,
+ async: make call asynchronously (true/false). */
+ if (frappe.session.user==="Guest") {
+ if (localStorage) {
+ localStorage.setItem("last_visited", window.location.pathname);
+ }
+ this.redirect_guest();
+ } else {
+ let method = "erpnext.e_commerce.doctype.wishlist.wishlist.add_to_wishlist";
+ if (action === "remove") {
+ method = "erpnext.e_commerce.doctype.wishlist.wishlist.remove_from_wishlist";
+ }
+
+ frappe.call({
+ async: async,
+ type: "POST",
+ method: method,
+ args: args,
+ callback: function (r) {
+ if (r.exc) {
+ if (failure_action && (typeof failure_action === 'function')) {
+ failure_action();
+ }
+ frappe.msgprint({
+ message: __("Sorry, something went wrong. Please refresh."),
+ indicator: "red", title: __("Note")
+ });
+ } else if (success_action && (typeof success_action === 'function')) {
+ success_action();
+ }
+ }
+ });
+ }
+ },
+
+ redirect_guest() {
+ frappe.call('erpnext.e_commerce.api.get_guest_redirect_on_action').then((res) => {
+ window.location.href = res.message || "/login";
+ });
+ },
+
+ render_empty_state() {
+ $(".page_content").append(`
+
+
+
+
+
${ __('Wishlist is empty !') }
+
+ `);
+ }
+
+});
+
+frappe.ready(function() {
+ if (window.location.pathname !== "/wishlist") {
+ $(".wishlist").toggleClass('hidden', true);
+ wishlist.set_wishlist_count();
+ } else {
+ wishlist.bind_move_to_cart_action();
+ wishlist.bind_remove_action();
+ }
+
+});
\ No newline at end of file
diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss
index 490a7c4af73..fbb26a8008c 100644
--- a/erpnext/public/scss/shopping_cart.scss
+++ b/erpnext/public/scss/shopping_cart.scss
@@ -1,16 +1,17 @@
@import "frappe/public/scss/common/mixins";
-body.product-page {
- background: var(--gray-50);
+:root {
+ --green-info: #38A160;
+ --product-bg-color: white;
+ --body-bg-color: var(--gray-50);
}
+body.product-page {
+ background: var(--body-bg-color);
+}
.item-breadcrumbs {
.breadcrumb-container {
- ol.breadcrumb {
- background-color: var(--gray-50) !important;
- }
-
a {
color: var(--gray-900);
}
@@ -61,9 +62,21 @@ body.product-page {
}
}
+.no-image-item {
+ height: 340px;
+ width: 340px;
+ background: var(--gray-100);
+ border-radius: var(--border-radius);
+ font-size: 2rem;
+ color: var(--gray-500);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
.item-card-group-section {
.card {
- height: 360px;
+ height: 100%;
align-items: center;
justify-content: center;
@@ -73,6 +86,19 @@ body.product-page {
}
}
+ .card:hover, .card:focus-within {
+ .btn-add-to-cart-list {
+ visibility: visible;
+ }
+ .like-action {
+ visibility: visible;
+ }
+ .btn-explore-variants {
+ visibility: visible;
+ }
+ }
+
+
.card-img-container {
height: 210px;
width: 100%;
@@ -86,14 +112,28 @@ body.product-page {
.no-image {
@include flex(flex, center, center, null);
- height: 200px;
- margin: 0 auto;
- margin-top: var(--margin-xl);
+ height: 220px;
+ background: var(--gray-100);
+ width: 100%;
+ border-radius: var(--border-radius) var(--border-radius) 0 0;
+ font-size: 2rem;
+ color: var(--gray-500);
+ }
+
+ .no-image-list {
+ @include flex(flex, center, center, null);
+ height: 150px;
background: var(--gray-100);
- width: 80%;
border-radius: var(--border-radius);
font-size: 2rem;
color: var(--gray-500);
+ margin-top: 15px;
+ margin-bottom: 15px;
+ }
+
+ .card-body-flex {
+ display: flex;
+ flex-direction: column;
}
.product-title {
@@ -126,10 +166,70 @@ body.product-page {
font-weight: 600;
color: var(--text-color);
margin: var(--margin-sm) 0;
+ margin-bottom: auto !important;
+
+ .striked-price {
+ font-weight: 500;
+ font-size: 15px;
+ color: var(--gray-500);
+ }
+ }
+
+ .product-info-green {
+ color: var(--green-info);
+ font-weight: 600;
}
.item-card {
padding: var(--padding-sm);
+ min-width: 300px;
+ }
+
+ .wishlist-card {
+ padding: var(--padding-sm);
+ min-width: 260px;
+ .card-body-flex {
+ display: flex;
+ flex-direction: column;
+ }
+ }
+}
+
+#products-list-area, #products-grid-area {
+ padding: 0 5px;
+}
+
+.list-row {
+ background-color: white;
+ padding-bottom: 1rem;
+ padding-top: 1.5rem !important;
+ border-radius: 8px;
+ border-bottom: 1px solid var(--gray-50);
+
+ &:hover, &:focus-within {
+ box-shadow: 0px 16px 60px rgba(0, 0, 0, 0.08), 0px 8px 30px -20px rgba(0, 0, 0, 0.04);
+ transition: box-shadow 400ms;
+
+ .btn-add-to-cart-list {
+ visibility: visible;
+ }
+ .like-action-list {
+ visibility: visible;
+ }
+ .btn-explore-variants {
+ visibility: visible;
+ }
+ }
+
+ .product-code {
+ padding-top: 0 !important;
+ }
+
+ .btn-explore-variants {
+ min-width: 135px;
+ max-height: 30px;
+ float: right;
+ padding: 0.25rem 1rem;
}
}
@@ -174,28 +274,76 @@ body.product-page {
}
}
+.product-filter {
+ width: 14px !important;
+ height: 14px !important;
+}
+
+.discount-filter {
+ &:before {
+ width: 14px !important;
+ height: 14px !important;
+ }
+}
+
+.list-image {
+ border: none !important;
+ overflow: hidden;
+ max-height: 200px;
+ background-color: white;
+}
+
.product-container {
@include card($padding: var(--padding-md));
- min-height: 70vh;
+ background-color: var(--product-bg-color) !important;
+ min-height: fit-content;
.product-details {
- max-width: 40%;
- margin-left: -30px;
+ max-width: 50%;
.btn-add-to-cart {
- font-size: var(--text-base);
+ font-size: 14px;
+ }
+ }
+
+ &.item-main {
+ .product-image {
+ width: 100%;
+ }
+ }
+
+ .expand {
+ max-width: 100% !important; // expand in absence of slideshow
+ }
+
+ @media (max-width: 789px) {
+ .product-details {
+ max-width: 90% !important;
+
+ .btn-add-to-cart {
+ font-size: 14px;
+ }
+ }
+ }
+
+ .btn-add-to-wishlist {
+ svg use {
+ stroke: #F47A7A;
+ }
+ }
+
+ .btn-view-in-wishlist {
+ svg use {
+ fill: #F47A7A;
+ stroke: none;
}
}
.product-title {
- font-size: 24px;
+ font-size: 16px;
font-weight: 600;
color: var(--text-color);
- }
-
- .product-code {
- color: var(--text-muted);
- font-size: 13px;
+ padding: 0 !important;
}
.product-description {
@@ -232,7 +380,7 @@ body.product-page {
max-height: 430px;
}
- overflow: scroll;
+ overflow: auto;
}
.item-slideshow-image {
@@ -251,29 +399,114 @@ body.product-page {
.item-cart {
.product-price {
- font-size: 20px;
+ font-size: 22px;
color: var(--text-color);
font-weight: 600;
.formatted-price {
color: var(--text-muted);
- font-size: var(--text-base);
+ font-size: 14px;
}
}
.no-stock {
font-size: var(--text-base);
}
+
+ .offers-heading {
+ font-size: 16px !important;
+ color: var(--text-color);
+ .tag-icon {
+ --icon-stroke: var(--gray-500);
+ }
+ }
+
+ .w-30-40 {
+ width: 30%;
+
+ @media (max-width: 992px) {
+ width: 40%;
+ }
+ }
+ }
+
+ .tab-content {
+ font-size: 14px;
+ }
+}
+
+// Item Recommendations
+.recommended-item-section {
+ padding-right: 0;
+
+ .recommendation-header {
+ font-size: 16px;
+ font-weight: 500
+ }
+
+ .recommendation-container {
+ padding: .5rem;
+ min-height: 0px;
+
+ .r-item-image {
+ width: 40%;
+
+ .r-product-image {
+ padding: 2px 15px;
+ }
+
+ .no-image-r-item {
+ display: flex; justify-content: center;
+ background-color: var(--gray-200);
+ align-items: center;
+ color: var(--gray-400);
+ margin-top: .15rem;
+ border-radius: 6px;
+ height: 100%;
+ font-size: 24px;
+ }
+ }
+
+ .r-item-info {
+ font-size: 14px;
+ padding-right: 0;
+ width: 60%;
+
+ a {
+ color: var(--gray-800);
+ font-weight: 400;
+ }
+
+ .item-price {
+ font-size: 15px;
+ font-weight: 600;
+ color: var(--text-color);
+ }
+
+ .striked-item-price {
+ font-weight: 500;
+ color: var(--gray-500);
+ }
+ }
+ }
+}
+
+.product-code {
+ padding: .5rem 0;
+ color: var(--text-muted);
+ font-size: 14px;
+ .product-item-group {
+ padding-right: .25rem;
+ border-right: solid 1px var(--text-muted);
+ }
+
+ .product-item-code {
+ padding-left: .5rem;
}
}
.item-configurator-dialog {
- .modal-header {
- padding: var(--padding-md) var(--padding-xl);
- }
-
.modal-body {
- padding: 0 var(--padding-xl);
padding-bottom: var(--padding-xl);
.status-area {
@@ -313,20 +546,74 @@ body.product-page {
}
}
-.cart-icon {
- .cart-badge {
- position: relative;
- top: -10px;
- left: -12px;
- background: var(--red-600);
- width: 16px;
- align-items: center;
- height: 16px;
- font-size: 10px;
- border-radius: 50%;
+.sub-category-container {
+ padding-bottom: .5rem;
+ margin-bottom: 1.25rem;
+ border-bottom: 1px solid var(--table-border-color);
+
+ .heading {
+ color: var(--gray-500);
}
}
+.scroll-categories {
+ white-space: nowrap;
+ overflow-x: auto;
+
+ .category-pill {
+ margin: 0px 4px;
+ display: inline-block;
+ padding: 6px 12px;
+ background-color: #ecf5fe;
+ width: fit-content;
+ font-size: 14px;
+ border-radius: 18px;
+ color: var(--blue-500);
+ }
+}
+
+
+.shopping-badge {
+ position: relative;
+ top: -10px;
+ left: -12px;
+ background: var(--red-600);
+ width: 16px;
+ align-items: center;
+ height: 16px;
+ font-size: 10px;
+ border-radius: 50%;
+}
+
+
+.cart-animate {
+ animation: wiggle 0.5s linear;
+}
+@keyframes wiggle {
+ 8%,
+ 41% {
+ transform: translateX(-10px);
+ }
+ 25%,
+ 58% {
+ transform: translate(10px);
+ }
+ 75% {
+ transform: translate(-5px);
+ }
+ 92% {
+ transform: translate(5px);
+ }
+ 0%,
+ 100% {
+ transform: translate(0);
+ }
+}
+
+.total-discount {
+ font-size: 14px;
+ color: var(--primary-color) !important;
+}
#page-cart {
.shopping-cart-header {
@@ -340,6 +627,7 @@ body.product-page {
display: flex;
flex-direction: column;
justify-content: space-between;
+ height: fit-content;
}
.cart-items-header {
@@ -347,6 +635,10 @@ body.product-page {
}
.cart-table {
+ tr {
+ margin-bottom: 1rem;
+ }
+
th, tr, td {
border-color: var(--border-color);
border-width: 1px;
@@ -364,71 +656,200 @@ body.product-page {
color: var(--text-color);
}
+ .cart-item-image {
+ width: 20%;
+ min-width: 100px;
+ img {
+ max-height: 112px;
+ }
+
+ .no-image-cart-item {
+ max-height: 112px;
+ display: flex; justify-content: center;
+ background-color: var(--gray-200);
+ align-items: center;
+ color: var(--gray-400);
+ margin-top: .15rem;
+ border-radius: 6px;
+ height: 100%;
+ font-size: 24px;
+ }
+ }
+
.cart-items {
.item-title {
- font-size: var(--text-base);
+ width: 80%;
+ font-size: 14px;
font-weight: 500;
color: var(--text-color);
}
.item-subtitle {
color: var(--text-muted);
- font-size: var(--text-md);
+ font-size: 13px;
}
.item-subtotal {
- font-size: var(--text-base);
+ font-size: 14px;
font-weight: 500;
}
+ .sm-item-subtotal {
+ font-size: 14px;
+ font-weight: 500;
+ display: none;
+
+ @media (max-width: 992px) {
+ display: unset !important;
+ }
+ }
+
.item-rate {
- font-size: var(--text-md);
+ font-size: 13px;
color: var(--text-muted);
}
- textarea {
- width: 40%;
+ .free-tag {
+ padding: 4px 8px;
+ border-radius: 4px;
+ background-color: var(--dark-green-50);
}
+
+ textarea {
+ width: 80%;
+ height: 60px;
+ font-size: 14px;
+ }
+
}
.cart-tax-items {
.item-grand-total {
font-size: 16px;
- font-weight: 600;
+ font-weight: 700;
color: var(--text-color);
}
}
+
+ .column-sm-view {
+ @media (max-width: 992px) {
+ display: none !important;
+ }
+ }
+
+ .item-column {
+ width: 50%;
+ @media (max-width: 992px) {
+ width: 70%;
+ }
+ }
+
+ .remove-cart-item {
+ border-radius: 6px;
+ border: 1px solid var(--gray-100);
+ width: 28px;
+ height: 28px;
+ font-weight: 300;
+ color: var(--gray-700);
+ background-color: var(--gray-100);
+ float: right;
+ cursor: pointer;
+ margin-top: .25rem;
+ justify-content: center;
+ }
+
+ .remove-cart-item-logo {
+ margin-top: 2px;
+ margin-left: 2.2px;
+ fill: var(--gray-700) !important;
+ }
}
- .cart-addresses {
+ .cart-payment-addresses {
hr {
border-color: var(--border-color);
}
}
+ .payment-summary {
+ h6 {
+ padding-bottom: 1rem;
+ border-bottom: solid 1px var(--gray-200);
+ }
+
+ table {
+ font-size: 14px;
+ td {
+ padding: 0;
+ padding-top: 0.35rem !important;
+ border: none !important;
+ }
+
+ &.grand-total {
+ border-top: solid 1px var(--gray-200);
+ }
+ }
+
+ .bill-label {
+ color: var(--gray-600);
+ }
+
+ .bill-content {
+ font-weight: 500;
+ &.net-total {
+ font-size: 16px;
+ font-weight: 600;
+ }
+ }
+
+ .btn-coupon-code {
+ font-size: 14px;
+ border: dashed 1px var(--gray-400);
+ box-shadow: none;
+ }
+ }
+
.number-spinner {
width: 75%;
+ min-width: 105px;
.cart-btn {
border: none;
background: var(--gray-100);
box-shadow: none;
+ width: 24px;
height: 28px;
align-items: center;
+ justify-content: center;
display: flex;
+ font-size: 20px;
+ font-weight: 300;
+ color: var(--gray-700);
}
.cart-qty {
height: 28px;
- font-size: var(--text-md);
+ font-size: 13px;
+ &:disabled {
+ background: var(--gray-100);
+ opacity: 0.65;
+ }
}
}
.place-order-container {
.btn-place-order {
- width: 62%;
+ float: right;
}
}
}
+
+ .t-and-c-container {
+ padding: 1.5rem;
+ }
+
+ .t-and-c-terms {
+ font-size: 14px;
+ }
}
.cart-empty.frappe-card {
@@ -444,7 +865,7 @@ body.product-page {
.address-card {
.card-title {
- font-size: var(--text-base);
+ font-size: 14px;
font-weight: 500;
}
@@ -453,27 +874,37 @@ body.product-page {
}
.card-text {
- font-size: var(--text-md);
+ font-size: 13px;
color: var(--gray-700);
}
.card-link {
- font-size: var(--text-md);
+ font-size: 13px;
svg use {
- stroke: var(--blue-500);
+ stroke: var(--primary-color);
}
}
.btn-change-address {
- color: var(--blue-500);
+ border: 1px solid var(--primary-color);
+ color: var(--primary-color);
+ box-shadow: none;
}
}
+.address-header {
+ margin-top: .15rem;padding: 0;
+}
+
+.btn-new-address {
+ float: right;
+ font-size: 15px !important;
+ color: var(--primary-color) !important;
+}
+
.btn-new-address:hover, .btn-change-address:hover {
- box-shadow: none;
- color: var(--blue-500) !important;
- border: 1px solid var(--blue-500);
+ color: var(--primary-color) !important;
}
.modal .address-card {
@@ -483,3 +914,451 @@ body.product-page {
border: 1px solid var(--dark-border-color);
}
}
+
+.cart-indicator {
+ position: absolute;
+ text-align: center;
+ width: 22px;
+ height: 22px;
+ left: calc(100% - 40px);
+ top: 22px;
+
+ border-radius: 66px;
+ box-shadow: 0px 2px 6px rgba(17, 43, 66, 0.08), 0px 1px 4px rgba(17, 43, 66, 0.1);
+ background: white;
+ color: var(--primary-color);
+ font-size: 14px;
+
+ &.list-indicator {
+ position: unset;
+ margin-left: auto;
+ }
+}
+
+
+.like-action {
+ visibility: hidden;
+ text-align: center;
+ position: absolute;
+ cursor: pointer;
+ width: 28px;
+ height: 28px;
+ left: 20px;
+ top: 20px;
+
+ /* White */
+ background: white;
+ box-shadow: 0px 2px 6px rgba(17, 43, 66, 0.08), 0px 1px 4px rgba(17, 43, 66, 0.1);
+ border-radius: 66px;
+
+ &.like-action-wished {
+ visibility: visible !important;
+ }
+
+ @media (max-width: 992px) {
+ visibility: visible !important;
+ }
+}
+
+.like-action-list {
+ visibility: hidden;
+ text-align: center;
+ position: absolute;
+ cursor: pointer;
+ width: 28px;
+ height: 28px;
+ left: 20px;
+ top: 0;
+
+ /* White */
+ background: white;
+ box-shadow: 0px 2px 6px rgba(17, 43, 66, 0.08), 0px 1px 4px rgba(17, 43, 66, 0.1);
+ border-radius: 66px;
+
+ &.like-action-wished {
+ visibility: visible !important;
+ }
+
+ @media (max-width: 992px) {
+ visibility: visible !important;
+ }
+}
+
+.like-action-item-fp {
+ visibility: visible !important;
+ position: unset;
+ float: right;
+}
+
+.like-animate {
+ animation: expand cubic-bezier(0.04, 0.4, 0.5, 0.95) 1.6s forwards 1;
+}
+
+@keyframes expand {
+ 30% {
+ transform: scale(1.3);
+ }
+ 50% {
+ transform: scale(0.8);
+ }
+ 70% {
+ transform: scale(1.1);
+ }
+ 100% {
+ transform: scale(1);
+ }
+ }
+
+.not-wished {
+ cursor: pointer;
+ stroke: #F47A7A !important;
+
+ &:hover {
+ fill: #F47A7A;
+ }
+}
+
+.wished {
+ stroke: none;
+ fill: #F47A7A !important;
+}
+
+.list-row-checkbox {
+ &:before {
+ display: none;
+ }
+
+ &:checked:before {
+ display: block;
+ z-index: 1;
+ }
+}
+
+#pay-for-order {
+ padding: .5rem 1rem; // Pay button in SO
+}
+
+.btn-explore-variants {
+ visibility: hidden;
+ box-shadow: none;
+ margin: var(--margin-sm) 0;
+ width: 90px;
+ max-height: 50px; // to avoid resizing on window resize
+ flex: none;
+ transition: 0.3s ease;
+
+ color: white;
+ background-color: var(--orange-500);
+ border: 1px solid var(--orange-500);
+ font-size: 13px;
+
+ &:hover {
+ color: white;
+ }
+}
+
+.btn-add-to-cart-list{
+ visibility: hidden;
+ box-shadow: none;
+ margin: var(--margin-sm) 0;
+ // margin-top: auto !important;
+ max-height: 50px; // to avoid resizing on window resize
+ flex: none;
+ transition: 0.3s ease;
+
+ font-size: 13px;
+
+ &:hover {
+ color: white;
+ }
+
+ @media (max-width: 992px) {
+ visibility: visible !important;
+ }
+}
+
+.go-to-cart-grid {
+ max-height: 30px;
+ margin-top: 1rem !important;
+}
+
+.go-to-cart {
+ max-height: 30px;
+ float: right;
+}
+
+.remove-wish {
+ background-color: white;
+ position: absolute;
+ cursor: pointer;
+ top:10px;
+ right: 20px;
+ width: 32px;
+ height: 32px;
+
+ border-radius: 50%;
+ border: 1px solid var(--gray-100);
+ box-shadow: 0px 2px 6px rgba(17, 43, 66, 0.08), 0px 1px 4px rgba(17, 43, 66, 0.1);
+}
+
+.wish-removed {
+ display: none;
+}
+
+.item-website-specification {
+ font-size: .875rem;
+ .product-title {
+ font-size: 18px;
+ }
+
+ .table {
+ width: 70%;
+ }
+
+ td {
+ border: none !important;
+ }
+
+ .spec-label {
+ color: var(--gray-600);
+ }
+
+ .spec-content {
+ color: var(--gray-800);
+ }
+}
+
+.reviews-full-page {
+ padding: 1rem 2rem;
+}
+
+.ratings-reviews-section {
+ border-top: 1px solid #E2E6E9;
+ padding: .5rem 1rem;
+}
+
+.reviews-header {
+ font-size: 20px;
+ font-weight: 600;
+ color: var(--gray-800);
+ display: flex;
+ align-items: center;
+ padding: 0;
+}
+
+.btn-write-review {
+ float: right;
+ padding: .5rem 1rem;
+ font-size: 14px;
+ font-weight: 400;
+ border: none !important;
+ box-shadow: none;
+
+ color: var(--gray-900);
+ background-color: var(--gray-100);
+
+ &:hover {
+ box-shadow: var(--btn-shadow);
+ }
+}
+
+.btn-view-more {
+ font-size: 14px;
+}
+
+.rating-summary-section {
+ display: flex;
+}
+
+.rating-summary-title {
+ margin-top: 0.15rem;
+ font-size: 18px;
+}
+
+.rating-summary-numbers {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ border-right: solid 1px var(--gray-100);
+}
+
+.user-review-title {
+ margin-top: 0.15rem;
+ font-size: 15px;
+ font-weight: 600;
+}
+
+.rating {
+ --star-fill: var(--gray-300);
+ .star-hover {
+ --star-fill: var(--yellow-100);
+ }
+ .star-click {
+ --star-fill: var(--yellow-300);
+ }
+}
+
+.ratings-pill {
+ background-color: var(--gray-100);
+ padding: .5rem 1rem;
+ border-radius: 66px;
+}
+
+.review {
+ max-width: 80%;
+ line-height: 1.6;
+ padding-bottom: 0.5rem;
+ border-bottom: 1px solid #E2E6E9;
+}
+
+.review-signature {
+ display: flex;
+ font-size: 13px;
+ color: var(--gray-500);
+ font-weight: 400;
+
+ .reviewer {
+ padding-right: 8px;
+ color: var(--gray-600);
+ }
+}
+
+.rating-progress-bar-section {
+ padding-bottom: 2rem;
+
+ .rating-bar-title {
+ margin-left: -15px;
+ }
+
+ .rating-progress-bar {
+ margin-bottom: 4px;
+ height: 7px;
+ margin-top: 6px;
+
+ .progress-bar-cosmetic {
+ background-color: var(--gray-600);
+ border-radius: var(--border-radius);
+ }
+ }
+}
+
+.offer-container {
+ font-size: 14px;
+}
+
+#search-results-container {
+ border: 1px solid var(--gray-200);
+ padding: .25rem 1rem;
+
+ .category-chip {
+ background-color: var(--gray-100);
+ border: none !important;
+ box-shadow: none;
+ }
+
+ .recent-search {
+ padding: .5rem .5rem;
+ border-radius: var(--border-radius);
+
+ &:hover {
+ background-color: var(--gray-100);
+ }
+ }
+}
+
+#search-box {
+ background-color: white;
+ height: 100%;
+ padding-left: 2.5rem;
+ border: 1px solid var(--gray-200);
+}
+
+.search-icon {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 2.5rem;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding-bottom: 1px;
+}
+
+#toggle-view {
+ float: right;
+
+ .btn-primary {
+ background-color: var(--gray-600);
+ box-shadow: 0 0 0 0.2rem var(--gray-400);
+ }
+}
+
+.placeholder-div {
+ height:80%;
+ width: -webkit-fill-available;
+ padding: 50px;
+ text-align: center;
+ background-color: #F9FAFA;
+ border-top-left-radius: calc(0.75rem - 1px);
+ border-top-right-radius: calc(0.75rem - 1px);
+}
+.placeholder {
+ font-size: 72px;
+}
+
+[data-path="cart"] {
+ .modal-backdrop {
+ background-color: var(--gray-50); // lighter backdrop only on cart freeze
+ }
+}
+
+.item-thumb {
+ height: 50px;
+ max-width: 80px;
+ min-width: 80px;
+ object-fit: cover;
+}
+
+.brand-line {
+ color: gray;
+}
+
+.btn-next, .btn-prev {
+ font-size: 14px;
+}
+
+.alert-error {
+ color: #e27a84;
+ background-color: #fff6f7;
+ border-color: #f5c6cb;
+}
+
+.font-md {
+ font-size: 14px !important;
+}
+
+.in-green {
+ color: var(--green-info) !important;
+ font-weight: 500;
+}
+
+.has-stock {
+ font-weight: 400 !important;
+}
+
+.out-of-stock {
+ font-weight: 400;
+ font-size: 14px;
+ line-height: 20px;
+ color: #F47A7A;
+}
+
+.mt-minus-2 {
+ margin-top: -2rem;
+}
+
+.mt-minus-1 {
+ margin-top: -1rem;
+}
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/non_conformance/non_conformance.py b/erpnext/quality_management/doctype/non_conformance/non_conformance.py
index d4e8cc7a716..a4613fdaf6b 100644
--- a/erpnext/quality_management/doctype/non_conformance/non_conformance.py
+++ b/erpnext/quality_management/doctype/non_conformance/non_conformance.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class NonConformance(Document):
pass
diff --git a/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py b/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py
index 54f8b58cfb0..759b117f9b0 100644
--- a/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py
+++ b/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestNonConformance(unittest.TestCase):
pass
diff --git a/erpnext/quality_management/doctype/quality_action/quality_action.py b/erpnext/quality_management/doctype/quality_action/quality_action.py
index 02401ba689d..646a0dfc2c8 100644
--- a/erpnext/quality_management/doctype/quality_action/quality_action.py
+++ b/erpnext/quality_management/doctype/quality_action/quality_action.py
@@ -3,9 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class QualityAction(Document):
def validate(self):
self.status = 'Open' if any([d.status=='Open' for d in self.resolutions]) else 'Completed'
diff --git a/erpnext/quality_management/doctype/quality_action/test_quality_action.py b/erpnext/quality_management/doctype/quality_action/test_quality_action.py
index 98d665f3910..33229d4b451 100644
--- a/erpnext/quality_management/doctype/quality_action/test_quality_action.py
+++ b/erpnext/quality_management/doctype/quality_action/test_quality_action.py
@@ -3,9 +3,9 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestQualityAction(unittest.TestCase):
# quality action has no code
pass
diff --git a/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.py b/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.py
index de8873feb0c..b456fb7e9a0 100644
--- a/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.py
+++ b/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityActionResolution(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py
index d3e96cf2d94..9189c282973 100644
--- a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py
+++ b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class QualityFeedback(Document):
@frappe.whitelist()
def set_parameters(self):
diff --git a/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py b/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py
index 5a8bd5ce30c..7a87c362446 100644
--- a/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py
+++ b/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py
@@ -3,9 +3,10 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
class TestQualityFeedback(unittest.TestCase):
def test_quality_feedback(self):
diff --git a/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.py b/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.py
index d652e8a57bb..9a21b263603 100644
--- a/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.py
+++ b/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityFeedbackParameter(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.py b/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.py
index 0c6dfc07802..c6a520a3c59 100644
--- a/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.py
+++ b/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityFeedbackTemplate(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py b/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py
index afed14b6ad0..1de58aae3ed 100644
--- a/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py
+++ b/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestQualityFeedbackTemplate(unittest.TestCase):
pass
diff --git a/erpnext/quality_management/doctype/quality_feedback_template_parameter/quality_feedback_template_parameter.py b/erpnext/quality_management/doctype/quality_feedback_template_parameter/quality_feedback_template_parameter.py
index 3f3348fd7fa..44a6b014a0c 100644
--- a/erpnext/quality_management/doctype/quality_feedback_template_parameter/quality_feedback_template_parameter.py
+++ b/erpnext/quality_management/doctype/quality_feedback_template_parameter/quality_feedback_template_parameter.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityFeedbackTemplateParameter(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_goal/quality_goal.py b/erpnext/quality_management/doctype/quality_goal/quality_goal.py
index 3e616b75ceb..2888401782a 100644
--- a/erpnext/quality_management/doctype/quality_goal/quality_goal.py
+++ b/erpnext/quality_management/doctype/quality_goal/quality_goal.py
@@ -3,10 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class QualityGoal(Document):
def validate(self):
pass
diff --git a/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py b/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py
index 0e135b50212..84240d227ea 100644
--- a/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py
+++ b/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py
@@ -3,9 +3,10 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from erpnext.quality_management.doctype.quality_procedure.test_quality_procedure import create_procedure
+
+import frappe
+
class TestQualityGoal(unittest.TestCase):
def test_quality_goal(self):
diff --git a/erpnext/quality_management/doctype/quality_goal_objective/quality_goal_objective.py b/erpnext/quality_management/doctype/quality_goal_objective/quality_goal_objective.py
index f4bd357f1b2..c9c2c6e564c 100644
--- a/erpnext/quality_management/doctype/quality_goal_objective/quality_goal_objective.py
+++ b/erpnext/quality_management/doctype/quality_goal_objective/quality_goal_objective.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityGoalObjective(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py b/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py
index 9e453ebfc2e..0ac0484399e 100644
--- a/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py
+++ b/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class QualityMeeting(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py b/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py
index 6bf4c179c6b..e57256d2896 100644
--- a/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py
+++ b/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py
@@ -3,9 +3,9 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestQualityMeeting(unittest.TestCase):
# nothing to test
pass
diff --git a/erpnext/quality_management/doctype/quality_meeting_agenda/quality_meeting_agenda.py b/erpnext/quality_management/doctype/quality_meeting_agenda/quality_meeting_agenda.py
index 5d77975d74c..5e4d9ff37a7 100644
--- a/erpnext/quality_management/doctype/quality_meeting_agenda/quality_meeting_agenda.py
+++ b/erpnext/quality_management/doctype/quality_meeting_agenda/quality_meeting_agenda.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityMeetingAgenda(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_meeting_agenda/test_quality_meeting_agenda.py b/erpnext/quality_management/doctype/quality_meeting_agenda/test_quality_meeting_agenda.py
index 4750cc1f7af..8744d275ed8 100644
--- a/erpnext/quality_management/doctype/quality_meeting_agenda/test_quality_meeting_agenda.py
+++ b/erpnext/quality_management/doctype/quality_meeting_agenda/test_quality_meeting_agenda.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestQualityMeetingAgenda(unittest.TestCase):
pass
diff --git a/erpnext/quality_management/doctype/quality_meeting_minutes/quality_meeting_minutes.py b/erpnext/quality_management/doctype/quality_meeting_minutes/quality_meeting_minutes.py
index 47b2c95bd9e..e3d061b36ca 100644
--- a/erpnext/quality_management/doctype/quality_meeting_minutes/quality_meeting_minutes.py
+++ b/erpnext/quality_management/doctype/quality_meeting_minutes/quality_meeting_minutes.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityMeetingMinutes(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
index 117db0012ba..56293c98e09 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils.nestedset import NestedSet, rebuild_tree
from frappe import _
+from frappe.utils.nestedset import NestedSet
+
class QualityProcedure(NestedSet):
nsm_parent_field = 'parent_quality_procedure'
diff --git a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
index 4fa7734bc68..b064011bf6c 100644
--- a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
+++ b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
@@ -3,11 +3,13 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
from .quality_procedure import add_node
+
class TestQualityProcedure(unittest.TestCase):
def test_add_node(self):
try:
diff --git a/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.py b/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.py
index 0d9a286052d..e281294643d 100644
--- a/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.py
+++ b/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityProcedureProcess(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_review/quality_review.py b/erpnext/quality_management/doctype/quality_review/quality_review.py
index 34cc890e219..b766623510a 100644
--- a/erpnext/quality_management/doctype/quality_review/quality_review.py
+++ b/erpnext/quality_management/doctype/quality_review/quality_review.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class QualityReview(Document):
def validate(self):
# fetch targets from goal
diff --git a/erpnext/quality_management/doctype/quality_review/test_quality_review.py b/erpnext/quality_management/doctype/quality_review/test_quality_review.py
index 161ecd01ef1..2f28ddac45e 100644
--- a/erpnext/quality_management/doctype/quality_review/test_quality_review.py
+++ b/erpnext/quality_management/doctype/quality_review/test_quality_review.py
@@ -3,12 +3,14 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
from ..quality_goal.test_quality_goal import get_quality_goal
from .quality_review import review
+
class TestQualityReview(unittest.TestCase):
def test_review_creation(self):
quality_goal = get_quality_goal()
diff --git a/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.py b/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.py
index 3092a1e9979..23b11e87e6a 100644
--- a/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.py
+++ b/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityReviewObjective(Document):
pass
diff --git a/erpnext/regional/__init__.py b/erpnext/regional/__init__.py
index faa59129a5a..45a689efa8b 100644
--- a/erpnext/regional/__init__.py
+++ b/erpnext/regional/__init__.py
@@ -2,10 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
from erpnext import get_region
+
def check_deletion_permission(doc, method):
region = get_region(doc.company)
if region in ["Nepal", "France"] and doc.docstatus != 0:
diff --git a/erpnext/regional/address_template/setup.py b/erpnext/regional/address_template/setup.py
index 1b4087d77ba..0f9a1b19f53 100644
--- a/erpnext/regional/address_template/setup.py
+++ b/erpnext/regional/address_template/setup.py
@@ -1,7 +1,9 @@
"""Import Address Templates from ./templates directory."""
import os
+
import frappe
+
def set_up_address_templates(default_country=None):
for country, html in get_address_templates():
is_default = 1 if country == default_country else 0
diff --git a/erpnext/regional/address_template/test_regional_address_template.py b/erpnext/regional/address_template/test_regional_address_template.py
index 8a05ea26f45..2880d6253f9 100644
--- a/erpnext/regional/address_template/test_regional_address_template.py
+++ b/erpnext/regional/address_template/test_regional_address_template.py
@@ -1,9 +1,11 @@
from __future__ import unicode_literals
+
from unittest import TestCase
import frappe
-from erpnext.regional.address_template.setup import get_address_templates
-from erpnext.regional.address_template.setup import update_address_template
+
+from erpnext.regional.address_template.setup import get_address_templates, update_address_template
+
def ensure_country(country):
if frappe.db.exists("Country", country):
diff --git a/erpnext/regional/doctype/datev_settings/datev_settings.py b/erpnext/regional/doctype/datev_settings/datev_settings.py
index cff5bba58fd..0d2d9eb4b47 100644
--- a/erpnext/regional/doctype/datev_settings/datev_settings.py
+++ b/erpnext/regional/doctype/datev_settings/datev_settings.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class DATEVSettings(Document):
pass
diff --git a/erpnext/regional/doctype/datev_settings/test_datev_settings.py b/erpnext/regional/doctype/datev_settings/test_datev_settings.py
index 0271329f4d2..73412f755d7 100644
--- a/erpnext/regional/doctype/datev_settings/test_datev_settings.py
+++ b/erpnext/regional/doctype/datev_settings/test_datev_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestDATEVSettings(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py
index 9150bdd9260..38fe3089412 100644
--- a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py
+++ b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class EInvoiceRequestLog(Document):
pass
diff --git a/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py b/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
index c84e9a249bd..091cc88e454 100644
--- a/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
+++ b/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestEInvoiceRequestLog(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
index 4f6b3eca7a6..70ec2ed0679 100644
--- a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
+++ b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
@@ -7,6 +7,7 @@ import frappe
from frappe import _
from frappe.model.document import Document
+
class EInvoiceSettings(Document):
def validate(self):
if self.enable and not self.credentials:
diff --git a/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py b/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
index a11ce63ee6c..10770deb0ee 100644
--- a/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
+++ b/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestEInvoiceSettings(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py b/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py
index 056c54f069d..a0fe399f110 100644
--- a/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py
+++ b/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class EInvoiceUser(Document):
pass
diff --git a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py
index 4791dc26753..0704de8387f 100644
--- a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py
+++ b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class GSTHSNCode(Document):
pass
diff --git a/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.js b/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.js
deleted file mode 100644
index 24c5fd355ff..00000000000
--- a/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: GST HSN Code", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new GST HSN Code
- () => frappe.tests.make('GST HSN Code', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.py b/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.py
index ed54f207139..1a90e6d711c 100644
--- a/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.py
+++ b/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestGSTHSNCode(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.py b/erpnext/regional/doctype/gst_settings/gst_settings.py
index af3d92e59a7..7b27fb6c5bc 100644
--- a/erpnext/regional/doctype/gst_settings/gst_settings.py
+++ b/erpnext/regional/doctype/gst_settings/gst_settings.py
@@ -3,11 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, os
+
+import os
+
+import frappe
from frappe import _
-from frappe.utils import get_url, nowdate, date_diff
-from frappe.model.document import Document
from frappe.contacts.doctype.contact.contact import get_default_contact
+from frappe.model.document import Document
+from frappe.utils import date_diff, get_url, nowdate
+
class EmailMissing(frappe.ValidationError): pass
diff --git a/erpnext/regional/doctype/gst_settings/test_gst_settings.js b/erpnext/regional/doctype/gst_settings/test_gst_settings.js
deleted file mode 100644
index 00fcca6f326..00000000000
--- a/erpnext/regional/doctype/gst_settings/test_gst_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: GST Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new GST Settings
- () => frappe.tests.make('GST Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/regional/doctype/gst_settings/test_gst_settings.py b/erpnext/regional/doctype/gst_settings/test_gst_settings.py
index d118dee6177..836d3a88c33 100644
--- a/erpnext/regional/doctype/gst_settings/test_gst_settings.py
+++ b/erpnext/regional/doctype/gst_settings/test_gst_settings.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestGSTSettings(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
index 0ee5b097b54..d8ce3197395 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
@@ -3,15 +3,19 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import os
+
import json
+import os
+
import frappe
-from six import iteritems
from frappe import _
from frappe.model.document import Document
-from frappe.utils import flt, cstr
+from frappe.utils import cstr, flt
+from six import iteritems
+
from erpnext.regional.india import state_numbers
+
class GSTR3BReport(Document):
def validate(self):
self.get_data()
diff --git a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
index 065f80d610a..115f9b88165 100644
--- a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
@@ -3,13 +3,15 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
-import unittest
-from frappe.utils import getdate
-from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
-from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
-from erpnext.stock.doctype.item.test_item import make_item
import json
+import unittest
+
+import frappe
+from frappe.utils import getdate
+
+from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+from erpnext.stock.doctype.item.test_item import make_item
test_dependencies = ["Territory", "Customer Group", "Supplier Group", "Item"]
diff --git a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py
index 00300539e9a..76cb621f541 100644
--- a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py
+++ b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py
@@ -3,21 +3,21 @@
from __future__ import unicode_literals
-from decimal import Decimal
-import json
import re
-import traceback
import zipfile
-import frappe, erpnext
+
+import dateutil
+import frappe
+from bs4 import BeautifulSoup as bs
from frappe import _
from frappe.model.document import Document
-from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+from frappe.utils import flt, get_datetime_str, today
from frappe.utils.data import format_datetime
-from bs4 import BeautifulSoup as bs
-from frappe.utils import cint, flt, today, nowdate, add_days, get_files_path, get_datetime_str
-import dateutil
from frappe.utils.file_manager import save_file
+import erpnext
+
+
class ImportSupplierInvoice(Document):
def validate(self):
if not frappe.db.get_value("Stock Settings", fieldname="stock_uom"):
diff --git a/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py b/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py
index d1caf77fc2c..4be4c3a22f9 100644
--- a/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py
+++ b/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestImportSupplierInvoice(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
index 656c3296e58..d8553f1d913 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import getdate, get_link_to_form
from frappe.model.document import Document
+from frappe.utils import get_link_to_form, getdate
+
from erpnext.accounts.utils import get_fiscal_year
+
class LowerDeductionCertificate(Document):
def validate(self):
self.validate_dates()
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py
index 7e950206fcc..54443c0206a 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py
+++ b/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestLowerDeductionCertificate(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/product_tax_category/__init__.py b/erpnext/regional/doctype/product_tax_category/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/regional/doctype/product_tax_category/product_tax_category.js b/erpnext/regional/doctype/product_tax_category/product_tax_category.js
new file mode 100644
index 00000000000..9f8e7950156
--- /dev/null
+++ b/erpnext/regional/doctype/product_tax_category/product_tax_category.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Product Tax Category', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/regional/doctype/product_tax_category/product_tax_category.json b/erpnext/regional/doctype/product_tax_category/product_tax_category.json
new file mode 100644
index 00000000000..147cb34425d
--- /dev/null
+++ b/erpnext/regional/doctype/product_tax_category/product_tax_category.json
@@ -0,0 +1,70 @@
+{
+ "actions": [],
+ "autoname": "field:product_tax_code",
+ "creation": "2021-08-23 12:33:37.910225",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "product_tax_code",
+ "column_break_2",
+ "category_name",
+ "section_break_4",
+ "description"
+ ],
+ "fields": [
+ {
+ "fieldname": "product_tax_code",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Product Tax Code",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Description"
+ },
+ {
+ "fieldname": "category_name",
+ "fieldtype": "Data",
+ "label": "Category Name",
+ "length": 255
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-08-24 09:10:25.313642",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "Product Tax Category",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "category_name",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/product_tax_category/product_tax_category.py b/erpnext/regional/doctype/product_tax_category/product_tax_category.py
new file mode 100644
index 00000000000..b6be9e0920b
--- /dev/null
+++ b/erpnext/regional/doctype/product_tax_category/product_tax_category.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class ProductTaxCategory(Document):
+ pass
diff --git a/erpnext/regional/doctype/product_tax_category/test_product_tax_category.py b/erpnext/regional/doctype/product_tax_category/test_product_tax_category.py
new file mode 100644
index 00000000000..2668f2391af
--- /dev/null
+++ b/erpnext/regional/doctype/product_tax_category/test_product_tax_category.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+import unittest
+
+
+class TestProductTaxCategory(unittest.TestCase):
+ pass
diff --git a/erpnext/regional/doctype/south_africa_vat_settings/south_africa_vat_settings.py b/erpnext/regional/doctype/south_africa_vat_settings/south_africa_vat_settings.py
index d74154bfe78..4c3e8a78e9d 100644
--- a/erpnext/regional/doctype/south_africa_vat_settings/south_africa_vat_settings.py
+++ b/erpnext/regional/doctype/south_africa_vat_settings/south_africa_vat_settings.py
@@ -4,5 +4,6 @@
# import frappe
from frappe.model.document import Document
+
class SouthAfricaVATSettings(Document):
pass
diff --git a/erpnext/regional/doctype/south_africa_vat_settings/test_south_africa_vat_settings.py b/erpnext/regional/doctype/south_africa_vat_settings/test_south_africa_vat_settings.py
index 1c36652ad6e..0f19f25f88d 100644
--- a/erpnext/regional/doctype/south_africa_vat_settings/test_south_africa_vat_settings.py
+++ b/erpnext/regional/doctype/south_africa_vat_settings/test_south_africa_vat_settings.py
@@ -4,5 +4,6 @@
# import frappe
import unittest
+
class TestSouthAfricaVATSettings(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py
index 41a0f1193bc..64b2ec5646c 100644
--- a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.model.document import Document
-from frappe.utils import getdate, flt, get_link_to_form
-from erpnext.accounts.utils import get_fiscal_year
from frappe.contacts.doctype.address.address import get_company_address
+from frappe.model.document import Document
+from frappe.utils import flt, get_link_to_form, getdate
+
+from erpnext.accounts.utils import get_fiscal_year
+
class TaxExemption80GCertificate(Document):
def validate(self):
diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py b/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py
index 41b42036687..74e9ced3941 100644
--- a/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py
@@ -3,14 +3,21 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
from frappe.utils import getdate
+
from erpnext.accounts.utils import get_fiscal_year
-from erpnext.non_profit.doctype.donation.test_donation import create_donor, create_mode_of_payment, create_donor_type
from erpnext.non_profit.doctype.donation.donation import create_donation
-from erpnext.non_profit.doctype.membership.test_membership import setup_membership, make_membership
+from erpnext.non_profit.doctype.donation.test_donation import (
+ create_donor,
+ create_donor_type,
+ create_mode_of_payment,
+)
from erpnext.non_profit.doctype.member.member import create_member
+from erpnext.non_profit.doctype.membership.test_membership import make_membership, setup_membership
+
class TestTaxExemption80GCertificate(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py
index bdad798d980..76d8912b004 100644
--- a/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class TaxExemption80GCertificateDetail(Document):
pass
diff --git a/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py
index 80d6b3a5f1f..a1b27d7e3d3 100644
--- a/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py
+++ b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class UAEVATAccount(Document):
pass
diff --git a/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py b/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py
index b88439f9b85..cec30e61cef 100644
--- a/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py
+++ b/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestUAEVATSettings(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py
index 20dc604510b..1bf37dd499d 100644
--- a/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py
+++ b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class UAEVATSettings(Document):
pass
diff --git a/erpnext/regional/france/setup.py b/erpnext/regional/france/setup.py
index db6419e9462..3e3a9f6e56a 100644
--- a/erpnext/regional/france/setup.py
+++ b/erpnext/regional/france/setup.py
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
def setup(company=None, patch=True):
make_custom_fields()
add_custom_roles_for_reports()
diff --git a/erpnext/regional/france/utils.py b/erpnext/regional/france/utils.py
index 424615dbbc0..63c5a1f583b 100644
--- a/erpnext/regional/france/utils.py
+++ b/erpnext/regional/france/utils.py
@@ -2,7 +2,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
# don't remove this function it is used in tests
def test_method():
diff --git a/erpnext/regional/germany/setup.py b/erpnext/regional/germany/setup.py
index c1fa6e492d1..35d14135ba5 100644
--- a/erpnext/regional/germany/setup.py
+++ b/erpnext/regional/germany/setup.py
@@ -1,4 +1,4 @@
-import os
+
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
diff --git a/erpnext/regional/germany/utils/datev/datev_csv.py b/erpnext/regional/germany/utils/datev/datev_csv.py
index c5c2bc41f4d..9d1fabbada7 100644
--- a/erpnext/regional/germany/utils/datev/datev_csv.py
+++ b/erpnext/regional/germany/utils/datev/datev_csv.py
@@ -4,12 +4,12 @@ from __future__ import unicode_literals
import datetime
import zipfile
from csv import QUOTE_NONNUMERIC
-from six import BytesIO
-import six
import frappe
import pandas as pd
from frappe import _
+from six import BytesIO
+
from .datev_constants import DataCategory
diff --git a/erpnext/regional/india/__init__.py b/erpnext/regional/india/__init__.py
index faeb36fc693..5c4d30881d1 100644
--- a/erpnext/regional/india/__init__.py
+++ b/erpnext/regional/india/__init__.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
from six import iteritems
states = [
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index fe4c172e237..19699243f9e 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -3,24 +3,39 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
+import base64
+import io
+import json
import os
import re
-import jwt
import sys
-import json
-import base64
-import frappe
-import six
import traceback
-import io
+
+import frappe
+import jwt
+import six
from frappe import _, bold
-from pyqrcode import create as qrcreate
-from frappe.utils.background_jobs import enqueue
-from frappe.utils.scheduler import is_scheduler_inactive
from frappe.core.page.background_jobs.background_jobs import get_info
-from frappe.integrations.utils import make_post_request, make_get_request
+from frappe.integrations.utils import make_get_request, make_post_request
+from frappe.utils.background_jobs import enqueue
+from frappe.utils.data import (
+ add_to_date,
+ cint,
+ cstr,
+ flt,
+ format_date,
+ get_link_to_form,
+ getdate,
+ now_datetime,
+ time_diff_in_hours,
+ time_diff_in_seconds,
+)
+from frappe.utils.scheduler import is_scheduler_inactive
+from pyqrcode import create as qrcreate
+
from erpnext.regional.india.utils import get_gst_accounts, get_place_of_supply
-from frappe.utils.data import cstr, cint, format_date, flt, time_diff_in_seconds, now_datetime, add_to_date, get_link_to_form, getdate, time_diff_in_hours
+
@frappe.whitelist()
def validate_eligibility(doc):
@@ -483,7 +498,7 @@ def log_error(data=None):
"Data:", data, seperator,
"Exception:", err_tb
])
- frappe.log_error(title=_('E Invoice Request Failed'), message=message)
+ return frappe.log_error(title=_('E Invoice Request Failed'), message=message)
def santize_einvoice_fields(einvoice):
int_fields = ["Pin","Distance","CrDay"]
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 2d6b9133900..03b5c8ad5f9 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -3,14 +3,19 @@
from __future__ import unicode_literals
-import frappe, os, json
+import json
+import os
+
+import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
from frappe.permissions import add_permission, update_permission_property
-from erpnext.regional.india import states
-from erpnext.accounts.utils import get_fiscal_year, FiscalYearError
from frappe.utils import today
+from erpnext.accounts.utils import FiscalYearError, get_fiscal_year
+from erpnext.regional.india import states
+
+
def setup(company=None, patch=True):
# Company independent fixtures should be called only once at the first company setup
if frappe.db.count('Company', {'country': 'India'}) <=1:
@@ -492,6 +497,26 @@ def make_custom_fields(update=True):
hidden=1, insert_after='einvoice_status', no_copy=1, print_hide=1, read_only=1)
]
+ payment_entry_fields = [
+ dict(fieldname='gst_section', label='GST Details', fieldtype='Section Break', insert_after='deductions',
+ print_hide=1, collapsible=1),
+ dict(fieldname='company_address', label='Company Address', fieldtype='Link', insert_after='gst_section',
+ print_hide=1, options='Address'),
+ dict(fieldname='company_gstin', label='Company GSTIN',
+ fieldtype='Data', insert_after='company_address',
+ fetch_from='company_address.gstin', print_hide=1, read_only=1),
+ dict(fieldname='place_of_supply', label='Place of Supply',
+ fieldtype='Data', insert_after='company_gstin',
+ print_hide=1, read_only=1),
+ dict(fieldname='gst_column_break', fieldtype='Column Break',
+ insert_after='place_of_supply'),
+ dict(fieldname='customer_address', label='Customer Address', fieldtype='Link', insert_after='gst_column_break',
+ print_hide=1, options='Address', depends_on = 'eval:doc.party_type == "Customer"'),
+ dict(fieldname='customer_gstin', label='Customer GSTIN',
+ fieldtype='Data', insert_after='customer_address',
+ fetch_from='customer_address.gstin', print_hide=1, read_only=1)
+ ]
+
custom_fields = {
'Address': [
dict(fieldname='gstin', label='Party GSTIN', fieldtype='Data',
@@ -506,6 +531,7 @@ def make_custom_fields(update=True):
'Purchase Receipt': purchase_invoice_gst_fields,
'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields + si_einvoice_fields,
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields + delivery_note_gst_category,
+ 'Payment Entry': payment_entry_fields,
'Journal Entry': journal_entry_fields,
'Sales Order': sales_invoice_gst_fields,
'Tax Category': inter_state_gst_field,
@@ -777,11 +803,11 @@ def set_tax_withholding_category(company):
accounts = [dict(company=company, account=tds_account)]
try:
- fiscal_year = get_fiscal_year(today(), verbose=0, company=company)[0]
+ fiscal_year_details = get_fiscal_year(today(), verbose=0, company=company)
except FiscalYearError:
pass
- docs = get_tds_details(accounts, fiscal_year)
+ docs = get_tds_details(accounts, fiscal_year_details)
for d in docs:
if not frappe.db.exists("Tax Withholding Category", d.get("name")):
@@ -796,9 +822,10 @@ def set_tax_withholding_category(company):
if accounts:
doc.append("accounts", accounts[0])
- if fiscal_year:
+ if fiscal_year_details:
# if fiscal year don't match with any of the already entered data, append rate row
- fy_exist = [k for k in doc.get('rates') if k.get('fiscal_year')==fiscal_year]
+ fy_exist = [k for k in doc.get('rates') if k.get('from_date') <= fiscal_year_details[1] \
+ and k.get('to_date') >= fiscal_year_details[2]]
if not fy_exist:
doc.append("rates", d.get('rates')[0])
@@ -821,149 +848,149 @@ def set_tds_account(docs, company):
}
])
-def get_tds_details(accounts, fiscal_year):
+def get_tds_details(accounts, fiscal_year_details):
# bootstrap default tax withholding sections
return [
dict(name="TDS - 194C - Company",
category_name="Payment to Contractors (Single / Aggregate)",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 2,
- "single_threshold": 30000, "cumulative_threshold": 100000}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 2, "single_threshold": 30000, "cumulative_threshold": 100000}]),
dict(name="TDS - 194C - Individual",
category_name="Payment to Contractors (Single / Aggregate)",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 1,
- "single_threshold": 30000, "cumulative_threshold": 100000}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 1, "single_threshold": 30000, "cumulative_threshold": 100000}]),
dict(name="TDS - 194C - No PAN / Invalid PAN",
category_name="Payment to Contractors (Single / Aggregate)",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 30000, "cumulative_threshold": 100000}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 30000, "cumulative_threshold": 100000}]),
dict(name="TDS - 194D - Company",
category_name="Insurance Commission",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 5,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194D - Company Assessee",
category_name="Insurance Commission",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194D - Individual",
category_name="Insurance Commission",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 5,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194D - No PAN / Invalid PAN",
category_name="Insurance Commission",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194DA - Company",
category_name="Non-exempt payments made under a life insurance policy",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 1,
- "single_threshold": 100000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 1, "single_threshold": 100000, "cumulative_threshold": 0}]),
dict(name="TDS - 194DA - Individual",
category_name="Non-exempt payments made under a life insurance policy",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 1,
- "single_threshold": 100000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 1, "single_threshold": 100000, "cumulative_threshold": 0}]),
dict(name="TDS - 194DA - No PAN / Invalid PAN",
category_name="Non-exempt payments made under a life insurance policy",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 100000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 100000, "cumulative_threshold": 0}]),
dict(name="TDS - 194H - Company",
category_name="Commission / Brokerage",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 5,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194H - Individual",
category_name="Commission / Brokerage",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 5,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194H - No PAN / Invalid PAN",
category_name="Commission / Brokerage",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194I - Rent - Company",
category_name="Rent",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 180000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 180000, "cumulative_threshold": 0}]),
dict(name="TDS - 194I - Rent - Individual",
category_name="Rent",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 180000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 180000, "cumulative_threshold": 0}]),
dict(name="TDS - 194I - Rent - No PAN / Invalid PAN",
category_name="Rent",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 180000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 180000, "cumulative_threshold": 0}]),
dict(name="TDS - 194I - Rent/Machinery - Company",
category_name="Rent-Plant / Machinery",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 2,
- "single_threshold": 180000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 2, "single_threshold": 180000, "cumulative_threshold": 0}]),
dict(name="TDS - 194I - Rent/Machinery - Individual",
category_name="Rent-Plant / Machinery",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 2,
- "single_threshold": 180000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 2, "single_threshold": 180000, "cumulative_threshold": 0}]),
dict(name="TDS - 194I - Rent/Machinery - No PAN / Invalid PAN",
category_name="Rent-Plant / Machinery",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 180000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 180000, "cumulative_threshold": 0}]),
dict(name="TDS - 194J - Professional Fees - Company",
category_name="Professional Fees",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 30000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 30000, "cumulative_threshold": 0}]),
dict(name="TDS - 194J - Professional Fees - Individual",
category_name="Professional Fees",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 30000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 30000, "cumulative_threshold": 0}]),
dict(name="TDS - 194J - Professional Fees - No PAN / Invalid PAN",
category_name="Professional Fees",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 30000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 30000, "cumulative_threshold": 0}]),
dict(name="TDS - 194J - Director Fees - Company",
category_name="Director Fees",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 0, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 0, "cumulative_threshold": 0}]),
dict(name="TDS - 194J - Director Fees - Individual",
category_name="Director Fees",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 0, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 0, "cumulative_threshold": 0}]),
dict(name="TDS - 194J - Director Fees - No PAN / Invalid PAN",
category_name="Director Fees",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 0, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 0, "cumulative_threshold": 0}]),
dict(name="TDS - 194 - Dividends - Company",
category_name="Dividends",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 2500, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 2500, "cumulative_threshold": 0}]),
dict(name="TDS - 194 - Dividends - Individual",
category_name="Dividends",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 2500, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 2500, "cumulative_threshold": 0}]),
dict(name="TDS - 194 - Dividends - No PAN / Invalid PAN",
category_name="Dividends",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 2500, "cumulative_threshold": 0}])
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 2500, "cumulative_threshold": 0}])
]
def create_gratuity_rule():
diff --git a/erpnext/regional/india/test_utils.py b/erpnext/regional/india/test_utils.py
index a16f56c704a..2c77c8d8aa8 100644
--- a/erpnext/regional/india/test_utils.py
+++ b/erpnext/regional/india/test_utils.py
@@ -1,8 +1,10 @@
from __future__ import unicode_literals
import unittest
-import frappe
from unittest.mock import patch
+
+import frappe
+
from erpnext.regional.india.utils import validate_document_name
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index ce5aa10902e..0feb2dbe536 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -1,19 +1,19 @@
from __future__ import unicode_literals
-import frappe, re, json
+
+import json
+import re
+
+import frappe
from frappe import _
-import erpnext
-from frappe.utils import cstr, flt, cint, date_diff, nowdate, round_based_on_smallest_currency_fraction, money_in_words, getdate
-from erpnext.regional.india import states, state_numbers
-from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount
+from frappe.model.utils import get_fetch_values
+from frappe.utils import cint, cstr, date_diff, flt, getdate, nowdate
+from six import string_types
+
from erpnext.controllers.accounts_controller import get_taxes_and_charges
+from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount
from erpnext.hr.utils import get_salary_assignment
from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
-from erpnext.regional.india import number_state_mapping
-from six import string_types
-from erpnext.accounts.general_ledger import make_gl_entries
-from erpnext.accounts.utils import get_account_currency
-from frappe.model.utils import get_fetch_values
-
+from erpnext.regional.india import number_state_mapping, state_numbers, states
GST_INVOICE_NUMBER_FORMAT = re.compile(r"^[a-zA-Z0-9\-/]+$") #alphanumeric and - /
GSTIN_FORMAT = re.compile("^[0-9]{2}[A-Z]{4}[0-9A-Z]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[1-9A-Z]{1}[0-9A-Z]{1}$")
@@ -767,6 +767,15 @@ def update_itc_availed_fields(doc, method):
if tax.account_head in gst_accounts.get('cess_account', []):
doc.itc_cess_amount += flt(tax.base_tax_amount_after_discount_amount)
+def update_place_of_supply(doc, method):
+ country = frappe.get_cached_value('Company', doc.company, 'country')
+ if country != 'India':
+ return
+
+ address = frappe.db.get_value("Address", doc.get('customer_address'), ["gst_state", "gst_state_number"], as_dict=1)
+ if address and address.gst_state and address.gst_state_number:
+ doc.place_of_supply = cstr(address.gst_state_number) + "-" + cstr(address.gst_state)
+
@frappe.whitelist()
def get_regional_round_off_accounts(company, account_list):
country = frappe.get_cached_value('Company', company, 'country')
diff --git a/erpnext/regional/italy/setup.py b/erpnext/regional/italy/setup.py
index 7db2f6b0f8d..291906af9cd 100644
--- a/erpnext/regional/italy/setup.py
+++ b/erpnext/regional/italy/setup.py
@@ -8,7 +8,14 @@ import frappe
from frappe import _
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.permissions import add_permission, update_permission_property
-from erpnext.regional.italy import fiscal_regimes, tax_exemption_reasons, mode_of_payment_codes, vat_collectability_options
+
+from erpnext.regional.italy import (
+ fiscal_regimes,
+ mode_of_payment_codes,
+ tax_exemption_reasons,
+ vat_collectability_options,
+)
+
def setup(company=None, patch=True):
make_custom_fields()
diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py
index ba1aeafc3e9..d6c7f1dbfa9 100644
--- a/erpnext/regional/italy/utils.py
+++ b/erpnext/regional/italy/utils.py
@@ -2,13 +2,14 @@ from __future__ import unicode_literals
import io
import json
+
import frappe
-from frappe.utils import flt, cstr
-from erpnext.controllers.taxes_and_totals import get_itemised_tax
from frappe import _
-from frappe.core.doctype.file.file import remove_file
+from frappe.utils import cstr, flt
+from frappe.utils.file_manager import remove_file
from six import string_types
-from frappe.desk.form.load import get_attachments
+
+from erpnext.controllers.taxes_and_totals import get_itemised_tax
from erpnext.regional.italy import state_codes
diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py
index 8f077e3de0b..dcabe368aa5 100644
--- a/erpnext/regional/report/datev/datev.py
+++ b/erpnext/regional/report/datev/datev.py
@@ -10,13 +10,18 @@ Provide a report and downloadable CSV according to the German DATEV format.
from __future__ import unicode_literals
import json
+
import frappe
+from frappe import _
from six import string_types
-from frappe import _
from erpnext.accounts.utils import get_fiscal_year
-from erpnext.regional.germany.utils.datev.datev_csv import zip_and_download, get_datev_csv
-from erpnext.regional.germany.utils.datev.datev_constants import Transactions, DebtorsCreditors, AccountNames
+from erpnext.regional.germany.utils.datev.datev_constants import (
+ AccountNames,
+ DebtorsCreditors,
+ Transactions,
+)
+from erpnext.regional.germany.utils.datev.datev_csv import get_datev_csv, zip_and_download
COLUMNS = [
{
@@ -200,7 +205,7 @@ def get_transactions(filters, as_dict=1):
def run(params_method, filters):
extra_fields, extra_joins, extra_filters = params_method(filters)
return run_query(filters, extra_fields, extra_joins, extra_filters, as_dict=as_dict)
-
+
def sort_by(row):
# "Belegdatum" is in the fifth column when list format is used
return row["Belegdatum" if as_dict else 5]
@@ -361,7 +366,7 @@ def run_query(filters, extra_fields, extra_joins, extra_filters, as_dict=1):
FROM `tabGL Entry` gl
/* Kontonummer */
- LEFT JOIN `tabAccount` acc
+ LEFT JOIN `tabAccount` acc
ON gl.account = acc.name
LEFT JOIN `tabParty Account` par
diff --git a/erpnext/regional/report/datev/test_datev.py b/erpnext/regional/report/datev/test_datev.py
index 59b878e94a5..b53889366f1 100644
--- a/erpnext/regional/report/datev/test_datev.py
+++ b/erpnext/regional/report/datev/test_datev.py
@@ -2,21 +2,27 @@
from __future__ import unicode_literals
import zipfile
-import frappe
-from six import BytesIO
from unittest import TestCase
-from frappe.utils import today, now_datetime, cstr
+
+import frappe
+from frappe.utils import cstr, now_datetime, today
+from six import BytesIO
+
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
-
-from erpnext.regional.report.datev.datev import validate
-from erpnext.regional.report.datev.datev import get_transactions
-from erpnext.regional.report.datev.datev import get_customers
-from erpnext.regional.report.datev.datev import get_suppliers
-from erpnext.regional.report.datev.datev import get_account_names
-from erpnext.regional.report.datev.datev import download_datev_csv
-
+from erpnext.regional.germany.utils.datev.datev_constants import (
+ AccountNames,
+ DebtorsCreditors,
+ Transactions,
+)
from erpnext.regional.germany.utils.datev.datev_csv import get_datev_csv, get_header
-from erpnext.regional.germany.utils.datev.datev_constants import Transactions, DebtorsCreditors, AccountNames
+from erpnext.regional.report.datev.datev import (
+ download_datev_csv,
+ get_account_names,
+ get_customers,
+ get_suppliers,
+ get_transactions,
+)
+
def make_company(company_name, abbr):
if not frappe.db.exists("Company", company_name):
diff --git a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
index 66ffceae539..a068a380776 100644
--- a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
+++ b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
validate_filters(filters)
diff --git a/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py
index 376ba3ee471..f4ce7a77ad9 100644
--- a/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py
+++ b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py
@@ -2,7 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from erpnext.accounts.report.sales_register.sales_register import _execute
+
def execute(filters=None):
return _execute(filters)
diff --git a/erpnext/regional/report/eway_bill/eway_bill.py b/erpnext/regional/report/eway_bill/eway_bill.py
index 4f777fcf7e3..c78084f7dff 100644
--- a/erpnext/regional/report/eway_bill/eway_bill.py
+++ b/erpnext/regional/report/eway_bill/eway_bill.py
@@ -2,12 +2,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
import re
+
+import frappe
from frappe import _
from frappe.utils import nowdate
+
def execute(filters=None):
if not filters: filters.setdefault('posting_date', [nowdate(), nowdate()])
columns, data = [], []
@@ -41,7 +44,7 @@ def get_data(filters):
}
# Regular expression set to remove all the special characters
- special_characters = "[$%^*()+\\[\]{};':\"\\|<>.?]"
+ special_characters = r"[$%^*()+\\[\]{};':\"\\|<>.?]"
for row in data:
set_defaults(row)
diff --git a/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py b/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py
index e903c9f00a4..9567916cd2a 100644
--- a/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py
+++ b/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py
@@ -2,11 +2,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import format_datetime
-from frappe import _
+
import re
+import frappe
+from frappe import _
+from frappe.utils import format_datetime
+
+
def execute(filters=None):
account_details = {}
for acc in frappe.db.sql("""select name, is_group from tabAccount""", as_dict=1):
@@ -116,7 +119,7 @@ def get_result_as_list(data, filters):
if d.get("voucher_no").startswith("{0}-".format(JournalCode)) or d.get("voucher_no").startswith("{0}/".format(JournalCode)):
EcritureNum = re.split("-|/", d.get("voucher_no"))[1]
else:
- EcritureNum = re.search("{0}(\d+)".format(JournalCode), d.get("voucher_no"), re.IGNORECASE).group(1)
+ EcritureNum = re.search(r"{0}(\d+)".format(JournalCode), d.get("voucher_no"), re.IGNORECASE).group(1)
EcritureDate = format_datetime(d.get("GlPostDate"), "yyyyMMdd")
diff --git a/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py b/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py
index b5948f9952d..092f72adf15 100644
--- a/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py
+++ b/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py
@@ -3,7 +3,10 @@
from __future__ import unicode_literals
-from erpnext.accounts.report.item_wise_purchase_register.item_wise_purchase_register import _execute
+from erpnext.accounts.report.item_wise_purchase_register.item_wise_purchase_register import (
+ _execute,
+)
+
def execute(filters=None):
return _execute(filters, additional_table_columns=[
diff --git a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py
index e13f509f475..44f623bfae9 100644
--- a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py
+++ b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import _execute
+
def execute(filters=None):
return _execute(filters, additional_table_columns=[
dict(fieldtype='Data', label='Customer GSTIN', fieldname="customer_gstin", width=120),
diff --git a/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py b/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py
index 12e9676b4ba..e9724441b17 100644
--- a/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py
+++ b/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
from erpnext.accounts.report.purchase_register.purchase_register import _execute
+
def execute(filters=None):
return _execute(filters, additional_table_columns=[
dict(fieldtype='Data', label='Supplier GSTIN', fieldname="supplier_gstin", width=120),
diff --git a/erpnext/regional/report/gst_sales_register/gst_sales_register.py b/erpnext/regional/report/gst_sales_register/gst_sales_register.py
index 075bd483cf0..6975af35854 100644
--- a/erpnext/regional/report/gst_sales_register/gst_sales_register.py
+++ b/erpnext/regional/report/gst_sales_register/gst_sales_register.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
from erpnext.accounts.report.sales_register.sales_register import _execute
+
def execute(filters=None):
return _execute(filters, additional_table_columns=[
dict(fieldtype='Data', label='Customer GSTIN', fieldname="customer_gstin", width=120),
diff --git a/erpnext/regional/report/gstr_1/gstr_1.js b/erpnext/regional/report/gstr_1/gstr_1.js
index 444f5dbb8ca..ef2bdb67980 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.js
+++ b/erpnext/regional/report/gstr_1/gstr_1.js
@@ -51,7 +51,9 @@ frappe.query_reports["GSTR-1"] = {
{ "value": "B2C Large", "label": __("B2C(Large) Invoices - 5A, 5B") },
{ "value": "B2C Small", "label": __("B2C(Small) Invoices - 7") },
{ "value": "CDNR-REG", "label": __("Credit/Debit Notes (Registered) - 9B") },
- { "value": "EXPORT", "label": __("Export Invoice - 6A") }
+ { "value": "CDNR-UNREG", "label": __("Credit/Debit Notes (Unregistered) - 9B") },
+ { "value": "EXPORT", "label": __("Export Invoice - 6A") },
+ { "value": "Advances", "label": __("Tax Liability (Advances Received) - 11A(1), 11A(2)") }
],
"default": "B2B"
}
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index 9d4f9206f50..23924c5fb66 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -2,14 +2,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, json
-from frappe import _
-from frappe.utils import flt, formatdate, now_datetime, getdate
+
+import json
from datetime import date
+
+import frappe
+from frappe import _
+from frappe.utils import flt, formatdate, getdate
from six import iteritems
-from erpnext.regional.doctype.gstr_3b_report.gstr_3b_report import get_period
+
from erpnext.regional.india.utils import get_gst_accounts
+
def execute(filters=None):
return Gstr1Report(filters).run()
@@ -50,63 +54,83 @@ class Gstr1Report(object):
self.get_invoice_items()
self.get_items_based_on_tax_rate()
self.invoice_fields = [d["fieldname"] for d in self.invoice_columns]
- self.get_data()
+
+ self.get_data()
return self.columns, self.data
def get_data(self):
if self.filters.get("type_of_business") in ("B2C Small", "B2C Large"):
self.get_b2c_data()
- else:
+ elif self.filters.get("type_of_business") == "Advances":
+ self.get_advance_data()
+ elif self.invoices:
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
invoice_details = self.invoices.get(inv)
for rate, items in items_based_on_rate.items():
row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
- if self.filters.get("type_of_business") == "CDNR-REG":
+ if self.filters.get("type_of_business") in ("CDNR-REG", "CDNR-UNREG"):
row.append("Y" if invoice_details.posting_date <= date(2017, 7, 1) else "N")
row.append("C" if invoice_details.is_return else "D")
if taxable_value:
self.data.append(row)
+ def get_advance_data(self):
+ advances_data = {}
+ advances = self.get_advance_entries()
+ for entry in advances:
+ # only consider IGST and SGST so as to avoid duplication of taxable amount
+ if entry.account_head in self.gst_accounts.igst_account or \
+ entry.account_head in self.gst_accounts.sgst_account:
+ advances_data.setdefault((entry.place_of_supply, entry.rate), [0.0, 0.0])
+ advances_data[(entry.place_of_supply, entry.rate)][0] += (entry.amount * 100 / entry.rate)
+ elif entry.account_head in self.gst_accounts.cess_account:
+ advances_data[(entry.place_of_supply, entry.rate)][1] += entry.amount
+
+ for key, value in advances_data.items():
+ row= [key[0], key[1], value[0], value[1]]
+ self.data.append(row)
+
def get_b2c_data(self):
b2cs_output = {}
- for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
- invoice_details = self.invoices.get(inv)
- for rate, items in items_based_on_rate.items():
- place_of_supply = invoice_details.get("place_of_supply")
- ecommerce_gstin = invoice_details.get("ecommerce_gstin")
+ if self.invoices:
+ for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
+ invoice_details = self.invoices.get(inv)
+ for rate, items in items_based_on_rate.items():
+ place_of_supply = invoice_details.get("place_of_supply")
+ ecommerce_gstin = invoice_details.get("ecommerce_gstin")
- b2cs_output.setdefault((rate, place_of_supply, ecommerce_gstin),{
- "place_of_supply": "",
- "ecommerce_gstin": "",
- "rate": "",
- "taxable_value": 0,
- "cess_amount": 0,
- "type": "",
- "invoice_number": invoice_details.get("invoice_number"),
- "posting_date": invoice_details.get("posting_date"),
- "invoice_value": invoice_details.get("base_grand_total"),
- })
+ b2cs_output.setdefault((rate, place_of_supply, ecommerce_gstin), {
+ "place_of_supply": "",
+ "ecommerce_gstin": "",
+ "rate": "",
+ "taxable_value": 0,
+ "cess_amount": 0,
+ "type": "",
+ "invoice_number": invoice_details.get("invoice_number"),
+ "posting_date": invoice_details.get("posting_date"),
+ "invoice_value": invoice_details.get("base_grand_total"),
+ })
- row = b2cs_output.get((rate, place_of_supply, ecommerce_gstin))
- row["place_of_supply"] = place_of_supply
- row["ecommerce_gstin"] = ecommerce_gstin
- row["rate"] = rate
- row["taxable_value"] += sum([abs(net_amount)
- for item_code, net_amount in self.invoice_items.get(inv).items() if item_code in items])
- row["cess_amount"] += flt(self.invoice_cess.get(inv), 2)
- row["type"] = "E" if ecommerce_gstin else "OE"
+ row = b2cs_output.get((rate, place_of_supply, ecommerce_gstin))
+ row["place_of_supply"] = place_of_supply
+ row["ecommerce_gstin"] = ecommerce_gstin
+ row["rate"] = rate
+ row["taxable_value"] += sum([abs(net_amount)
+ for item_code, net_amount in self.invoice_items.get(inv).items() if item_code in items])
+ row["cess_amount"] += flt(self.invoice_cess.get(inv), 2)
+ row["type"] = "E" if ecommerce_gstin else "OE"
- for key, value in iteritems(b2cs_output):
- self.data.append(value)
+ for key, value in iteritems(b2cs_output):
+ self.data.append(value)
def get_row_data_for_invoice(self, invoice, invoice_details, tax_rate, items):
row = []
for fieldname in self.invoice_fields:
- if self.filters.get("type_of_business") == "CDNR-REG" and fieldname == "invoice_value":
+ if self.filters.get("type_of_business") in ("CDNR-REG", "CDNR-UNREG") and fieldname == "invoice_value":
row.append(abs(invoice_details.base_rounded_total) or abs(invoice_details.base_grand_total))
elif fieldname == "invoice_value":
row.append(invoice_details.base_rounded_total or invoice_details.base_grand_total)
@@ -150,9 +174,10 @@ class Gstr1Report(object):
company_gstins = get_company_gstin_number(self.filters.get('company'), all_gstins=True)
- self.filters.update({
- 'company_gstins': company_gstins
- })
+ if company_gstins:
+ self.filters.update({
+ 'company_gstins': company_gstins
+ })
invoice_data = frappe.db.sql("""
select
@@ -167,6 +192,16 @@ class Gstr1Report(object):
for d in invoice_data:
self.invoices.setdefault(d.invoice_number, d)
+ def get_advance_entries(self):
+ return frappe.db.sql("""
+ SELECT SUM(a.base_tax_amount) as amount, a.account_head, a.rate, p.place_of_supply
+ FROM `tabPayment Entry` p, `tabAdvance Taxes and Charges` a
+ WHERE p.docstatus = 1
+ AND p.name = a.parent
+ AND posting_date between %s and %s
+ GROUP BY a.account_head, p.place_of_supply, a.rate
+ """, (self.filters.get('from_date'), self.filters.get('to_date')), as_dict=1)
+
def get_conditions(self):
conditions = ""
@@ -179,7 +214,7 @@ class Gstr1Report(object):
if self.filters.get("type_of_business") == "B2B":
- conditions += "AND IFNULL(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') AND is_return != 1"
+ conditions += "AND IFNULL(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') AND is_return != 1 AND is_debit_note !=1"
if self.filters.get("type_of_business") in ("B2C Large", "B2C Small"):
b2c_limit = frappe.db.get_single_value('GST Settings', 'b2c_limit')
@@ -188,7 +223,7 @@ class Gstr1Report(object):
if self.filters.get("type_of_business") == "B2C Large":
conditions += """ AND ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'')
- AND grand_total > {0} AND is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
+ AND grand_total > {0} AND is_return != 1 AND is_debit_note !=1 AND gst_category ='Unregistered' """.format(flt(b2c_limit))
elif self.filters.get("type_of_business") == "B2C Small":
conditions += """ AND (
@@ -198,6 +233,12 @@ class Gstr1Report(object):
elif self.filters.get("type_of_business") == "CDNR-REG":
conditions += """ AND (is_return = 1 OR is_debit_note = 1) AND IFNULL(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ')"""
+ elif self.filters.get("type_of_business") == "CDNR-UNREG":
+ b2c_limit = frappe.db.get_single_value('GST Settings', 'b2c_limit')
+ conditions += """ AND ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'')
+ AND (is_return = 1 OR is_debit_note = 1)
+ AND IFNULL(gst_category, '') in ('Unregistered', 'Overseas')"""
+
elif self.filters.get("type_of_business") == "EXPORT":
conditions += """ AND is_return !=1 and gst_category = 'Overseas' """
@@ -503,6 +544,84 @@ class Gstr1Report(object):
"width": 80
}
]
+ elif self.filters.get("type_of_business") == "CDNR-UNREG":
+ self.invoice_columns = [
+ {
+ "fieldname": "customer_name",
+ "label": "Receiver Name",
+ "fieldtype": "Data",
+ "width": 120
+ },
+ {
+ "fieldname": "return_against",
+ "label": "Issued Against",
+ "fieldtype": "Link",
+ "options": "Sales Invoice",
+ "width": 120
+ },
+ {
+ "fieldname": "posting_date",
+ "label": "Note Date",
+ "fieldtype": "Date",
+ "width": 120
+ },
+ {
+ "fieldname": "invoice_number",
+ "label": "Note Number",
+ "fieldtype": "Link",
+ "options": "Sales Invoice",
+ "width":120
+ },
+ {
+ "fieldname": "export_type",
+ "label": "Export Type",
+ "fieldtype": "Data",
+ "hidden": 1
+ },
+ {
+ "fieldname": "reason_for_issuing_document",
+ "label": "Reason For Issuing document",
+ "fieldtype": "Data",
+ "width": 140
+ },
+ {
+ "fieldname": "place_of_supply",
+ "label": "Place Of Supply",
+ "fieldtype": "Data",
+ "width": 120
+ },
+ {
+ "fieldname": "gst_category",
+ "label": "GST Category",
+ "fieldtype": "Data"
+ },
+ {
+ "fieldname": "invoice_value",
+ "label": "Invoice Value",
+ "fieldtype": "Currency",
+ "width": 120
+ }
+ ]
+ self.other_columns = [
+ {
+ "fieldname": "cess_amount",
+ "label": "Cess Amount",
+ "fieldtype": "Currency",
+ "width": 100
+ },
+ {
+ "fieldname": "pre_gst",
+ "label": "PRE GST",
+ "fieldtype": "Data",
+ "width": 80
+ },
+ {
+ "fieldname": "document_type",
+ "label": "Document Type",
+ "fieldtype": "Data",
+ "width": 80
+ }
+ ]
elif self.filters.get("type_of_business") == "B2C Small":
self.invoice_columns = [
{
@@ -578,6 +697,25 @@ class Gstr1Report(object):
"width": 120
}
]
+ elif self.filters.get("type_of_business") == "Advances":
+ self.invoice_columns = [
+ {
+ "fieldname": "place_of_supply",
+ "label": "Place Of Supply",
+ "fieldtype": "Data",
+ "width": 120
+ }
+ ]
+
+ self.other_columns = [
+ {
+ "fieldname": "cess_amount",
+ "label": "Cess Amount",
+ "fieldtype": "Currency",
+ "width": 100
+ }
+ ]
+
self.columns = self.invoice_columns + self.tax_columns + self.other_columns
@frappe.whitelist()
@@ -616,12 +754,29 @@ def get_json(filters, report_name, data):
out = get_export_json(res)
gst_json["exp"] = out
- elif filters["type_of_business"] == 'CDNR-REG':
+ elif filters["type_of_business"] == "CDNR-REG":
for item in report_data[:-1]:
res.setdefault(item["customer_gstin"], {}).setdefault(item["invoice_number"],[]).append(item)
out = get_cdnr_reg_json(res, gstin)
gst_json["cdnr"] = out
+ elif filters["type_of_business"] == "CDNR-UNREG":
+ for item in report_data[:-1]:
+ res.setdefault(item["invoice_number"],[]).append(item)
+
+ out = get_cdnr_unreg_json(res, gstin)
+ gst_json["cdnur"] = out
+
+ elif filters["type_of_business"] == "Advances":
+ for item in report_data[:-1]:
+ if not item.get("place_of_supply"):
+ frappe.throw(_("""{0} not entered in some entries.
+ Please update and try again""").format(frappe.bold("Place Of Supply")))
+
+ res.setdefault(item["place_of_supply"],[]).append(item)
+
+ out = get_advances_json(res, gstin)
+ gst_json["at"] = out
return {
'report_name': report_name,
@@ -701,6 +856,40 @@ def get_b2cs_json(data, gstin):
return out
+def get_advances_json(data, gstin):
+ company_state_number = gstin[0:2]
+ out = []
+ for place_of_supply, items in iteritems(data):
+ supply_type = "INTRA" if company_state_number == place_of_supply.split('-')[0] else "INTER"
+ row = {
+ "pos": place_of_supply.split('-')[0],
+ "itms": [],
+ "sply_ty": supply_type
+ }
+
+ for item in items:
+ itms = {
+ 'rt': item['rate'],
+ 'ad_amount': flt(item.get('taxable_value')),
+ 'csamt': flt(item.get('cess_amount'))
+ }
+
+ if supply_type == "INTRA":
+ itms.update({
+ "samt": flt((itms["ad_amount"] * itms["rt"]) / 100),
+ "camt": flt((itms["ad_amount"] * itms["rt"]) / 100),
+ "rt": itms["rt"] * 2
+ })
+ else:
+ itms.update({
+ "iamt": flt((itms["ad_amount"] * itms["rt"]) / 100)
+ })
+
+ row['itms'].append(itms)
+ out.append(row)
+
+ return out
+
def get_b2cl_json(res, gstin):
out = []
for pos in res:
@@ -780,6 +969,27 @@ def get_cdnr_reg_json(res, gstin):
return out
+def get_cdnr_unreg_json(res, gstin):
+ out = []
+
+ for invoice, items in iteritems(res):
+ inv_item = {
+ "nt_num": items[0]["invoice_number"],
+ "nt_dt": getdate(items[0]["posting_date"]).strftime('%d-%m-%Y'),
+ "val": abs(flt(items[0]["invoice_value"])),
+ "ntty": items[0]["document_type"],
+ "pos": "%02d" % int(items[0]["place_of_supply"].split('-')[0]),
+ "typ": get_invoice_type_for_cdnrur(items[0])
+ }
+
+ inv_item["itms"] = []
+ for item in items:
+ inv_item["itms"].append(get_rate_and_tax_details(item, gstin))
+
+ out.append(inv_item)
+
+ return out
+
def get_invoice_type_for_cdnr(row):
if row.get('gst_category') == 'SEZ':
if row.get('export_type') == 'WPAY':
@@ -787,12 +997,23 @@ def get_invoice_type_for_cdnr(row):
else:
invoice_type = 'SEWOP'
elif row.get('gst_category') == 'Deemed Export':
- row.invoice_type = 'DE'
+ invoice_type = 'DE'
elif row.get('gst_category') == 'Registered Regular':
invoice_type = 'R'
return invoice_type
+def get_invoice_type_for_cdnrur(row):
+ if row.get('gst_category') == 'Overseas':
+ if row.get('export_type') == 'WPAY':
+ invoice_type = 'EXPWP'
+ else:
+ invoice_type = 'EXPWOP'
+ elif row.get('gst_category') == 'Unregistered':
+ invoice_type = 'B2CL'
+
+ return invoice_type
+
def get_basic_invoice_detail(row):
return {
"inum": row["invoice_number"],
@@ -831,8 +1052,9 @@ def get_company_gstin_number(company, address=None, all_gstins=False):
["Dynamic Link", "link_doctype", "=", "Company"],
["Dynamic Link", "link_name", "=", company],
["Dynamic Link", "parenttype", "=", "Address"],
+ ["gstin", "!=", '']
]
- gstin = frappe.get_all("Address", filters=filters, pluck="gstin")
+ gstin = frappe.get_all("Address", filters=filters, pluck="gstin", order_by="is_primary_address desc")
if gstin and not all_gstins:
gstin = gstin[0]
diff --git a/erpnext/regional/report/gstr_2/gstr_2.py b/erpnext/regional/report/gstr_2/gstr_2.py
index 616c2b853df..5e44955ce30 100644
--- a/erpnext/regional/report/gstr_2/gstr_2.py
+++ b/erpnext/regional/report/gstr_2/gstr_2.py
@@ -2,10 +2,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from datetime import date
+
+import frappe
+
from erpnext.regional.report.gstr_1.gstr_1 import Gstr1Report
+
def execute(filters=None):
return Gstr2Report(filters).run()
diff --git a/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py
index 1adddbdae57..7a938c7e0f2 100644
--- a/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py
+++ b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py
@@ -2,16 +2,20 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-from frappe import _
-from frappe.utils import flt, getdate, cstr
-from frappe.model.meta import get_field_precision
-from frappe.utils.xlsxutils import handle_html
-from six import iteritems
+
import json
+
+import frappe
+from frappe import _
+from frappe.model.meta import get_field_precision
+from frappe.utils import cstr, flt, getdate
+from six import iteritems
+
+import erpnext
from erpnext.regional.india.utils import get_gst_accounts
from erpnext.regional.report.gstr_1.gstr_1 import get_company_gstin_number
+
def execute(filters=None):
return _execute(filters)
diff --git a/erpnext/regional/report/irs_1099/irs_1099.py b/erpnext/regional/report/irs_1099/irs_1099.py
index f67d622fdf8..b1a5d109621 100644
--- a/erpnext/regional/report/irs_1099/irs_1099.py
+++ b/erpnext/regional/report/irs_1099/irs_1099.py
@@ -3,16 +3,16 @@
import json
-from PyPDF2 import PdfFileWriter
-
import frappe
-from erpnext.accounts.utils import get_fiscal_year
from frappe import _
from frappe.utils import cstr, nowdate
from frappe.utils.data import fmt_money
from frappe.utils.jinja import render_template
from frappe.utils.pdf import get_pdf
from frappe.utils.print_format import read_multi_pdf
+from PyPDF2 import PdfFileWriter
+
+from erpnext.accounts.utils import get_fiscal_year
IRS_1099_FORMS_FILE_EXTENSION = ".pdf"
diff --git a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py
index 54808e59e1a..5300b928925 100644
--- a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py
+++ b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py
@@ -2,9 +2,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from erpnext.regional.report.provident_fund_deductions.provident_fund_deductions import get_conditions
+
+from erpnext.regional.report.provident_fund_deductions.provident_fund_deductions import (
+ get_conditions,
+)
+
def execute(filters=None):
data = get_data(filters)
diff --git a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py
index 82423f005cc..ae5d6b90b4e 100644
--- a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py
+++ b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import getdate
from frappe import _
+from frappe.utils import getdate
+
def execute(filters=None):
data = get_data(filters)
diff --git a/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py b/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py
index daa69768c57..e19aeaa0eff 100644
--- a/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py
+++ b/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py
@@ -1,21 +1,23 @@
# coding=utf-8
from __future__ import unicode_literals
-import erpnext
-import frappe
from unittest import TestCase
-from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+
+import frappe
+
+import erpnext
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
-from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse_account
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.regional.report.uae_vat_201.uae_vat_201 import (
- get_total_emiratewise,
- get_tourist_tax_return_total,
- get_tourist_tax_return_tax,
- get_zero_rated_total,
get_exempt_total,
- get_standard_rated_expenses_total,
get_standard_rated_expenses_tax,
+ get_standard_rated_expenses_total,
+ get_total_emiratewise,
+ get_tourist_tax_return_tax,
+ get_tourist_tax_return_total,
+ get_zero_rated_total,
)
+from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse_account
test_dependencies = ["Territory", "Customer Group", "Supplier Group", "Item"]
diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.py b/erpnext/regional/report/uae_vat_201/uae_vat_201.py
index b0614238ba0..f4c049d1623 100644
--- a/erpnext/regional/report/uae_vat_201/uae_vat_201.py
+++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
columns = get_columns()
data, emirates, amounts_by_emirate = get_data(filters)
diff --git a/erpnext/regional/report/vat_audit_report/test_vat_audit_report.py b/erpnext/regional/report/vat_audit_report/test_vat_audit_report.py
index dea17a66fda..77beff36ecd 100644
--- a/erpnext/regional/report/vat_audit_report/test_vat_audit_report.py
+++ b/erpnext/regional/report/vat_audit_report/test_vat_audit_report.py
@@ -2,16 +2,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from unittest import TestCase
+
+import frappe
from frappe.utils import today
from erpnext.accounts.doctype.account.test_account import create_account
-from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
-
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.regional.report.vat_audit_report.vat_audit_report import execute
+
class TestVATAuditReport(TestCase):
def setUp(self):
frappe.set_user("Administrator")
diff --git a/erpnext/regional/report/vat_audit_report/vat_audit_report.py b/erpnext/regional/report/vat_audit_report/vat_audit_report.py
index ebf297113d7..3637bcaf439 100644
--- a/erpnext/regional/report/vat_audit_report/vat_audit_report.py
+++ b/erpnext/regional/report/vat_audit_report/vat_audit_report.py
@@ -2,11 +2,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
+
+import frappe
from frappe import _
from frappe.utils import formatdate, get_link_to_form
+
def execute(filters=None):
return VATAuditReport(filters).run()
@@ -190,7 +193,7 @@ class VATAuditReport(object):
row["posting_date"] = formatdate(inv_data.get("posting_date"), "dd-mm-yyyy")
row["voucher_type"] = doctype
row["voucher_no"] = inv
- row["party_type"] = "Customer" if doctype == "Sales Invoice" else "Supplier"
+ row["party_type"] = "Customer" if doctype == "Sales Invoice" else "Supplier"
row["party"] = inv_data.get("party")
row["remarks"] = inv_data.get("remarks")
row["gross_amount"]= item_details[0].get("gross_amount")
diff --git a/erpnext/regional/saudi_arabia/setup.py b/erpnext/regional/saudi_arabia/setup.py
index 9b3677d2c64..3ccaae9e6a5 100644
--- a/erpnext/regional/saudi_arabia/setup.py
+++ b/erpnext/regional/saudi_arabia/setup.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
-from erpnext.regional.united_arab_emirates.setup import make_custom_fields, add_print_formats
+from erpnext.regional.united_arab_emirates.setup import add_print_formats, make_custom_fields
def setup(company=None, patch=True):
diff --git a/erpnext/regional/south_africa/setup.py b/erpnext/regional/south_africa/setup.py
index 4657ff833dd..b13599ed0cb 100644
--- a/erpnext/regional/south_africa/setup.py
+++ b/erpnext/regional/south_africa/setup.py
@@ -7,6 +7,7 @@ import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.permissions import add_permission, update_permission_property
+
def setup(company=None, patch=True):
make_custom_fields()
add_permissions()
@@ -24,7 +25,7 @@ def make_custom_fields(update=True):
'Sales Invoice Item': is_zero_rated,
'Purchase Invoice Item': is_zero_rated
}
-
+
create_custom_fields(custom_fields, update=update)
def add_permissions():
@@ -36,7 +37,7 @@ def add_permissions():
add_permission(doctype, role, 0)
update_permission_property(doctype, role, 0, 'write', 1)
update_permission_property(doctype, role, 0, 'create', 1)
-
+
if not frappe.db.get_value('Custom Role', dict(report="VAT Audit Report")):
frappe.get_doc(dict(
diff --git a/erpnext/regional/turkey/setup.py b/erpnext/regional/turkey/setup.py
index 2396aab91f5..85d29b5da7f 100644
--- a/erpnext/regional/turkey/setup.py
+++ b/erpnext/regional/turkey/setup.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
def setup(company=None, patch=True):
pass
diff --git a/erpnext/regional/united_arab_emirates/setup.py b/erpnext/regional/united_arab_emirates/setup.py
index bd12d661f00..68da887bb72 100644
--- a/erpnext/regional/united_arab_emirates/setup.py
+++ b/erpnext/regional/united_arab_emirates/setup.py
@@ -3,11 +3,13 @@
from __future__ import unicode_literals
-import frappe, os, json
+import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.permissions import add_permission, update_permission_property
+
from erpnext.payroll.doctype.gratuity_rule.gratuity_rule import get_gratuity_rule
+
def setup(company=None, patch=True):
make_custom_fields()
add_print_formats()
diff --git a/erpnext/regional/united_arab_emirates/utils.py b/erpnext/regional/united_arab_emirates/utils.py
index 7d5fd6ecf86..66a96514fc1 100644
--- a/erpnext/regional/united_arab_emirates/utils.py
+++ b/erpnext/regional/united_arab_emirates/utils.py
@@ -1,11 +1,14 @@
from __future__ import unicode_literals
+
import frappe
from frappe import _
-import erpnext
-from frappe.utils import flt, round_based_on_smallest_currency_fraction, money_in_words
-from erpnext.controllers.taxes_and_totals import get_itemised_tax
+from frappe.utils import flt, money_in_words, round_based_on_smallest_currency_fraction
from six import iteritems
+import erpnext
+from erpnext.controllers.taxes_and_totals import get_itemised_tax
+
+
def update_itemised_tax_data(doc):
if not doc.taxes: return
diff --git a/erpnext/regional/united_states/product_tax_category_data.json b/erpnext/regional/united_states/product_tax_category_data.json
new file mode 100644
index 00000000000..4527bb25384
--- /dev/null
+++ b/erpnext/regional/united_states/product_tax_category_data.json
@@ -0,0 +1,4084 @@
+{
+ "categories": [
+ {
+ "description": "An item commonly used by a student in a course of study. This category is limited to the following items...binders, blackboard chalk, cellophane tape, compasses, composition books, crayons, erasers, folders, glue/paste/glue sticks, highlighters, index cards, index card boxes, legal pads, lunch boxes, markers, notebooks, paper (copy, graph, tracing, manila, colored, construction, notebook), pencils, pencil boxes, pencil sharpeners, pens, posterboard, protractors, rulers, scissors, writing tablets.",
+ "name": "School Supplies",
+ "product_tax_code": "44121600A0001"
+ },
+ {
+ "description": "This is a labor charge for: the planning and design of interior spaces; preparation of layout drawings, schedules, and specifications pertaining to the planning and design of interior spaces; furniture arranging; design and planning of furniture, fixtures, and cabinetry; staging; lighting and sound design; and the selection, purchase, and arrangement of surface coverings, draperies, furniture, and other decorations.",
+ "name": "Interior Decorating Services",
+ "product_tax_code": "73890600A0000"
+ },
+ {
+ "description": "Ammunition for firearms with a barrel greater than an internal diameter of .50 caliber or a shotgun larger than 10 gauge., including bullets, shotgun shells, and gunpowder.",
+ "name": "Ammunition - designed for firearms other than small arms.",
+ "product_tax_code": "46101600A0002"
+ },
+ {
+ "description": "Firearms, limited to pistols, revolvers, rifles with a barrel greater than an internal diameter of .50 caliber or a shotgun larger than 10 gauge.",
+ "name": "Firearms - other than small arms",
+ "product_tax_code": "46101500A0002"
+ },
+ {
+ "description": "A charge for an objective visual examination of a house’s systems and physical structure. The charge includes a report of the inspector's findings including pictures, analysis, and recommendations.",
+ "name": "Home Inspection Services",
+ "product_tax_code": "80131802A0001"
+ },
+ {
+ "description": "A charge for custodial services to residential structures, including the cleaning of floors, carpets, walls, windows, appliances, furniture, fixtures, exterior cleaning, etc. No Tangible Personal Property is transferred.",
+ "name": "Cleaning/Janitorial Services - Residential",
+ "product_tax_code": "76111501A0001"
+ },
+ {
+ "description": "A subscription service for membership to an online dating platform.",
+ "name": "Online Dating Services",
+ "product_tax_code": "91000000A1111"
+ },
+ {
+ "description": "A charge for the service to maintain the proper operation of home or building gutters through cleaning out debris that could otherwise affect the proper water flow through the gutter system.",
+ "name": "Gutter Cleaning Services",
+ "product_tax_code": "72152602A0001"
+ },
+ {
+ "description": "Clothing - Swim Fins",
+ "name": "Clothing - Swim Fins",
+ "product_tax_code": "4914606A0001"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods can be streamed and/or downloaded to a device with permanent access granted. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - bundle - downloaded with permanent rights and streamed - non subscription",
+ "product_tax_code": "55111516A0110"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods can be streamed and/or downloaded to a device with access that expires after a stated period of time. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - bundle - downloaded with limited rights and streamed - non subscription",
+ "product_tax_code": "55111516A0210"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods are downloaded to a device with access that expires after a stated period of time. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - downloaded - non subscription - with limited rights",
+ "product_tax_code": "55111516A0020"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods are downloaded to a device with permanent access granted. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - downloaded - non subscription - with permanent rights",
+ "product_tax_code": "55111516A0010"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods are streamed to a device with access that expires after a stated period of time. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - streamed - non subscription - with limited rights",
+ "product_tax_code": "55111516A0030"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods are streamed to a device with access that is conditioned upon continued subscription payment. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - streamed - subscription - with conditional rights",
+ "product_tax_code": "55111516A0040"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods are streamed and/or downloaded to a device with access that is conditioned upon continued subscription payment. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - bundle - downloaded and streamed - subscription - with conditional rights",
+ "product_tax_code": "55111516A0310"
+ },
+ {
+ "description": "Works that result from the fixation of a series of musical, spoken, or other sounds that are transferred electronically. These goods are streamed to a device with access that is conditioned upon continued subscription payment. These goods include prerecorded or live music, prerecorded or live readings of books or other written materials, prerecorded or live speeches, ringtones, or other sound recordings, but not including audio greeting cards.",
+ "name": "Digital Audio Works - streamed - subscription - with conditional rights",
+ "product_tax_code": "55111512A0040"
+ },
+ {
+ "description": "Works that result from the fixation of a series of musical, spoken, or other sounds that are transferred electronically. These goods are streamed to a device with access that expires after a stated period of time. These goods include prerecorded or live music, prerecorded or live readings of books or other written materials, prerecorded or live speeches, ringtones, or other sound recordings, but not including audio greeting cards.",
+ "name": "Digital Audio Works - streamed - non subscription - with limited rights",
+ "product_tax_code": "55111512A0030"
+ },
+ {
+ "description": "Works that result from the fixation of a series of musical, spoken, or other sounds that are transferred electronically. These goods are downloaded to a device with permanent access granted. These goods include prerecorded or live music, prerecorded or live readings of books or other written materials, prerecorded or live speeches, ringtones, or other sound recordings, but not including audio greeting cards.",
+ "name": "Digital Audio Works - downloaded - non subscription - with permanent rights",
+ "product_tax_code": "55111512A0010"
+ },
+ {
+ "description": "Works that result from the fixation of a series of musical, spoken, or other sounds that are transferred electronically. These goods are downloaded to a device with access that expires after a stated period of time. These goods include prerecorded or live music, prerecorded or live readings of books or other written materials, prerecorded or live speeches, ringtones, or other sound recordings, but not including audio greeting cards.",
+ "name": "Digital Audio Works - downloaded - non subscription - with limited rights",
+ "product_tax_code": "55111512A0020"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals with the entire publication or individual articles viewable (but not downloadable) on a device with access that is conditioned upon continued subscription payment.",
+ "name": "Digital Newspapers - viewable only - subscription - with conditional rights",
+ "product_tax_code": "55111507A0060"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals with the entire publication or individual articles viewable (but not downloadable) on a device with permanent access granted. The publication is accessed without a subscription.",
+ "name": "Digital Newspapers - viewable only - non subscription - with permanent rights",
+ "product_tax_code": "55111507A0040"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals with the entire publication or individual articles viewable (but not downloadable) on a device with access that expires after a stated period of time. The publication is accessed without a subscription.",
+ "name": "Digital Newspapers - viewable only - non subscription - with limited rights",
+ "product_tax_code": "55111507A0030"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals. The publication is accessed via a subscription which also entitles the purchaser to physical copies of the media.",
+ "name": "Digital Newspapers - subscription tangible and digital",
+ "product_tax_code": "55111507A0070"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals with the entire publication or individual articles downloaded to a device with access that is conditioned upon continued subscription payment.",
+ "name": "Digital Newspapers - downloadable - subscription - with conditional rights",
+ "product_tax_code": "55111507A0050"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals with the entire publication or individual articles downloaded to a device with permanent access granted. The publication is accessed without a subscription.",
+ "name": "Digital Newspapers - downloadable - non subscription - with permanent rights",
+ "product_tax_code": "55111507A0010"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals with the entire publication or individual articles downloaded to a device with access that expires after a stated period of time. The publication is accessed without a subscription.",
+ "name": "Digital Newspapers - downloadable - non subscription - with limited rights",
+ "product_tax_code": "55111507A0020"
+ },
+ {
+ "description": "A digital version of a traditional periodical published at regular intervals with the entire publication or individual articles viewable (but not downloadable) on a device with access that is conditioned upon continued subscription payment.",
+ "name": "Digital Magazines/Periodicals - viewable only - subscription - with conditional rights",
+ "product_tax_code": "55111506A0060"
+ },
+ {
+ "description": "A digital version of a traditional periodical published at regular intervals with the entire publication or individual articles viewable (but not downloadable) on a device with permanent access granted. The publication is accessed without a subscription.",
+ "name": "Digital Magazines/Periodicals - viewable only - non subscription - with permanent rights",
+ "product_tax_code": "55111506A0040"
+ },
+ {
+ "description": "A digital version of a traditional periodical published at regular intervals with the entire publication or individual articles viewable (but not downloadable) on a device with access that expires after a stated period of time. The publication is accessed without a subscription.",
+ "name": "Digital Magazines/Periodicals - viewable only - non subscription - with limited rights",
+ "product_tax_code": "55111506A0030"
+ },
+ {
+ "description": "A digital version of a traditional magazine published at regular intervals. The publication is accessed via a subscription which also entitles the purchaser to physical copies of the media.",
+ "name": "Digital Magazines/Periodicals - subscription tangible and digital",
+ "product_tax_code": "55111506A0070"
+ },
+ {
+ "description": "A digital version of a traditional periodical published at regular intervals with the entire publication or individual articles downloaded to a device with access that is conditioned upon continued subscription payment.",
+ "name": "Digital Magazines/Periodicals - downloadable - subscription - with conditional rights",
+ "product_tax_code": "55111506A0050"
+ },
+ {
+ "description": "A digital version of a traditional periodical published at regular intervals with the entire publication or individual articles downloaded to a device with permanent access granted. The publication is accessed without a subscription.",
+ "name": "Digital Magazines/Periodicals - downloadable - non subscription - with permanent rights",
+ "product_tax_code": "55111506A0010"
+ },
+ {
+ "description": "A digital version of a traditional periodical published at regular intervals with the entire publication or individual articles downloaded to a device with access that expires after a stated period of time. The publication is accessed without a subscription.",
+ "name": "Digital Magazines/Periodicals - downloadable - non subscription - with limited rights",
+ "product_tax_code": "55111506A0020"
+ },
+ {
+ "description": "Works that are generally recognized in the ordinary and usual sense as books and are transferred electronically. These goods are viewable (but not downloadable) on a device with access that is conditioned upon continued subscription payment. These goods include novels, autobiographies, encyclopedias, dictionaries, repair manuals, phone directories, business directories, zip code directories, cookbooks, etc.",
+ "name": "Digital Books - viewable only - subscription - with conditional rights",
+ "product_tax_code": "55111505A0060"
+ },
+ {
+ "description": "Works that are generally recognized in the ordinary and usual sense as books and are transferred electronically. These goods are downloaded to a device with access that is conditioned upon continued subscription payment. These goods include novels, autobiographies, encyclopedias, dictionaries, repair manuals, phone directories, business directories, zip code directories, cookbooks, etc.",
+ "name": "Digital Books - downloaded - subscription - with conditional rights",
+ "product_tax_code": "55111505A0050"
+ },
+ {
+ "description": "Works that are generally recognized in the ordinary and usual sense as books and are transferred electronically. These goods are downloaded to a device with permanent access granted. These goods include novels, autobiographies, encyclopedias, dictionaries, repair manuals, phone directories, business directories, zip code directories, cookbooks, etc.",
+ "name": "Digital Books - downloaded - non subscription - with permanent rights",
+ "product_tax_code": "55111505A0010"
+ },
+ {
+ "description": "Works that are generally recognized in the ordinary and usual sense as books and are transferred electronically. These goods are downloaded to a device with access that expires after a stated period of time. These goods include novels, autobiographies, encyclopedias, dictionaries, repair manuals, phone directories, business directories, zip code directories, cookbooks, etc.",
+ "name": "Digital Books - downloaded - non subscription - with limited rights",
+ "product_tax_code": "55111505A0020"
+ },
+ {
+ "description": "The final art used for actual reproduction by photomechanical or other processes or for display purposes, but does not include website or home page design, and that is transferred electronically. These goods are downloaded to a device with access that is conditioned upon continued subscription payment. These goods include drawings, paintings, designs, photographs, lettering, paste-ups, mechanicals, assemblies, charts, graphs, illustrative materials, etc.",
+ "name": "Digital Finished Artwork - downloaded - subscription - with conditional rights",
+ "product_tax_code": "82141502A0050"
+ },
+ {
+ "description": "The final art used for actual reproduction by photomechanical or other processes or for display purposes, but does not include website or home page design, and that is transferred electronically. These goods are downloaded to a device with permanent access granted. These goods include drawings, paintings, designs, photographs, lettering, paste-ups, mechanicals, assemblies, charts, graphs, illustrative materials, etc.",
+ "name": "Digital Finished Artwork - downloaded - non subscription - with permanent rights",
+ "product_tax_code": "82141502A0010"
+ },
+ {
+ "description": "The final art used for actual reproduction by photomechanical or other processes or for display purposes, but does not include website or home page design, and that is transferred electronically. These goods are downloaded to a device with access that expires after a stated period of time. These goods include drawings, paintings, designs, photographs, lettering, paste-ups, mechanicals, assemblies, charts, graphs, illustrative materials, etc.",
+ "name": "Digital Finished Artwork - downloaded - non subscription - with limited rights",
+ "product_tax_code": "82141502A0020"
+ },
+ {
+ "description": "Individual digital news articles, newsletters, and other stand-alone documents. These goods are viewable (but not downloadable) on a device with access that is conditioned upon continued subscription payment.",
+ "name": "Digital other news or documents - viewable only - subscription - with conditional rights",
+ "product_tax_code": "82111900A0002"
+ },
+ {
+ "description": "Individual digital news articles, newsletters, and other stand-alone documents. These goods are viewable (but not downloadable) on a device with permanent access granted.",
+ "name": "Digital other news or documents - viewable only - non subscription - with permanent rights",
+ "product_tax_code": "82111900A0005"
+ },
+ {
+ "description": "Individual digital news articles, newsletters, and other stand-alone documents. These goods are viewable (but not downloadable) on a device with access that expires after a stated period of time.",
+ "name": "Digital other news or documents - viewable only - non subscription - with limited rights",
+ "product_tax_code": "82111900A0006"
+ },
+ {
+ "description": "Individual digital news articles, newsletters, and other stand-alone documents. These goods are downloaded to a device with access that is conditioned upon continued subscription payment.",
+ "name": "Digital other news or documents - downloadable - subscription - with conditional rights",
+ "product_tax_code": "82111900A0001"
+ },
+ {
+ "description": "Individual digital news articles, newsletters, and other stand-alone documents. These goods are downloaded to a device with permanent access granted. These publications are accessed without a subscription.",
+ "name": "Digital other news or documents - downloadable - non subscription - with permanent rights",
+ "product_tax_code": "82111900A0003"
+ },
+ {
+ "description": "Individual digital news articles, newsletters, and other stand-alone documents. These goods are downloaded to a device with access that expires after a stated period of time.",
+ "name": "Digital other news or documents - downloadable - non subscription - with limited rights",
+ "product_tax_code": "82111900A0004"
+ },
+ {
+ "description": "Works that are required as part of a formal academic education program and are transferred electronically. These goods are downloaded to a device with permanent access granted.",
+ "name": "Digital School Textbooks - downloaded - non subscription - with permanent rights",
+ "product_tax_code": "55111513A0010"
+ },
+ {
+ "description": "Works that are required as part of a formal academic education program and are transferred electronically. These goods are downloaded to a device with access that expires after a stated period of time.",
+ "name": "Digital School Textbooks - downloaded - non subscription - with limited rights",
+ "product_tax_code": "55111513A0020"
+ },
+ {
+ "description": "An electronic greeting \"card\" typically sent via email that contains only static images or text, rather than an audio visual or audio only experience.",
+ "name": "Digital Greeting Cards - Static text and/or images only",
+ "product_tax_code": "14111605A0003"
+ },
+ {
+ "description": "An electronic greeting \"card\" typically sent via email that contains a series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any.",
+ "name": "Digital Greeting Cards - Audio Visual",
+ "product_tax_code": "14111605A0001"
+ },
+ {
+ "description": "An electronic greeting \"card\" typically sent via email that contains an audio only message.",
+ "name": "Digital Greeting Cards - Audio Only",
+ "product_tax_code": "14111605A0002"
+ },
+ {
+ "description": "Digital images that are downloaded to a device with permanent access granted.",
+ "name": "Digital Photographs/Images - downloaded - non subscription - with permanent rights for permanent use",
+ "product_tax_code": "60121011A0001"
+ },
+ {
+ "description": "Video or electronic games in the common sense are transferred electronically. These goods are streamed to a device with access that is conditioned upon continued subscription payment.",
+ "name": "Video Games - streamed - subscription - with conditional rights",
+ "product_tax_code": "60141104A0040"
+ },
+ {
+ "description": "Video or electronic games in the common sense are transferred electronically. These goods are streamed to a device with access that expires after a stated period of time.",
+ "name": "Video Games - streamed - non subscription - with limited rights",
+ "product_tax_code": "60141104A0030"
+ },
+ {
+ "description": "Video or electronic games in the common sense are transferred electronically. These goods are downloaded to a device with access that is conditioned upon continued subscription payment.",
+ "name": "Video Games - downloaded - subscription - with conditional rights",
+ "product_tax_code": "60141104A0050"
+ },
+ {
+ "description": "Video or electronic games in the common sense are transferred electronically. These goods are downloaded to a device with permanent access granted.",
+ "name": "Video Games - downloaded - non subscription - with permanent rights",
+ "product_tax_code": "60141104A0010"
+ },
+ {
+ "description": "Video or electronic games in the common sense are transferred electronically. These goods are downloaded to a device with access that expires after a stated period of time.",
+ "name": "Video Games - downloaded - non subscription - with limited rights",
+ "product_tax_code": "60141104A0020"
+ },
+ {
+ "description": "The conceptualize, design, program or maintain a website. The code is unique to a particular client's website.",
+ "name": "Web Site Design",
+ "product_tax_code": "81112103A0000"
+ },
+ {
+ "description": "The process of renting or buying space to house a website on the World Wide Web. Website content such as HTML, CSS, and images has to be housed on a server to be viewable online.",
+ "name": "Web Hosting Services",
+ "product_tax_code": "81112105A0000"
+ },
+ {
+ "description": "A charge separately stated from the sale of the product itself that entitles the purchaser to future repair and labor services to return the defective item of tangible personal property to its original state. The warranty contract is optional to the purchaser. Motor vehicle warranties are excluded.",
+ "name": "Warranty - Optional",
+ "product_tax_code": "81111818A0000"
+ },
+ {
+ "description": "A charge separately stated from the sale of the product itself that entitles the purchaser to future repair and labor services to return the defective item of tangible personal property to its original state. The warranty contract is mandatory and is required to be purchased on conjunction with the purchased tangible personal property. Motor vehicle warranties are excluded.",
+ "name": "Warranty - Mandatory",
+ "product_tax_code": "81111818A0001"
+ },
+ {
+ "description": "Personal or small group teaching, designed to help people who need extra help with their studies",
+ "name": "Tutoring",
+ "product_tax_code": "86132001A0000"
+ },
+ {
+ "description": "Self Study web based training, not instructor led. This does not include downloads of video replays.",
+ "name": "Training Services - Self Study Web Based",
+ "product_tax_code": "86132000A0002"
+ },
+ {
+ "description": "Live training web based. This does not include video replays of the instruction or course.",
+ "name": "Training Services - Live Virtual",
+ "product_tax_code": "86132201A0000"
+ },
+ {
+ "description": "Charges for installing, configuring, debugging, modifying, testing, or troubleshooting computer hardware, networks, programs or software. Labor only charge.",
+ "name": "Technical Support Services",
+ "product_tax_code": "81111811A0001"
+ },
+ {
+ "description": "A charge to preserve an animal's body via mounting or stuffing, for the purpose of display or study. The customer provide the animal. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Taxidermy Services",
+ "product_tax_code": "82151508A0000"
+ },
+ {
+ "description": "A charge to have files or documents shredded either onsite or offsite.",
+ "name": "Shredding Service",
+ "product_tax_code": "44101603A9007"
+ },
+ {
+ "description": "A charge to repair or restore footwear was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential. Note: This product tax code will partially apply tax in CA, MI, IL.",
+ "name": "Shoe Repair",
+ "product_tax_code": "53111600A9007"
+ },
+ {
+ "description": "A charge for the printing, imprinting, lithographing, mimeographing, photocopying, and similar reproductions of various articles including mailers, catalogs, letterhead, envelopes, business cards, presentation folders, forms, signage, etc. The end result is the transfer of tangible personal property to the customer.",
+ "name": "Printing",
+ "product_tax_code": "82121500A0000"
+ },
+ {
+ "description": "Service processing payroll checks and tracking payroll data; including printing employees’ payroll checks, pay statements, management reports, tracking payroll taxes, preparing tax returns and producing W-2’s for distribution.",
+ "name": "Payroll Services",
+ "product_tax_code": "87210202A0000"
+ },
+ {
+ "description": "A charge to repair or restore to operating condition a motor vehicle that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Motor Vehicle Repair",
+ "product_tax_code": "25100000A9007"
+ },
+ {
+ "description": "A charge to make customer provided meat suitable for human consumption, typically referred to a butcher or slaughter services.",
+ "name": "Meat Processing",
+ "product_tax_code": "42447000A0000"
+ },
+ {
+ "description": "A charge to repair or restore to operating condition a machine that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Machine Repair",
+ "product_tax_code": "23019007A0000"
+ },
+ {
+ "description": "A charge to provide laundry services to linens and the like. This charge is not for clothing items. The business customer is the owner of the items being cleaned.",
+ "name": "Linen Services - Laundry only - items other than clothing",
+ "product_tax_code": "91111502A1601"
+ },
+ {
+ "description": "A charge to provide laundry services to clothing. The business customer is the owner of the items being cleaned.",
+ "name": "Linen Services - Laundry only",
+ "product_tax_code": "91111502A1600"
+ },
+ {
+ "description": "A charge to repair or restore jewelry that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Jewelry Repair",
+ "product_tax_code": "54119007A0000"
+ },
+ {
+ "description": "A charge for the wrapping of articles in a box or bag with paper and other decorative additions. The wrapping not linked the purchased of the article(s) and is performed by a party other vendor of the article(s).",
+ "name": "Gift Wrapping - separate from purchase of article",
+ "product_tax_code": "14111601A9007"
+ },
+ {
+ "description": "A charge for the wrapping of articles in a box or bag with paper and other decorative additions. The charge is separately stated from the article.",
+ "name": "Gift Wrapping - in conjunction with purchase of article",
+ "product_tax_code": "14111601A0001"
+ },
+ {
+ "description": "A charge to perform an alteration on a item of clothing by a service provider other than vendor of the article. The alteration is not linked to the clothing purchase. Alterations could include hemming of a dress, shortening of pants, adjusting the waistline of a garment, etc.",
+ "name": "Garment Alterations- separate from purchase of garment",
+ "product_tax_code": "81149000A0000"
+ },
+ {
+ "description": "A charge to perform an alteration on a item of clothing by the vendor of the article. The alteration is separately stated from the clothing, but contracted for at the time of the clothing purchase. Alterations could include hemming of a dress, shortening of pants, adjusting the waistline of a garment, etc.",
+ "name": "Garment Alterations- in conjunction with purchase of garment",
+ "product_tax_code": "81149000A0001"
+ },
+ {
+ "description": "A separately stated labor charge to cover a piece of furniture previously owned by the customer with new fabric coverings. Any materials transferred as part of the service are separately stated.",
+ "name": "Furniture Reupholstering",
+ "product_tax_code": "72153614A0000"
+ },
+ {
+ "description": "A charge to create a finished good from materials supplied by the customer. This is a labor only charge to transform a customer's existing property.",
+ "name": "Fabrication",
+ "product_tax_code": "23839000A0000"
+ },
+ {
+ "description": "E-file services for tax returns",
+ "name": "Electronic Filing Service",
+ "product_tax_code": "72910000A0000"
+ },
+ {
+ "description": "Private schools, not college or university",
+ "name": "Educational Services",
+ "product_tax_code": "86132209A0000"
+ },
+ {
+ "description": "A charge to a non-commercial customer for the cleaning or renovating items other than clothing by immersion and agitation, spraying, vaporization, or immersion only, in a volatile, commercially moisture-free solvent or by the use of a volatile or inflammable product. This does not include the use of a self-service coin (or credit card) operated cleaning machine.",
+ "name": "Dry Cleaning - items other than clothing",
+ "product_tax_code": "91111503A1601"
+ },
+ {
+ "description": "A charge to repair or restore to operating condition computer hardware that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Computer Repair",
+ "product_tax_code": "81112300A0000"
+ },
+ {
+ "description": "A charge to clean, wash or wax a motor vehicle, other than a self-service coin (or credit card) operated washing station. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Car Washing",
+ "product_tax_code": "81119200A0000"
+ },
+ {
+ "description": "A charge to assemble goods for a purchaser who will later sell the assembled goods to end consumers.",
+ "name": "Assembly - prior to final purchase of article",
+ "product_tax_code": "93121706A0001"
+ },
+ {
+ "description": "A charge separately stated from the sale of the product itself to bring the article to its finished state and in the condition specified by the buyer.",
+ "name": "Assembly - in conjunction with final purchase of article",
+ "product_tax_code": "93121706A0000"
+ },
+ {
+ "description": "A charge to repair or restore to operating condition an appliance (dishwasher, washing machine, refrigerator, etc.) that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Appliance Repair",
+ "product_tax_code": "52143609A0000"
+ },
+ {
+ "description": "A charge to repair or restore to operating condition an aircraft that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential. Commercial aircraft is excluded.",
+ "name": "Aircraft Repair",
+ "product_tax_code": "78181800A0000"
+ },
+ {
+ "description": "A charge for the printing, imprinting, or lithographing on any article supplied by the customer. The customer owns the article throughout the process. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Printing - customer supplied articles",
+ "product_tax_code": "19009"
+ },
+ {
+ "description": "A charge to a non-commercial customer for the cleaning or renovating clothing by immersion and agitation, spraying, vaporization, or immersion only, in a volatile, commercially moisture-free solvent or by the use of a volatile or inflammable product. This does not include the use of a self-service coin (or credit card) operated cleaning machine.",
+ "name": "Dry Cleaning Services",
+ "product_tax_code": "19006"
+ },
+ {
+ "description": "A charge to repair or restore tangible personal property that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Repair Services",
+ "product_tax_code": "19007"
+ },
+ {
+ "description": "Food for household pets that is consumed for nutritional value. This code is not intended for food related to working farm animals or animals raised for meat or milk production. This code is intended for retail sales made directly to end consumers.",
+ "name": "OTC Pet Food",
+ "product_tax_code": "10122100A0000"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with candy, with the candy comprising between 25% and 49% of the overall value of the bundle (food comprises 51 to 75%). Note that any candy containing flour should be considered as food (and not candy) when determining bundle percentages.",
+ "name": "Food/Candy Bundle - with Candy 25% to 49%",
+ "product_tax_code": "50193400A0008"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with candy, with the candy comprising between 11% and 24% of the overall value of the bundle (food comprises 76% to 89%). Note that any candy containing flour should be considered as food (and not candy) when determining bundle percentages.",
+ "name": "Food/Candy Bundle - with Candy 11% to 24%",
+ "product_tax_code": "50193400A0009"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with candy, with the candy comprising 10% or less of the overall value of the bundle (food comprises 90% or more). Note that any candy containing flour should be considered as food (and not candy) when determining bundle percentages.",
+ "name": "Food/Candy Bundle - with Candy 10% or less",
+ "product_tax_code": "50193400A0010"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with candy, with the candy comprising 50% or more of the overall value of the bundle (food comprises 50% or less). Note that any candy containing flour should be considered as food (and not candy) when determining bundle percentages.",
+ "name": "Food/Candy Bundle - with Candy 50% or more",
+ "product_tax_code": "50193400A0007"
+ },
+ {
+ "description": "Male or female condoms and vaginal sponges used to prevent pregnancy and/or exposure to STDs, containing a spermicidal lubricant as indicated by a \"drug facts\" panel or a statement of active ingredients, sold under prescription order of a licensed professional.",
+ "name": "Condoms with Spermicide with Prescription",
+ "product_tax_code": "53131622A0004"
+ },
+ {
+ "description": "Over-the-Counter emergency contraceptive pills act to prevent pregnancy after intercourse. The contraceptive contains a hormone that prevents ovulation, fertilization, or implantation of an embryo.",
+ "name": "Birth Control - Over-the-Counter Oral Contraceptives",
+ "product_tax_code": "51350000A0001"
+ },
+ {
+ "description": "An oral medication containing hormones effective in altering the menstrual cycle to eliminate ovulation and prevent pregnancy, available only under prescription order of a licensed professional. Other than preventing pregnancy, hormonal birth control can also be used to treat various conditions, such as Polycystic Ovary Syndrome, Endometriosis, Primary Ovarian Insufficiency, etc.",
+ "name": "Birth Control - Prescription Oral Contraceptives",
+ "product_tax_code": "51350000A0000"
+ },
+ {
+ "description": "Over-the-Counter emergency contraceptive pills act to prevent pregnancy after intercourse, sold under prescription order of a licensed professional. The contraceptive contains a hormone that prevents ovulation, fertilization, or implantation of an embryo.",
+ "name": "Birth Control - Over-the-Counter Oral Contraceptives with Prescription",
+ "product_tax_code": "51350000A0002"
+ },
+ {
+ "description": "Barrier based prescription only birth control methods, including the diaphragm and cervical cap that prevent the joining of the sperm and egg, available only under prescription order of a licensed professional.",
+ "name": "Birth Control - Prescription non-Oral Contraceptives - Barriers",
+ "product_tax_code": "42143103A0000"
+ },
+ {
+ "description": "Hormonal based birth control methods other than the oral pill, including intrauterine devices, injections, skin implants, transdermal patches, and vaginal rings that release a continuous dose of hormones to eliminate ovulation and prevent pregnancy, available only under prescription order of a licensed professional.",
+ "name": "Birth Control - Prescription non-Oral Contraceptives - Hormonal",
+ "product_tax_code": "51350000A0003"
+ },
+ {
+ "description": "Male or female condoms and vaginal sponges used to prevent pregnancy and/or exposure to STDs, sold under prescription order of a licensed professional.",
+ "name": "Condoms with Prescription",
+ "product_tax_code": "53131622A0003"
+ },
+ {
+ "description": "Feminine hygiene product designed to absorb the menstrual flow. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Tampons, menstrual cups, pads, liners",
+ "product_tax_code": "53131615A0000"
+ },
+ {
+ "description": "Infant washable/reusable cloth diapers.",
+ "name": "Clothing - Cloth Diapers",
+ "product_tax_code": "53102305A0001"
+ },
+ {
+ "description": "Clothing - Diaper liners",
+ "name": "Clothing - Diaper liners",
+ "product_tax_code": "53102308A0000"
+ },
+ {
+ "description": "Clothing - Adult diapers",
+ "name": "Clothing - Adult diapers",
+ "product_tax_code": "53102306A0000"
+ },
+ {
+ "description": "Clothing - Infant diapers",
+ "name": "Clothing - Infant diapers",
+ "product_tax_code": "53102305A0000"
+ },
+ {
+ "description": "Food and Beverage - Candy containing flour as an ingredient",
+ "name": "Food and Beverage - Candy containing flour as an ingredient",
+ "product_tax_code": "50161800A0001"
+ },
+ {
+ "description": "Food and Beverage - Food and Food Ingredients for Home Consumption",
+ "name": "Food and Beverage - Food and Food Ingredients for Home Consumption",
+ "product_tax_code": "50000000A0000"
+ },
+ {
+ "description": "Clothing - Zippers",
+ "name": "Clothing - Zippers",
+ "product_tax_code": "53141503A0000"
+ },
+ {
+ "description": "Clothing - Gorgets",
+ "name": "Clothing - Gorgets",
+ "product_tax_code": "53102519A0000"
+ },
+ {
+ "description": "Clothing - Shoulder boards or epaulettes",
+ "name": "Clothing - Shoulder boards or epaulettes",
+ "product_tax_code": "53102520A0000"
+ },
+ {
+ "description": "Yarn - For use other than fabricating/repairing clothing",
+ "name": "Yarn - For use other than fabricating/repairing clothing",
+ "product_tax_code": "11151700A0001"
+ },
+ {
+ "description": "Clothing - Snaps",
+ "name": "Clothing - Snaps",
+ "product_tax_code": "53141506A0000"
+ },
+ {
+ "description": "Clothing - Clasps",
+ "name": "Clothing - Clasps",
+ "product_tax_code": "53141507A0000"
+ },
+ {
+ "description": "Clothing - Buttons",
+ "name": "Clothing - Buttons",
+ "product_tax_code": "53141505A0000"
+ },
+ {
+ "description": "Clothing - Clothing - Fabric dye",
+ "name": "Clothing - Fabric dye",
+ "product_tax_code": "60105810A0000"
+ },
+ {
+ "description": "Clothing - Fabric for use in clothing",
+ "name": "Clothing - Fabric for use in clothing",
+ "product_tax_code": "11160000A0000"
+ },
+ {
+ "description": "Clothing - Clothing - Yarn",
+ "name": "Clothing - Yarn",
+ "product_tax_code": "11151700A0000"
+ },
+ {
+ "description": "A lump sum charge where both the downloaded digital products and the service components each are greater than 10% of the bundle.",
+ "name": "Digital Products (> 10%) / General Services (> 10%) Bundle",
+ "product_tax_code": "55111500A5000"
+ },
+ {
+ "description": "Services provided by a licensed or registered professional in the medical field. Examples: Doctor, dentist, nurse, optometrist, etc.",
+ "name": "Medical Professional Services - Physician, Dentist, and similar",
+ "product_tax_code": "62139900A0000"
+ },
+ {
+ "description": "The puncturing or penetration of the skin of a person and the insertion of jewelry or other adornment into the opening.",
+ "name": "Body Piercing",
+ "product_tax_code": "72990190A0000"
+ },
+ {
+ "description": "Cosmetic beauty treatment for the fingernails and toenails. Consists of filing, cutting and shaping and the application of polish.",
+ "name": "Manicure Services",
+ "product_tax_code": "72310104A0000"
+ },
+ {
+ "description": "Performing tests and research for a particular client in connection with the development of particular products, property, goods or services that the client sells to consumers in the regular course of business.",
+ "name": "Marketing Services",
+ "product_tax_code": "87420300A0000"
+ },
+ {
+ "description": "Performing surveying and mapping services of the surface of the earth, including the sea floor. These services may include surveying and mapping of areas above or below the surface of the earth, such as the creation of view easements or segregating rights in parcels of land by creating underground utility easements.",
+ "name": "Property Surveying Services",
+ "product_tax_code": "87130000A0000"
+ },
+ {
+ "description": "Providing a systematic inquiry, examination, or analysis of people, events or documents, to determine the facts of a given situation. The evaluation is submitted in the form of a report or provided as a testimony in legal proceedings. Techniques such as surveillance, background checks, computer searches, fingerprinting, lie detector services, and interviews may be used to gather the information.",
+ "name": "Private Investigator Services",
+ "product_tax_code": "73810204A0000"
+ },
+ {
+ "description": "The provision of expertise or strategic advice that is presented for consideration and decision-making.",
+ "name": "Consulting Services",
+ "product_tax_code": "87480000A0000"
+ },
+ {
+ "description": "Services relating to advocating for the passage or defeat of legislation to members or staff of the government.",
+ "name": "Lobbying Services",
+ "product_tax_code": "87439901A0000"
+ },
+ {
+ "description": "Preparation of materials, written or otherwise, that are designed to influence the general public or other groups by promoting the interests of a service recipient.",
+ "name": "Public Relations",
+ "product_tax_code": "87430000A0000"
+ },
+ {
+ "description": "Services related to the art and science of designing and building structures for human habitation or use and includes planning, providing preliminary studies, designs, specifications, working drawings and providing for general administration of construction contracts.",
+ "name": "Architectural Services",
+ "product_tax_code": "87120000A0000"
+ },
+ {
+ "description": "Services provided by a profession trained to apply physical laws and principles of engineering in the design, development, and utilization of machines, materials, instruments, structures, processes, and systems. The services involve any of the following activities: provision of advice, preparation of feasibility studies, preparation of preliminary and final plans and designs, provision of technical services during the construction or installation phase, inspection and evaluation of engineering projects, and related services.",
+ "name": "Engineering Services",
+ "product_tax_code": "87110000A0000"
+ },
+ {
+ "description": "Services that provide non-medical care and supervision for infant to school-age children or senior citizens.",
+ "name": "Childcare Services / Adultcare",
+ "product_tax_code": "83510000A0000"
+ },
+ {
+ "description": "Services provided by a facility for overnight care of an animal not related to veterinary care.",
+ "name": "Pet Services - Boarding",
+ "product_tax_code": "81291000A0001"
+ },
+ {
+ "description": "Services relating to or concerned with the law. Such services include, but are not limited to, representation by an attorney (or other person, when permitted) in an administrative or legal proceeding, legal drafting, paralegal services, legal research services, arbitration, mediation, and court reporting services.",
+ "name": "Legal Services",
+ "product_tax_code": "81110000A0000"
+ },
+ {
+ "description": "Medical procedure performed on an individual that is directed at improving the individual's appearance and that does not meaningfully promote the proper function of the body or prevent or treat illness or disease.",
+ "name": "Cosmetic Medical Procedure",
+ "product_tax_code": "80110517A0000"
+ },
+ {
+ "description": "Alarm monitoring involves people using computers, software, and telecommunications to monitor homes and businesses for break-ins, fires, and other unexpected events.",
+ "name": "Security - Alarm Services",
+ "product_tax_code": "73829901A0000"
+ },
+ {
+ "description": "Services related to protecting persons or their property, preventing the theft of goods, merchandise, or money. Responding to alarm signal device, burglar alarm, television camera, still camera, or a mechanical or electronic device installed or used to prevent or detect burglary, theft, shoplifting, pilferage, losses, or other security measures. Providing management and control of crowds for safety and protection.",
+ "name": "Security - Guard Services",
+ "product_tax_code": "73810105A0000"
+ },
+ {
+ "description": "Transporting under armed private security guard from one place to another any currency, jewels, stocks, bonds, paintings, or other valuables of any kind in a specially equipped motor vehicle that offers a high degree of security.",
+ "name": "Armored Car Services",
+ "product_tax_code": "73810101A0000"
+ },
+ {
+ "description": "Services related to providing personnel, on a temporary basis, to perform work or labor under the supervision or control of another.",
+ "name": "Temporary Help Services",
+ "product_tax_code": "73630103A0000"
+ },
+ {
+ "description": "Services employment agencies provide are finding a job for a job-seeker and finding an employee for an employer.",
+ "name": "Employment Services",
+ "product_tax_code": "73610000A0000"
+ },
+ {
+ "description": "Services to industrial, commercial or income-producing real property, such as as management, electrical, plumbing, painting and carpentry, provided to income-producing property.",
+ "name": "Building Management Services",
+ "product_tax_code": "73490000A0000"
+ },
+ {
+ "description": "Services which include, but are not limited to, editing, letter writing, proofreading, resume writing, typing or word processing.  Not including court reporting and stenographic services.",
+ "name": "Secretarial Services",
+ "product_tax_code": "73389903A0000"
+ },
+ {
+ "description": "Services that include typing, taking shorthand, and taking and transcribing dictation for others for a consideration.",
+ "name": "Stenographic Services",
+ "product_tax_code": "73380200A0000"
+ },
+ {
+ "description": "A process that uses needles and colored ink to permanently put a mark or design on a person’s skin. Also applying permanent make-up, such as eyelining and other permanent colors to enhance the skin of the face, lips, eyelids, and eyebrows.",
+ "name": "Tattooing Services",
+ "product_tax_code": "72990106A0000"
+ },
+ {
+ "description": "A variety of personal services typically with the purpose of improving health, beauty and relaxation through treatments such as hair, massages and facials.",
+ "name": "Spa Services",
+ "product_tax_code": "72990201A0000"
+ },
+ {
+ "description": "Services where the use of structured touch, include holding, applying pressure, positioning, and mobilizing soft tissue of the body by manual technique. Note: This does not include medical massage prescribed by a physician.",
+ "name": "Massage Services",
+ "product_tax_code": "72990200A0000"
+ },
+ {
+ "description": "The measurement, processing and communication of financial information about economic entities including, but is not limited to, financial accounting, management accounting, auditing, cost containment and auditing services, taxation and accounting information systems; excluding general bookkeeping service.",
+ "name": "Accounting Services",
+ "product_tax_code": "87210200A0000"
+ },
+ {
+ "description": "The training of an animal to obey certain commands.",
+ "name": "Pet Services - Obedience Training",
+ "product_tax_code": "81291000A0002"
+ },
+ {
+ "description": "Credit monitoring services are companies consumers pay to keep an eye on your credit files. The services notifies one when they see activity in credit files, so one can determine if that activity is a result of action one took or possibly fraudulent",
+ "name": "Credit Monitoring Services",
+ "product_tax_code": "56145000A0000"
+ },
+ {
+ "description": "Grooming services for an animal such as haircuts, bathing, nail trimming, and flea dips.",
+ "name": "Pet Services - Grooming",
+ "product_tax_code": "81291000A0000"
+ },
+ {
+ "description": "Debt collection is when a collection agency or company tries to collect past-due debts from borrowers.",
+ "name": "Debt Collection Services",
+ "product_tax_code": "73229902A0000"
+ },
+ {
+ "description": "A service that arranges introductions, for a fee, for strangers seeking romantic partners or friends. This excludes online dating services.",
+ "name": "Dating Services",
+ "product_tax_code": "72990301A0000"
+ },
+ {
+ "description": "A service that allows merchants to accept credit cards as well as send credit card payment details to the credit card network. It then forwards the payment authorization back to the acquiring bank.",
+ "name": "Credit Card Processing Services",
+ "product_tax_code": "52232000A0000"
+ },
+ {
+ "description": "Services for artificial tanning and skin beautification.",
+ "name": "Tanning Services",
+ "product_tax_code": "72990105A0000"
+ },
+ {
+ "description": "Credit reporting agencies receive various types of information which can be included in their offerings for customers.",
+ "name": "Credit Reporting Services",
+ "product_tax_code": "73230000A0000"
+ },
+ {
+ "description": "Miscellaneous personal services are generally services that affect the appearance or comfort of people. This does not include haircutting/styling services",
+ "name": "Personal Services",
+ "product_tax_code": "72990000A0000"
+ },
+ {
+ "description": "The removal of hair from the face or body using chemicals or heat energy.",
+ "name": "Electrolysis",
+ "product_tax_code": "72310102A0000"
+ },
+ {
+ "description": "Services provided to insurance companies providing insurance to consumers. Examples are loss or damage appraisals, inspections, actuarial services, claims adjustment or processing. Investigations as excluded from this definition.",
+ "name": "Insurance Services",
+ "product_tax_code": "64110000A0000"
+ },
+ {
+ "description": "An at-home infectious disease test kit that can be sold without a prescription.",
+ "name": "Infectious Disease Test - Over-the-Counter",
+ "product_tax_code": "41116205A0005"
+ },
+ {
+ "description": "An at-home infectious disease test kit that can only be sold with a prescription.",
+ "name": "Infectious Disease Test - Prescription only",
+ "product_tax_code": "41116205A0004"
+ },
+ {
+ "description": "Online database information retrieval service (personal or individual)",
+ "name": "Online database information retrieval service (personal or individual)",
+ "product_tax_code": "81111902A0001"
+ },
+ {
+ "description": "Database information retrieval",
+ "name": "Database information retrieval (personal or individual)",
+ "product_tax_code": "81111901A0001"
+ },
+ {
+ "description": "Services provided by beauty shops and barber shops, including but not limited to haircutting, hair coloring, shampooing, blow drying, permanents, hair extensions, hair straightening, and hair restorations.",
+ "name": "Hairdressing Services",
+ "product_tax_code": "19008"
+ },
+ {
+ "description": "Professional services which are not subject to a service-specific tax levy.",
+ "name": "Professional Services",
+ "product_tax_code": "19005"
+ },
+ {
+ "description": "Online database information retrieval service",
+ "name": "Online database information retrieval service",
+ "product_tax_code": "81111902A0000"
+ },
+ {
+ "description": "Database information retrieval",
+ "name": "Database information retrieval",
+ "product_tax_code": "81111901A0000"
+ },
+ {
+ "description": "Cash donation",
+ "name": "Cash donation",
+ "product_tax_code": "14111803A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicaid, medical grade oyxgen.",
+ "name": "Medical Oxygen with Prescription billed to Medicaid",
+ "product_tax_code": "42271700A0008"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, a machine used that filters a patient's blood to remove excess water and waste products when the kidneys are damaged,",
+ "name": "Kidney Dialysis Equipment for home use without Prescription",
+ "product_tax_code": "42161800A0006"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicaid, equipment that: can withstand repeated use; is primarily and customarily used to serve a medical purpose; generally is not useful to a person in the absence of illness or injury; and is not worn in or on the body. Home use means the equipment is sold to an individual for use at home, regardless of where the individual resides. Examples include hospital beds, commode chairs, bed pans, shower and bath aids, IV poles, etc.",
+ "name": "Durable Medical Equipment for home use with Prescription reimbursed by Medicaid",
+ "product_tax_code": "42140000A0005"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicare, a machine used that filters a patient's blood to remove excess water and waste products when the kidneys are damaged, dysfunctional, or missing. The kidney dialysis machine is an artificial part which augments the natural functioning of the kidneys.",
+ "name": "Kidney Dialysis Equipment for home use with Prescription billed to Medicare",
+ "product_tax_code": "42161800A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicare, equipment that: can withstand repeated use; is primarily and customarily used to serve a medical purpose; generally is not useful to a person in the absence of illness or injury; and is not worn in or on the body. Home use means the equipment is sold to an individual for use at home, regardless of where the individual resides. Examples include hospital beds, commode chairs, bed pans, shower and bath aids, IV poles, etc.",
+ "name": "Durable Medical Equipment for home use with Prescription reimbursed by Medicare",
+ "product_tax_code": "42140000A0004"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicare, equipment used to administer oxygen directly into the lungs of the patient for the relief of conditions in which the human body experiences an abnormal deficiency or inadequate supply of oxygen. Oxygen equipment means oxygen cylinders, cylinder transport devices, including sheaths and carts, cylinder studs and support devices, regulators, flowmeters, tank wrenches, oxygen concentrators, liquid oxygen base dispensers, liquid oxygen portable dispensers, oxygen tubing, nasal cannulas, face masks, oxygen humidifiers, and oxygen fittings and accessories.",
+ "name": "Oxygen Delivery Equipment for home use with Prescription reimbursed by Medicare",
+ "product_tax_code": "42271700A0004"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, equipment that: can withstand repeated use; is primarily and customarily used to serve a medical purpose; generally is not useful to a person in the absence of illness or injury; and is not worn in or on the body. Home use means the equipment is sold to an individual for use at home, regardless of where the individual resides. Examples include hospital beds, commode chairs, bed pans, shower and bath aids, IV poles, etc.",
+ "name": "Durable Medical Equipment for home use with Prescription",
+ "product_tax_code": "42140000A0001"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicare, equipment used to administer oxygen directly into the lungs of the patient for the relief of conditions in which the human body experiences an abnormal deficiency or inadequate supply of oxygen. Oxygen equipment means oxygen cylinders, cylinder transport devices, including sheaths and carts, cylinder studs and support devices, regulators, flowmeters, tank wrenches, oxygen concentrators, liquid oxygen base dispensers, liquid oxygen portable dispensers, oxygen tubing, nasal cannulas, face masks, oxygen humidifiers, and oxygen fittings and accessories.",
+ "name": "Oxygen Delivery Equipment for home use with Prescription billed to Medicare",
+ "product_tax_code": "42271700A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicaid, medical grade oyxgen.",
+ "name": "Medical Oxygen with Prescription reimbursed by Medicaid",
+ "product_tax_code": "42271700A0010"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, medical grade oyxgen.",
+ "name": "Medical Oxygen with Prescription",
+ "product_tax_code": "42271700A0012"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, medical grade oyxgen.",
+ "name": "Medical Oxygen without Prescription",
+ "product_tax_code": "42271700A0011"
+ },
+ {
+ "description": "Equipment which is primarily and customarily used to provide or increase the ability to move from one place to another, sold without a prescription, and which is appropriate for use either in a home or a motor vehicle; Is not generally used by persons with normal mobility; and does not include any motor vehicle or equipment on a motor vehicle normally provided by a motor vehicle manufacturer. Examples include wheelchairs, crutches, canes, walkers, chair lifts, etc.",
+ "name": "Mobility Enhancing Equipment without Prescription",
+ "product_tax_code": "42211500A0006"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicaid, equipment used to administer oxygen directly into the lungs of the patient for the relief of conditions in which the human body experiences an abnormal deficiency or inadequate supply of oxygen. Oxygen equipment means oxygen cylinders, cylinder transport devices, including sheaths and carts, cylinder studs and support devices, regulators, flowmeters, tank wrenches, oxygen concentrators, liquid oxygen base dispensers, liquid oxygen portable dispensers, oxygen tubing, nasal cannulas, face masks, oxygen humidifiers, and oxygen fittings and accessories.",
+ "name": "Oxygen Delivery Equipment for home use with Prescription billed to Medicaid",
+ "product_tax_code": "42271700A0003"
+ },
+ {
+ "description": "Synthetic or animal-based insulin used as an injectible drug for diabetes patients, sold under prescription order of a licensed professional.",
+ "name": "Insulin with Prescription",
+ "product_tax_code": "51183603A0000"
+ },
+ {
+ "description": "Devices used by diabetic individuals to monitor sugar levels in the blood, sold under prescription order of a licensed professional.",
+ "name": "Blood Glucose Monitoring Devices with Prescription",
+ "product_tax_code": "41116201A0000"
+ },
+ {
+ "description": "Devices used by diabetic individuals to monitor sugar levels in the blood, sold without prescription order of a licensed professional.",
+ "name": "Blood Glucose Monitoring Devices without Prescription",
+ "product_tax_code": "41116201A0001"
+ },
+ {
+ "description": "At home urine-based tests used to detect the presense of various drug substances in an individual.",
+ "name": "Drug Testing Kits",
+ "product_tax_code": "41116136A0001"
+ },
+ {
+ "description": "Single use hollow needle commonly used with a syringe to inject insulin into the body by diabetic individuals, sold under prescription order of a licensed professional.",
+ "name": "Hypodermic Needles/Syringes with prescription - Insulin",
+ "product_tax_code": "42142523A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicare, medical grade oyxgen.",
+ "name": "Medical Oxygen with Prescription reimbursed by Medicare",
+ "product_tax_code": "42271700A0009"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicare, medical grade oyxgen.",
+ "name": "Medical Oxygen with Prescription billed to Medicare",
+ "product_tax_code": "42271700A0007"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, a replacement, corrective, or supportive device, worn on or in the body to: Artificially replace a missing portion of the body; Prevent or correct physical deformity or malfunction; or Support a weak or deformed portion of the body. Worn in or on the body means that the item is implanted or attached so that it becomes part of the body, or is carried by the body and does not hinder the mobility of the individual. Examples include artificial limbs, pacemakers, orthopedics, ostomy/colostomy devices, etc.",
+ "name": "Prosthetic Devices without Prescription",
+ "product_tax_code": "42242000A0006"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicaid, a replacement, corrective, or supportive device, worn on or in the body to: Artificially replace a missing portion of the body; Prevent or correct physical deformity or malfunction; or Support a weak or deformed portion of the body. Worn in or on the body means that the item is implanted or attached so that it becomes part of the body, or is carried by the body and does not hinder the mobility of the individual. Examples include artificial limbs, pacemakers, orthotics, orthopedics, ostomy/colostomy devices, catheters, etc.",
+ "name": "Prosthetic Devices with Prescription Billed to Medicaid",
+ "product_tax_code": "42242000A0003"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicare, a replacement, corrective, or supportive device, worn on or in the body to: Artificially replace a missing portion of the body; Prevent or correct physical deformity or malfunction; or Support a weak or deformed portion of the body. Worn in or on the body means that the item is implanted or attached so that it becomes part of the body, or is carried by the body and does not hinder the mobility of the individual. Examples include artificial limbs, pacemakers, orthotics, orthopedics, ostomy/colostomy devices, catheters, etc.",
+ "name": "Prosthetic Devices with Prescription Billed to Medicare",
+ "product_tax_code": "42242000A0002"
+ },
+ {
+ "description": "At home saliva, cheeek swab or blood drop based tests used to detect various genetic markers in an individual.",
+ "name": "DNA Testing Kits",
+ "product_tax_code": "41116205A0003"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicaid, nutritional tube feeding equipment including button-style feeding tubes, standard G-tubes, NG-tubes, extension sets, adapters, feeding pumps, feeding pump delivery sets.",
+ "name": "Enteral Feeding Equipment for home use with Prescription reimbursed by Medicaid",
+ "product_tax_code": "42231500A0005"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicaid, equipment used to administer oxygen directly into the lungs of the patient for the relief of conditions in which the human body experiences an abnormal deficiency or inadequate supply of oxygen. Oxygen equipment means oxygen cylinders, cylinder transport devices, including sheaths and carts, cylinder studs and support devices, regulators, flowmeters, tank wrenches, oxygen concentrators, liquid oxygen base dispensers, liquid oxygen portable dispensers, oxygen tubing, nasal cannulas, face masks, oxygen humidifiers, and oxygen fittings and accessories.",
+ "name": "Oxygen Delivery Equipment for home use with Prescription reimbursed by Medicaid",
+ "product_tax_code": "42271700A0005"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, equipment used to administer oxygen directly into the lungs of the patient for the relief of conditions in which the human body experiences an abnormal deficiency or inadequate supply of oxygen. Oxygen equipment means oxygen cylinders, cylinder transport devices, including sheaths and carts, cylinder studs and support devices, regulators, flowmeters, tank wrenches, oxygen concentrators, liquid oxygen base dispensers, liquid oxygen portable dispensers, oxygen tubing, nasal cannulas, face masks, oxygen humidifiers, and oxygen fittings and accessories.",
+ "name": "Oxygen Delivery Equipment for home use with Prescription",
+ "product_tax_code": "42271700A0001"
+ },
+ {
+ "description": "Synthetic or animal-based insulin used as an injectible drug for diabetes patients, sold without prescription order of a licensed professional.",
+ "name": "Insulin without Prescription",
+ "product_tax_code": "51183603A0001"
+ },
+ {
+ "description": "Single use hollow needle commonly used with a syringe to inject insulin into the body by diabetic individuals, sold without prescription order of a licensed professional.",
+ "name": "Hypodermic Needles/Syringes without prescription - Insulin",
+ "product_tax_code": "42142523A0001"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, equipment used to administer oxygen directly into the lungs of the patient for the relief of conditions in which the human body experiences an abnormal deficiency or inadequate supply of oxygen. Oxygen equipment means oxygen cylinders, cylinder transport devices, including sheaths and carts, cylinder studs and support devices, regulators, flowmeters, tank wrenches, oxygen concentrators, liquid oxygen base dispensers, liquid oxygen portable dispensers, oxygen tubing, nasal cannulas, face masks, oxygen humidifiers, and oxygen fittings and accessories.",
+ "name": "Oxygen Delivery Equipment for home use without Prescription",
+ "product_tax_code": "42271700A0006"
+ },
+ {
+ "description": "At home blood-prick based tests used to monitor cholesterol levels in an individual.",
+ "name": "Cholesterol Testing Kits",
+ "product_tax_code": "41116202A0001"
+ },
+ {
+ "description": "Single use supplies utilized by diabetics in the regular blood sugar monitoring regimen. Includes skin puncture lancets, test strips for blood glucose monitors, visual read test strips, and urine test strips, sold under prescription order of a licensed professional.",
+ "name": "Diabetic Testing Supplies - single use - with Prescription",
+ "product_tax_code": "41116120A0002"
+ },
+ {
+ "description": "A breast pump is a mechanical device that lactating women use to extract milk from their breasts. They may be manual devices powered by hand or foot movements or automatic devices powered by electricity.",
+ "name": "Breast Pumps",
+ "product_tax_code": "42231901A0000"
+ },
+ {
+ "description": "At home urine-based tests used to detect pregancy hormone levels.",
+ "name": "Pregenacy Testing Kits",
+ "product_tax_code": "41116205A0001"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, and reimbursed by Medicaid, equipment which is primarily and customarily used to provide or increase the ability to move from one place to another and which is appropriate for use either in a home or a motor vehicle; Is not generally used by persons with normal mobility; and Does not include any motor vehicle or equipment on a motor vehicle normally provided by a motor vehicle manufacturer. Examples include wheelchairs, crutches, canes, walkers, chair lifts, etc.",
+ "name": "Mobility Enhancing Equipment with Prescription Reimbursed by Medicaid",
+ "product_tax_code": "42211500A0005"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, a replacement, corrective, or supportive device, worn in the mouth, including dentures, orthodontics, crowns, bridges, etc.",
+ "name": "Dental Prosthetics without Prescription",
+ "product_tax_code": "42151500A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, a replacement, corrective, or supportive device, worn in the mouth, including dentures, orthodontics, crowns, bridges, etc.",
+ "name": "Dental Prosthetics with Prescription",
+ "product_tax_code": "42151500A0001"
+ },
+ {
+ "description": "At home urine-based tests used to detect impending ovulation to assist in pregnancy planning.",
+ "name": "Ovulation Testing Kits",
+ "product_tax_code": "41116205A0002"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, nutritional tube feeding equipment including button-style feeding tubes, standard G-tubes, NG-tubes, extension sets, adapters, feeding pumps, feeding pump delivery sets.",
+ "name": "Enteral Feeding Equipment for home use without Prescription",
+ "product_tax_code": "42231500A0006"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicare, nutritional tube feeding equipment including button-style feeding tubes, standard G-tubes, NG-tubes, extension sets, adapters, feeding pumps, feeding pump delivery sets.",
+ "name": "Enteral Feeding Equipment for home use with Prescription reimbursed by Medicare",
+ "product_tax_code": "42231500A0004"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, equipment that: can withstand repeated use; is primarily and customarily used to serve a medical purpose; generally is not useful to a person in the absence of illness or injury; and is not worn in or on the body. Home use means the equipment is sold to an individual for use at home, regardless of where the individual resides. Examples include hospital beds, commode chairs, bed pans, IV poles, etc.",
+ "name": "Durable Medical Equipment for home use without Prescription",
+ "product_tax_code": "42140000A0006"
+ },
+ {
+ "description": "Male or female condoms used to prevent pregnancy or exposure to STDs, containing a spermicidal lubricant as indicated by a \"drug facts\" panel or a statement of active ingredients.",
+ "name": "Condoms with Spermicide",
+ "product_tax_code": "53131622A0001"
+ },
+ {
+ "description": "Single use supplies utilized by diabetics in the regular blood sugar monitoring regimen. Includes skin puncture lancets, test strips for blood glucose monitors, visual read test strips, and urine test strips.",
+ "name": "Diabetic Testing Supplies - single use - without Prescription",
+ "product_tax_code": "41116120A0001"
+ },
+ {
+ "description": "An electronic device that clips onto a patient's finger to measure heart rate and oxygen saturation in his or her red blood cells.",
+ "name": "Pulse Oximeter",
+ "product_tax_code": "42181801A0000"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, equipment which is primarily and customarily used to provide or increase the ability to move from one place to another and which is appropriate for use either in a home or a motor vehicle; Is not generally used by persons with normal mobility; and Does not include any motor vehicle or equipment on a motor vehicle normally provided by a motor vehicle manufacturer. Examples include wheelchairs, crutches, canes, walkers, chair lifts, etc.",
+ "name": "Mobility Enhancing Equipment with Prescription",
+ "product_tax_code": "42211500A0001"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, a replacement, corrective, or supportive device, worn on or in the body to: Artificially replace a missing portion of the body; Prevent or correct physical deformity or malfunction; or Support a weak or deformed portion of the body. Worn in or on the body means that the item is implanted or attached so that it becomes part of the body, or is carried by the body and does not hinder the mobility of the individual. Examples include artificial limbs, pacemakers, orthotics, orthopedics, ostomy/colostomy devices, catheters, etc.",
+ "name": "Prosthetic Devices with Prescription",
+ "product_tax_code": "42242000A0001"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicare, nutritional tube feeding equipment including button-style feeding tubes, standard G-tubes, NG-tubes, extension sets, adapters, feeding pumps, feeding pump delivery sets.",
+ "name": "Enteral Feeding Equipment for home use with Prescription billed to Medicare",
+ "product_tax_code": "42231500A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicaid, equipment that: can withstand repeated use; is primarily and customarily used to serve a medical purpose; generally is not useful to a person in the absence of illness or injury; and is not worn in or on the body. Home use means the equipment is sold to an individual for use at home, regardless of where the individual resides. Examples include hospital beds, commode chairs, bed pans, shower and bath aids, IV poles, etc.",
+ "name": "Durable Medical Equipment for home use with Prescription billed to Medicaid",
+ "product_tax_code": "42140000A0003"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicare, a replacement, corrective, or supportive device, worn on or in the body to: Artificially replace a missing portion of the body; Prevent or correct physical deformity or malfunction; or Support a weak or deformed portion of the body. Worn in or on the body means that the item is implanted or attached so that it becomes part of the body, or is carried by the body and does not hinder the mobility of the individual. Examples include artificial limbs, pacemakers, orthotics, orthopedics, ostomy/colostomy devices, catheters, etc.",
+ "name": "Prosthetic Devices with Prescription Reimbursed by Medicare",
+ "product_tax_code": "42242000A0004"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, and billed to Medicare, equipment which is primarily and customarily used to provide or increase the ability to move from one place to another and which is appropriate for use either in a home or a motor vehicle; Is not generally used by persons with normal mobility; and Does not include any motor vehicle or equipment on a motor vehicle normally provided by a motor vehicle manufacturer. Examples include wheelchairs, crutches, canes, walkers, chair lifts, etc.",
+ "name": "Mobility Enhancing Equipment with Prescription Billed to Medicare",
+ "product_tax_code": "42211500A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, and billed to Medicaid, equipment which is primarily and customarily used to provide or increase the ability to move from one place to another and which is appropriate for use either in a home or a motor vehicle; Is not generally used by persons with normal mobility; and Does not include any motor vehicle or equipment on a motor vehicle normally provided by a motor vehicle manufacturer. Examples include wheelchairs, crutches, canes, walkers, chair lifts, etc.",
+ "name": "Mobility Enhancing Equipment with Prescription Billed to Medicaid",
+ "product_tax_code": "42211500A0003"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicare, a machine used that filters a patient's blood to remove excess water and waste products when the kidneys are damaged, dysfunctional, or missing. The kidney dialysis machine is an artificial part which augments the natural functioning of the kidneys.",
+ "name": "Kidney Dialysis Equipment for home use with Prescription reimbursed by Medicare",
+ "product_tax_code": "42161800A0004"
+ },
+ {
+ "description": "At home digital or manual (aneroid) sphygmomanometers, also known as a blood pressure meter, blood pressure monitor, or blood pressure gauge, are devices used to measure blood pressure, composed of an inflatable cuff to collapse and then release the artery under the cuff in a controlled manner.",
+ "name": "Blood Pressure Testing Devices",
+ "product_tax_code": "42181600A0001"
+ },
+ {
+ "description": "A topical preparation containing a spermicidal lubricant to prevent pregnancy as indicated by a \"drug facts\" panel or a statement of active ingredients.",
+ "name": "Contraceptive Ointments",
+ "product_tax_code": "53131622A0002"
+ },
+ {
+ "description": "Male or female condoms used to prevent pregnacy or exposure to STDs.",
+ "name": "Condoms",
+ "product_tax_code": "53131622A0000"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicare, equipment that: can withstand repeated use; is primarily and customarily used to serve a medical purpose; generally is not useful to a person in the absence of illness or injury; and is not worn in or on the body. Home use means the equipment is sold to an individual for use at home, regardless of where the individual resides. Examples include hospital beds, commode chairs, bed pans, shower and bath aids, IV poles, etc.",
+ "name": "Durable Medical Equipment for home use with Prescription billed to Medicare",
+ "product_tax_code": "42140000A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicaid, a replacement, corrective, or supportive device, worn on or in the body to: Artificially replace a missing portion of the body; Prevent or correct physical deformity or malfunction; or Support a weak or deformed portion of the body. Worn in or on the body means that the item is implanted or attached so that it becomes part of the body, or is carried by the body and does not hinder the mobility of the individual. Examples include artificial limbs, pacemakers, orthotics, orthopedics, ostomy/colostomy devices, catheters, etc.",
+ "name": "Prosthetic Devices with Prescription Reimbursed by Medicaid",
+ "product_tax_code": "42242000A0005"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, and reimbursed by Medicare, equipment which is primarily and customarily used to provide or increase the ability to move from one place to another and which is appropriate for use either in a home or a motor vehicle; Is not generally used by persons with normal mobility; and Does not include any motor vehicle or equipment on a motor vehicle normally provided by a motor vehicle manufacturer. Examples include wheelchairs, crutches, canes, walkers, chair lifts, etc.",
+ "name": "Mobility Enhancing Equipment with Prescription Reimbursed by Medicare",
+ "product_tax_code": "42211500A0004"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicaid, nutritional tube feeding equipment including button-style feeding tubes, standard G-tubes, NG-tubes, extension sets, adapters, feeding pumps, feeding pump delivery sets.",
+ "name": "Enteral Feeding Equipment for home use with prescription billed to Medicaid",
+ "product_tax_code": "42231500A0003"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, nutritional tube feeding equipment including button-style feeding tubes, standard G-tubes, NG-tubes, extension sets, adapters, feeding pumps, feeding pump delivery sets.",
+ "name": "Enteral Feeding Equipment for home use with Prescription",
+ "product_tax_code": "42231500A0001"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicaid, a machine used that filters a patient's blood to remove excess water and waste products when the kidneys are damaged, dysfunctional, or missing. The kidney dialysis machine is an artificial part which augments the natural functioning of the kidneys.",
+ "name": "Kidney Dialysis Equipment for home use with Prescription billed to Medicaid",
+ "product_tax_code": "42161800A0003"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicaid, a machine used that filters a patient's blood to remove excess water and waste products when the kidneys are damaged, dysfunctional, or missing. The kidney dialysis machine is an artificial part which augments the natural functioning of the kidneys.",
+ "name": "Kidney Dialysis Equipment for home use with Prescription and reimbursed by Medicaid",
+ "product_tax_code": "42161800A0005"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, a machine used that filters a patient's blood to remove excess water and waste products when the kidneys are damaged, dysfunctional, or missing. The kidney dialysis machine is an artificial part which augments the natural functioning of the kidneys.",
+ "name": "Kidney Dialysis Equipment for home use with Prescription",
+ "product_tax_code": "42161800A0001"
+ },
+ {
+ "description": "Handbags, Purses",
+ "name": "Handbags, Purses",
+ "product_tax_code": "53121600A0000"
+ },
+ {
+ "description": "Video Gaming Console - Fixed",
+ "name": "Video Gaming Console - Fixed",
+ "product_tax_code": "52161557A0000"
+ },
+ {
+ "description": "Video Cameras",
+ "name": "Video Cameras",
+ "product_tax_code": "45121515A0000"
+ },
+ {
+ "description": "Portable audio equipment that records digital music for playback",
+ "name": "Digital Music Players",
+ "product_tax_code": "52161543A0000"
+ },
+ {
+ "description": "A type of consumer electronic device used to play vinyl recordings.",
+ "name": "Audio Turntables",
+ "product_tax_code": "52161548A0000"
+ },
+ {
+ "description": "Video Gaming Console - Portable",
+ "name": "Video Gaming Console - Portable",
+ "product_tax_code": "52161558A0000"
+ },
+ {
+ "description": "A framed display designed to display preloaded digital images (jpeg or any digital image format). Has slots for flash memory cards and/or an interface for digital photo camera connection.",
+ "name": "Digital Picture Frames",
+ "product_tax_code": "52161549A0000"
+ },
+ {
+ "description": "Digital Cameras",
+ "name": "Digital Cameras",
+ "product_tax_code": "45121504A0000"
+ },
+ {
+ "description": "Mobile Phones",
+ "name": "Mobile Phones",
+ "product_tax_code": "43191501A0000"
+ },
+ {
+ "description": "A digital wristwatch that provides many other features besides timekeeping. Like a smartphone, a smartwatch has a touchscreen display, which allows you to perform actions by tapping or swiping on the screen. Smartwatches include allow access to apps, similar to apps for smartphones and tablets.",
+ "name": "Watches - Smart",
+ "product_tax_code": "54111500A0001"
+ },
+ {
+ "description": "A bicycle helmet that is NOT marketed and labeled as being intended for youth.",
+ "name": "Bicycle Helmets - Adult",
+ "product_tax_code": "46181704A0003"
+ },
+ {
+ "description": "A bicycle helmet marketed and labeled as being intended for youth.",
+ "name": "Bicycle Helmets - Youth",
+ "product_tax_code": "46181704A0002"
+ },
+ {
+ "description": "Luggage",
+ "name": "Luggage",
+ "product_tax_code": "53121500A0000"
+ },
+ {
+ "description": "Clothing - Sleep or eye mask",
+ "name": "Clothing - Sleep or eye mask",
+ "product_tax_code": "53102607A0000"
+ },
+ {
+ "description": "Clothing - Pocket protectors",
+ "name": "Clothing - Pocket protectors",
+ "product_tax_code": "53102514A0000"
+ },
+ {
+ "description": "Clothing - Button covers",
+ "name": "Clothing - Button covers",
+ "product_tax_code": "53102515A0000"
+ },
+ {
+ "description": "Shoe Inserts/Insoles",
+ "name": "Clothing - Shoe Inserts/Insoles",
+ "product_tax_code": "46182208A0000"
+ },
+ {
+ "description": "Aprons - Household/Kitchen",
+ "name": "Clothing - Aprons - Household/Kitchen",
+ "product_tax_code": "46181501A0002"
+ },
+ {
+ "description": "Hunting Vests",
+ "name": "Clothing - Hunting Vests",
+ "product_tax_code": "53103100A0003"
+ },
+ {
+ "description": "Clothing apparel/uniforms that are specific to the training and competition of various martial arts.",
+ "name": "Clothing - Martial Arts Attire",
+ "product_tax_code": "53102717A0001"
+ },
+ {
+ "description": "Clothing - Umbrellas",
+ "name": "Clothing - Umbrellas",
+ "product_tax_code": "53102505A0000"
+ },
+ {
+ "description": "Briefcases",
+ "name": "Briefcases",
+ "product_tax_code": "53121701A0000"
+ },
+ {
+ "description": "Wallets",
+ "name": "Wallets",
+ "product_tax_code": "53121600A0001"
+ },
+ {
+ "description": "Wristwatch timepieces",
+ "name": "Watches",
+ "product_tax_code": "54111500A0000"
+ },
+ {
+ "description": "Jewelry",
+ "name": "Jewelry",
+ "product_tax_code": "54100000A0000"
+ },
+ {
+ "description": "Non-prescription sunglasses",
+ "name": "Sunglasses - Non-Rx",
+ "product_tax_code": "42142905A0001"
+ },
+ {
+ "description": "Wigs, Hairpieces, Hair extensions",
+ "name": "Clothing - Wigs, Hairpieces, Hair extensions",
+ "product_tax_code": "53102500A0002"
+ },
+ {
+ "description": "Hair notions, hair clips, barrettes, hair bows, hair nets, etc.",
+ "name": "Clothing - Hair Accessories",
+ "product_tax_code": "53102500A0001"
+ },
+ {
+ "description": "Clothing - Headbands",
+ "name": "Clothing - Headbands",
+ "product_tax_code": "53102513A0000"
+ },
+ {
+ "description": "These supplies contain medication such as an antibiotic ointment. They are a labeled with a \"drug facts\" panel or a statement of active ingredients. A wound care supply is defined as an item that is applied directly to or inside a wound to absorb wound drainage, protect healing tissue, maintain a moist or dry wound environment (as appropriate), or prevent bacterial contamination. Examples include bandages, dressings, gauze, medical tape. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Wound Care Supplies - Bandages, Dressings, Gauze - Medicated",
+ "product_tax_code": "42311514A0000"
+ },
+ {
+ "description": "A wound care supply is defined as an item that is applied directly to or inside a wound to absorb wound drainage, protect healing tissue, maintain a moist or dry wound environment (as appropriate), or prevent bacterial contamination. Examples include bandages, dressings, gauze, medical tape. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Wound Care Supplies - Bandages, Dressings, Gauze",
+ "product_tax_code": "42311500A0001"
+ },
+ {
+ "description": "Toothpaste containing \"drug facts\" panel or a statement of active ingredients. These products do contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Toothpaste",
+ "product_tax_code": "53131502A0000"
+ },
+ {
+ "description": "Disposable moistened cleansing wipes - non medicated. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Baby Wipes/Cleansing Wipes",
+ "product_tax_code": "53131624A0000"
+ },
+ {
+ "description": "Toilet Paper. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Toilet Paper",
+ "product_tax_code": "14111704A0000"
+ },
+ {
+ "description": "A lotion, spray, gel, foam, stick or other topical product that absorbs or reflects some of the sun's ultraviolet (UV) radiation and thus helps protect against sunburn. Sunscreen contains a \"drug facts\" label or statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Sunscreen",
+ "product_tax_code": "53131609A0000"
+ },
+ {
+ "description": "Soaps, body washes, shower gels for personal hygiene containing antibacterial. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Soaps - Antibacterial",
+ "product_tax_code": "53131608A0001"
+ },
+ {
+ "description": "Over-the-counter nicotine replacement products, including patches, gum, lozenges, sprays and inhalers. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Smoking Cessation Products",
+ "product_tax_code": "51143218A0000"
+ },
+ {
+ "description": "Lotions, moisturizers, creams, powders, sprays, etc that promote optimal skin health. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Skin Care Products- Medicated",
+ "product_tax_code": "51241200A0001"
+ },
+ {
+ "description": "A hair care product for cleansing the hair/scalp, with anti-dandruff active ingredients. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Shampoo - medicated (anti-dandruff)",
+ "product_tax_code": "53131628A0001"
+ },
+ {
+ "description": "A multi-purpose skin protectorant and topical ointment. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Petroleum Jelly",
+ "product_tax_code": "53131641A0000"
+ },
+ {
+ "description": "An over-the-counter drug via RX is a substance that contains a label identifying it as a drug and including a \"drug facts\" panel or a statement of active ingredients, that can be obtained without a prescription, but is sold under prescription order of a licensed professional. A drug can be intended for internal (ingestible, implant, injectable) or external (topical) application to the human body. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Over-the-Counter Drugs via Prescription",
+ "product_tax_code": "51030"
+ },
+ {
+ "description": "Flexible adhesive strips that attach over the bridge of the nose to lift the sides of the nose, opening the nasal passages to provide relief for congestion and snoring. The products are drug free and contain no active drug ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Nasal Breathing Strips",
+ "product_tax_code": "42312402A0001"
+ },
+ {
+ "description": "Therapeutic mouthwash, having active ingredients (such as antiseptic, or flouride) intended to help control or reduce conditions like bad breath, gingivitis, plaque, and tooth decay. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Mouthwash - Therapeutic",
+ "product_tax_code": "53131501A0000"
+ },
+ {
+ "description": "Multiple use medical thermometers for oral, temporal/forehead, or rectal body temperature diagnostics. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Medical Thermometers - Reusable",
+ "product_tax_code": "42182200A0002"
+ },
+ {
+ "description": "One-time use medical thermometers for oral, temporal/forehead, or rectal body temperature diagnostics. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Medical Thermometers - Disposable",
+ "product_tax_code": "42182200A0001"
+ },
+ {
+ "description": "Masks designed for one-time use to protect the wearer from contamination of breathable particles. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Medical Masks",
+ "product_tax_code": "42131713A0001"
+ },
+ {
+ "description": "A medicated skin protectorant for the lips. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Lip Balm - Medicated",
+ "product_tax_code": "53131630A0001"
+ },
+ {
+ "description": "A skin protectorant for the lips. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Lip Balm",
+ "product_tax_code": "53131630A0000"
+ },
+ {
+ "description": "Artificial devices to correct or alleviate hearing deficiencies, sold under prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hearing Aids with Prescription",
+ "product_tax_code": "42211705A0000"
+ },
+ {
+ "description": "Artificial deives to correct or alleviate hearing deficiencies, sold without a prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hearing Aids without Prescription",
+ "product_tax_code": "42211705A0001"
+ },
+ {
+ "description": "Batteries specifically labeled and designed to operate hearing aid devices, sold under prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hearing Aid Batteries with Prescription",
+ "product_tax_code": "26111710A0001"
+ },
+ {
+ "description": "Batteries specifically labeled and designed to operate hearing aid devices, sold without a prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hearing Aid Batteries without Prescription",
+ "product_tax_code": "26111710A0002"
+ },
+ {
+ "description": "A liquid, gel, foam, or wipe generally used to decrease infectious agents on the hands. Alcohol-based versions typically contain some combination of isopropyl alcohol, ethanol (ethyl alcohol), or n-propanol. Alcohol-free products are generally based on disinfectants, or on antimicrobial agents. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hand Sanitizers",
+ "product_tax_code": "53131626A0000"
+ },
+ {
+ "description": "Topical foams, creams, gels, etc that prevent hair loss and promote hair regrowth. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hair Loss Products",
+ "product_tax_code": "51182001A0001"
+ },
+ {
+ "description": "A collection of mixed supplies and equipment that is used to give medical treatment, often housed in durable plastic boxes, fabric pouches or in wall mounted cabinets. Exempt or low rated qualifying medicinal items (eg. OTC drugs) make up 51% or more of the value of the kit. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "First Aid Kits - 51% or more medicinal items",
+ "product_tax_code": "42172001A0002"
+ },
+ {
+ "description": "A collection of mixed supplies and equipment that is used to give medical treatment, often housed in durable plastic boxes, fabric pouches or in wall mounted cabinets. Exempt or low rated qualifying medicinal items (eg. OTC drugs) make up 50% or less of the value of the kit. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "First Aid Kits - 50% or less medicinal items",
+ "product_tax_code": "42172001A0001"
+ },
+ {
+ "description": "Over-the-counter antifungal creams, ointments or suppositories to treat yeast infections, containing a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Feminine Yeast Treatments",
+ "product_tax_code": "51302300A0001"
+ },
+ {
+ "description": "Vaginal cleaning products include douches and wipes with medication such as an antiseptic, containing a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Feminine Cleansing Solutions - Medicated",
+ "product_tax_code": "53131615A0002"
+ },
+ {
+ "description": "Vaginal cleaning products include douches and wipes. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Feminine Cleansing Solutions",
+ "product_tax_code": "53131615A0001"
+ },
+ {
+ "description": "Single use disposable gloves (latex, nitrile, vinyl, etc) that while appropriate for multiple uses, have an application in a first aid or medical setting. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Disposable Gloves",
+ "product_tax_code": "42132203A0000"
+ },
+ {
+ "description": "Personal under-arm deodorants/antiperspirants. These products do contain a \"drug facts\" panel or a statement of active ingredients, typically aluminum. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Deodorant/Antiperspirant",
+ "product_tax_code": "53131606A0000"
+ },
+ {
+ "description": "Denture adhesives are pastes, powders or adhesive pads that may be placed in/on dentures to help them stay in place. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Denture creams/adhesives",
+ "product_tax_code": "53131510A0000"
+ },
+ {
+ "description": "Toothbrushes. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Toothbrushes",
+ "product_tax_code": "53131503A0000"
+ },
+ {
+ "description": "Dental Floss/picks. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Dental Floss/picks",
+ "product_tax_code": "53131504A0000"
+ },
+ {
+ "description": "Single use cotton balls or swabs for multi-purpose use other than applying medicines and cleaning wounds, due to not being sterile. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Cotton Balls/Swabs - Unsterile",
+ "product_tax_code": "42141500A0002"
+ },
+ {
+ "description": "Single use cotton balls or swabs for application of antiseptics and medications and to cleanse scratches, cuts or minor wounds. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Cotton Balls/Swabs - Sterile",
+ "product_tax_code": "42141500A0001"
+ },
+ {
+ "description": "Corrective lenses, eyeglasses, sold under prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Corrective Lenses, Eyeglasses with Prescription",
+ "product_tax_code": "42142900A0001"
+ },
+ {
+ "description": "Corrective lenses, including eyeglasses and contact lenses, sold without a prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Corrective Lenses without Prescription",
+ "product_tax_code": "42142900A0002"
+ },
+ {
+ "description": "Liquid solution for lubricating/rewetting, but not disinfecting, contact lenses. This solution is applied directly to the lens, rather then inserted into the eye. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Contact Lens Lubricating Solutions - For lens",
+ "product_tax_code": "42142914A0001"
+ },
+ {
+ "description": "Liquid solution for lubricating/rewetting, but not disinfecting, contact lenses. This solution is applied directly to the eye. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Contact Lens Lubricating Solutions - For eyes",
+ "product_tax_code": "42142914A0002"
+ },
+ {
+ "description": "Contact lenses, sold under prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Contact Lenses with Prescription",
+ "product_tax_code": "42142913A0000"
+ },
+ {
+ "description": "Liquid solution for cleaning and disinfecting contact lenses. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Contact Lens Disinfecting Solutions",
+ "product_tax_code": "42142914A0000"
+ },
+ {
+ "description": "A reusable pain management supply that includes artificial ice packs, gel packs, heat wraps, etc used for pain relief. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Cold or Hot Therapy Packs - Reusable",
+ "product_tax_code": "42142100A0002"
+ },
+ {
+ "description": "A heating pad is a pad used for warming of parts of the body in order to manage pain. Types of heating pads include electrical, chemical and hot water bottles. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Heating Pads",
+ "product_tax_code": "42142100A0001"
+ },
+ {
+ "description": "A single use pain management supply that includes artificial ice packs, gel packs, heat wraps, etc used for pain relief. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Cold or Hot Therapy Packs - Disposable - Medicated",
+ "product_tax_code": "42142100A0004"
+ },
+ {
+ "description": "A single use pain management supply that includes artificial ice packs, gel packs, heat wraps, etc used for pain relief. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Cold or Hot Therapy Packs - Disposable",
+ "product_tax_code": "42142100A0003"
+ },
+ {
+ "description": "Baby powder is an astringent powder used for preventing diaper rash, as a spray, and for other cosmetic uses. It may be composed of talcum (in which case it is also called talcum powder) or corn starch. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Baby Powder",
+ "product_tax_code": "53131649A0001"
+ },
+ {
+ "description": "Baby oil is an inert (typically mineral) oil for the purpose of keeping skin soft and supple. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Baby Oil",
+ "product_tax_code": "51241900A0001"
+ },
+ {
+ "description": "A cosmetic foam or gel used for shaving preparation. The purpose of shaving cream is to soften the hair by providing lubrication. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Shaving Creams",
+ "product_tax_code": "53131611A0000"
+ },
+ {
+ "description": "Personal under-arm deodorants/antiperspirants containing natural ingredients and/or ingredients that are not considered drugs. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Deodorant - Natural or no active ingredients",
+ "product_tax_code": "53131606A0001"
+ },
+ {
+ "description": "A hair care product for cleansing the hair/scalp. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Shampoo",
+ "product_tax_code": "53131628A0000"
+ },
+ {
+ "description": "Various surfactant preparations to improve cleaning, enhance the enjoyment of bathing, and serve as a vehicle for cosmetic agents. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Bubble Bath, Bath Salts/Oils/Crystals",
+ "product_tax_code": "53131612A0001"
+ },
+ {
+ "description": "Cosmetic mouthwash may temporarily control bad breath and leave behind a pleasant taste, but has no chemical or biological application beyond their temporary benefit. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Mouthwash - Cosmetic",
+ "product_tax_code": "53131501A0001"
+ },
+ {
+ "description": "Teeth whitening gels, rinse, strips, trays, etc containing bleaching agents. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Teeth Whitening Kits",
+ "product_tax_code": "42151506A0000"
+ },
+ {
+ "description": "A hair care product typically applied and rinsed after shampooing that is used to improve the feel, appearance and manageability of hair. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Conditioner - Hair",
+ "product_tax_code": "53131628A0002"
+ },
+ {
+ "description": "Depilatories are cosmetic preparations used to remove hair from the skin. Chemical depilatories are available in gel, cream, lotion, aerosol, roll-on, and powder forms. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hair Removal Products",
+ "product_tax_code": "53131623A0000"
+ },
+ {
+ "description": "Breath spray is a product sprayed into the mouth and breath strips dissolve in the mouth for the purpose of eliminating halitosis. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Breath Spray/dissolvable strips",
+ "product_tax_code": "53131509A0000"
+ },
+ {
+ "description": "Lotions, moisturizers, creams, powders, sprays, etc that promote optimal skin health. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Skin Care Products",
+ "product_tax_code": "51241200A0002"
+ },
+ {
+ "description": "Liquid drops to be placed inside the ear canal to reduce the symptoms of an ear ache, or to act as an ear drying aid, or to loosen, cleanse, and aid in the removal of ear wax. These products contain a \"drug facts\" panel or a statement of active ingredients. Examples include Ear Ache, Swimmers' Ears, and Ear Wax removal drops. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Ear Drops - Medicated",
+ "product_tax_code": "51241000A0001"
+ },
+ {
+ "description": "Topical medicated solutions for treating skin acne. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Acne Treatments",
+ "product_tax_code": "51241400A0001"
+ },
+ {
+ "description": "A skin cream forming a protective barrier to help heal and soothe diaper rash discomfort. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Diaper Cream",
+ "product_tax_code": "51241859A0001"
+ },
+ {
+ "description": "A liquid solution typically used as a topical antiseptic. The products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Isopropyl (Rubbing) Alcohol",
+ "product_tax_code": "51471901A0000"
+ },
+ {
+ "description": "Hydrogen peroxide is a mild antiseptic used on the skin to prevent infection of minor cuts, scrapes, and burns. It may also be used as a mouth rinse to help remove mucus or to relieve minor mouth irritation (e.g., due to canker/cold sores, gingivitis). These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hydrogen Peroxide",
+ "product_tax_code": "51473503A0000"
+ },
+ {
+ "description": "Articles intended to be rubbed, poured, sprinkled, or sprayed on, introduced into, or otherwise applied to the human body or any part thereof for beautifying, promoting attractiveness, or altering the appearance. This category supports only the following items: Acrylic fingernail glue, Acrylic fingernails, Artificial eyelashes, Blush, Bronzer, Body glitter, Concealer, Eyelash glue, Finger/toenail decorations, Finger/toenail polish, Nail polish remover, Hair coloring, Hair mousse/gel, Hair oil, Hair spray, Hair relaxer, Hair wave treatment, Hair wax, Lip gloss, Lip liner, Lipstick, Liquid foundation, Makeup, Mascara, Nail polish remover, Powder foundation, Cologne, Perfume. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Cosmetics - Beautifying",
+ "product_tax_code": "53131619A0001"
+ },
+ {
+ "description": "Power cords",
+ "name": "Power cords",
+ "product_tax_code": "26121636A0000"
+ },
+ {
+ "description": "Archery accessories including quivers, releases, arrow shafts, armguards, hunting belts, bow parts, cleaning products, mounted safety equipment, scopes, sights, hunting slings, string wax, targets, target throwers, etc.",
+ "name": "Archery Accessories",
+ "product_tax_code": "49181602A0002"
+ },
+ {
+ "description": "Landscape soil, mulch, compost - residential",
+ "name": "Landscape Soil, Mulch, Compost - Residential",
+ "product_tax_code": "11121700A0001"
+ },
+ {
+ "description": "Firearms, limited to pistols, revolvers, rifles with a barrel no greater than an internal diameter of .50 caliber or a shotguns of 10 gauge or smaller.",
+ "name": "Firearms",
+ "product_tax_code": "46101500A0001"
+ },
+ {
+ "description": "Firearm accessories including repair parts, cleaning products, holsters, mounted safety equipment, choke tubes, scopes, shooting tripod/bipod/monopod, shooting bags/pouches, sights, etc.",
+ "name": "Firearm Accessories",
+ "product_tax_code": "46101506A0001"
+ },
+ {
+ "description": "Portable fuel container",
+ "name": "Portable Fuel Container",
+ "product_tax_code": "24111808A0001"
+ },
+ {
+ "description": "Hard and soft cases designed specifically for firearms equipment",
+ "name": "Gun Cases",
+ "product_tax_code": "46101801A0000"
+ },
+ {
+ "description": "Primary archery equipment including bows, crossbow, and bow strings.",
+ "name": "Archery Equipment",
+ "product_tax_code": "49181602A0001"
+ },
+ {
+ "description": "Hard and soft cases designed specifically for archery equipment.",
+ "name": "Archery Cases",
+ "product_tax_code": "46101801A0001"
+ },
+ {
+ "description": "Protective earmuffs to muffle the sound of gunfire.",
+ "name": "Hearing Protection Earmuffs",
+ "product_tax_code": "46181902A0001"
+ },
+ {
+ "description": "Ammunition for firearms with a barrel no greater than an internal diameter of .50 caliber or a shotgun of 10 gauge or smaller., including bullets, shotgun shells, and gunpowder.",
+ "name": "Ammunition",
+ "product_tax_code": "46101600A0001"
+ },
+ {
+ "description": "Bedclothes items including sheets, pillow cases, bedspreads, comforters, blankets, throws, duvet covers, pillow shams, bed skirts, mattress pad, mattress toppers, and pillows.",
+ "name": "Bedding",
+ "product_tax_code": "52121500A0000"
+ },
+ {
+ "description": "Towels used for individual drying of persons, including bath towels, beach towels, wash cloths, hand towels, fact towels, sport towels, etc.",
+ "name": "Bath towels",
+ "product_tax_code": "52121700A0000"
+ },
+ {
+ "description": "WaterSense labeled urinals.",
+ "name": "Urinals - WaterSense",
+ "product_tax_code": "30181506A0000"
+ },
+ {
+ "description": "WaterSense labeled toilets.",
+ "name": "Toilets - WaterSense",
+ "product_tax_code": "30181505A0000"
+ },
+ {
+ "description": "WaterSense labeled irrigation controllers, which act like a thermostat for your sprinkler system telling it when to turn on and off, use local weather and landscape conditions to tailor watering schedules to actual conditions on the site.",
+ "name": "Irrigation Controls - WaterSense",
+ "product_tax_code": "21102503A0001"
+ },
+ {
+ "description": "Ceiling Fans carrying an Energy Star rating.",
+ "name": "Ceiling fans - Energy Star",
+ "product_tax_code": "40101609A0000"
+ },
+ {
+ "description": "Standard incandescent light bulbs carrying an Energy Star rating.",
+ "name": "Incandescent Light Bulbs - Energy Star",
+ "product_tax_code": "39101612A0001"
+ },
+ {
+ "description": "Compact Fluorescent light (CFL) bulbs carrying an Energy Star rating.",
+ "name": "Compact Fluorescent Light Bulbs - Energy Star",
+ "product_tax_code": "39101619A0001"
+ },
+ {
+ "description": "Domestic appliance carrying an Energy Star Rating which reduces and maintains the level of humidity in the air.",
+ "name": "Dehumidifier - Energy Star",
+ "product_tax_code": "40101902A0000"
+ },
+ {
+ "description": "Domestic air conditioning (central or room) systems carrying Energy Star rating.",
+ "name": "Air conditioners - Energy Star",
+ "product_tax_code": "40101701A0000"
+ },
+ {
+ "description": "Artificial ice, blue ice, ice packs, reusable ice",
+ "name": "Artificial Ice",
+ "product_tax_code": "24121512A0000"
+ },
+ {
+ "description": "A port replicator is an attachment for a notebook computer that allows a number of devices such as a printer, large monitor, and keyboard to be simultaneously connected.",
+ "name": "Port Replicators",
+ "product_tax_code": "43211603A0000"
+ },
+ {
+ "description": "Computer Mouse/Pointing Devices",
+ "name": "Computer Mouse/Pointing Devices",
+ "product_tax_code": "43211708A0000"
+ },
+ {
+ "description": "Storage drives, hard drives, Zip drives, etc.",
+ "name": "Computer Drives",
+ "product_tax_code": "43201800A0001"
+ },
+ {
+ "description": "An in home programmable thermostat, such as a WiFi enabled smart thermostat, carrying an Energy Star rating.",
+ "name": "Programmable Wall Thermostat - Energy Star",
+ "product_tax_code": "41112209A0001"
+ },
+ {
+ "description": "Domestic gas or oil boilers for space or water heating carrying an Energy Star rating.",
+ "name": "Boilers - Energy Star",
+ "product_tax_code": "40102004A0001"
+ },
+ {
+ "description": "Domestic water heater carrying Energy Star rating.",
+ "name": "Water heater - Energy Star",
+ "product_tax_code": "40101825A0000"
+ },
+ {
+ "description": "Domestic freezers carrying Energy Star rating.",
+ "name": "Freezers- Energy Star",
+ "product_tax_code": "52141506A0000"
+ },
+ {
+ "description": "Domestic air source heat pumps carrying Energy Star rating.",
+ "name": "Heat Pumps - Energy Star",
+ "product_tax_code": "40101806A0000"
+ },
+ {
+ "description": "Domestic gas or oil furnaces carrying an Energy Star rating.",
+ "name": "Furnaces - Energy Star",
+ "product_tax_code": "40101805A0000"
+ },
+ {
+ "description": "Plywood, window film, storm shutters, hurricane shutters or other materials specifically designed to protect windows.",
+ "name": "Storm shutters/window protection devices",
+ "product_tax_code": "30151801A0001"
+ },
+ {
+ "description": "Smoke Detectors",
+ "name": "Smoke Detectors",
+ "product_tax_code": "46191501A0000"
+ },
+ {
+ "description": "Mobile phone charging device/cord",
+ "name": "Mobile Phone Charging Device/cord",
+ "product_tax_code": "43191501A0002"
+ },
+ {
+ "description": "A webcam is a video camera that feeds or streams an image or video in real time to or through a computer to a computer network, such as the Internet. Webcams are typically small cameras that sit on a desk, attach to a user's monitor, or are built into the hardware",
+ "name": "Web Camera",
+ "product_tax_code": "45121520A0000"
+ },
+ {
+ "description": "A sound card is an expansion component used in computers to receive and send audio.",
+ "name": "Sound Cards",
+ "product_tax_code": "43201502A0000"
+ },
+ {
+ "description": "Computer Speakers",
+ "name": "Computer Speakers",
+ "product_tax_code": "43211607A0000"
+ },
+ {
+ "description": "Computer Microphones",
+ "name": "Computer Microphones",
+ "product_tax_code": "43211719A0000"
+ },
+ {
+ "description": "A docking station is a hardware frame and set of electrical connection interfaces that enable a notebook computer to effectively serve as a desktop computer.",
+ "name": "Docking Stations",
+ "product_tax_code": "43211602A0000"
+ },
+ {
+ "description": "Computer Batteries",
+ "name": "Computer Batteries",
+ "product_tax_code": "26111711A0001"
+ },
+ {
+ "description": "Computer Monitor/Displays",
+ "name": "Computer Monitor/Displays",
+ "product_tax_code": "43211900A0000"
+ },
+ {
+ "description": "Computer Keyboards",
+ "name": "Computer Keyboards",
+ "product_tax_code": "43211706A0000"
+ },
+ {
+ "description": "Printer Ink",
+ "name": "Printer Ink",
+ "product_tax_code": "44103105A0000"
+ },
+ {
+ "description": "Printer Paper",
+ "name": "Printer Paper",
+ "product_tax_code": "14111507A0000"
+ },
+ {
+ "description": "Non-electric can opener",
+ "name": "Can opener - manual",
+ "product_tax_code": "52151605A0001"
+ },
+ {
+ "description": "Sheet music - Student",
+ "name": "Sheet music - Student",
+ "product_tax_code": "55101514A0000"
+ },
+ {
+ "description": "Musical instruments - Student",
+ "name": "Musical instruments - Student",
+ "product_tax_code": "60130000A0001"
+ },
+ {
+ "description": "Reference printed material commonly used by a student in a course of study as a reference and to learn the subject being taught.",
+ "name": "Dictionaries/Thesauruses",
+ "product_tax_code": "55101526A0001"
+ },
+ {
+ "description": "An item commonly used by a student in a course of study for artwork. This category is limited to the following items...clay and glazes, paints, paintbrushes for artwork, sketch and drawing pads, watercolors.",
+ "name": "School Art Supplies",
+ "product_tax_code": "60121200A0001"
+ },
+ {
+ "description": "A calendar based notebook to aid in outlining one's daily appointments, classes, activities, etc.",
+ "name": "Daily Planners",
+ "product_tax_code": "44112004A0001"
+ },
+ {
+ "description": "Portable self-powered or battery powered radio, two-way radio, weatherband radio.",
+ "name": "Portable Radios",
+ "product_tax_code": "43191510A0000"
+ },
+ {
+ "description": "Single or multi-pack AA, AAA, c, D, 6-volt or 9-volt batteries, excluding automobile or boat batteries.",
+ "name": "Alkaline Batteries",
+ "product_tax_code": "26111702A0000"
+ },
+ {
+ "description": "Routers",
+ "name": "Routers",
+ "product_tax_code": "43222609A0000"
+ },
+ {
+ "description": "Removable storage media such as compact disks, flash drives, thumb drives, flash memory cards.",
+ "name": "Computer Storage Media",
+ "product_tax_code": "43202000A0000"
+ },
+ {
+ "description": "Computer Printer",
+ "name": "Computer Printer",
+ "product_tax_code": "43212100A0001"
+ },
+ {
+ "description": "Portable self-powered or battery powered light sources, including flashlights, lanterns, emergency glow sticks or light sticks.",
+ "name": "Portable Light Sources",
+ "product_tax_code": "39111610A0000"
+ },
+ {
+ "description": "Canned software on tangible media that is used for non-recreational purposes, such as Antivirus, Database, Educational, Financial, Word processing, etc.",
+ "name": "Software - Prewritten, tangible media - Non-recreational",
+ "product_tax_code": "43230000A1101"
+ },
+ {
+ "description": "Personal computers, including laptops, tablets, desktops.",
+ "name": "Personal Computers",
+ "product_tax_code": "43211500A0001"
+ },
+ {
+ "description": "A device that joins pages of paper or similar material by fastening a thin metal staple through the sheets and folding the ends underneath.",
+ "name": "Staplers/Staples",
+ "product_tax_code": "44121615A0000"
+ },
+ {
+ "description": "Pins/tacks to secure papers, pictures, calendars, etc. to bulletin boards, walls, etc.",
+ "name": "Push pins/tacks",
+ "product_tax_code": "44122106A0000"
+ },
+ {
+ "description": "Bags/packs designed to carry students' books during the school day. This category does not include backpags for traveling, hiking, camping, etc.",
+ "name": "Bookbags/Backpacks - Student",
+ "product_tax_code": "53121603A0001"
+ },
+ {
+ "description": "Ground anchor systems and tie down kits for securing property against severe weather.",
+ "name": "Ground Anchor Systems and Tie-down Kits",
+ "product_tax_code": "31162108A0000"
+ },
+ {
+ "description": "An expansion card that allows the computer to send graphical information to a video display device such as a monitor, TV, or projector. Video cards are often used by gamers in place of integrated graphics due to their extra processing power and video ram.",
+ "name": "Video/Graphics Card",
+ "product_tax_code": "43201401A0000"
+ },
+ {
+ "description": "Scanners",
+ "name": "Scanners",
+ "product_tax_code": "43211711A0000"
+ },
+ {
+ "description": "Modems",
+ "name": "Modems",
+ "product_tax_code": "43222628A0000"
+ },
+ {
+ "description": "A map that could be used by a student in a course of study as a reference and to learn the subject being taught.",
+ "name": "Maps - Student",
+ "product_tax_code": "60103410A0001"
+ },
+ {
+ "description": "Tarps, plastic sheeting, plastic drop cloths, waterproof sheeting.",
+ "name": "Tarpaulins and Weatherproof Sheeting",
+ "product_tax_code": "24141506A0000"
+ },
+ {
+ "description": "Portable generator used to provide light or communications or power appliances during a power outage.",
+ "name": "Portable Generator",
+ "product_tax_code": "26111604A0001"
+ },
+ {
+ "description": "Headphones/Earbuds",
+ "name": "Headphones/Earbuds",
+ "product_tax_code": "52161514A0000"
+ },
+ {
+ "description": "A portable electronic device for reading digital books and periodicals.",
+ "name": "E-Book Readers",
+ "product_tax_code": "43211519A0000"
+ },
+ {
+ "description": "Mobile phone batteries",
+ "name": "Mobile Phone Batteries",
+ "product_tax_code": "43191501A0001"
+ },
+ {
+ "description": "A globe that could be used by a student in a course of study as a reference and to learn the subject being taught.",
+ "name": "Globes - Student",
+ "product_tax_code": "60104414A0001"
+ },
+ {
+ "description": "Domestic standard size refrigerators carrying Energy Star rating.",
+ "name": "Refrigerators - Energy Star",
+ "product_tax_code": "52141501A0000"
+ },
+ {
+ "description": "Non-electric food or beverage cooler.",
+ "name": "Food Storage Cooler",
+ "product_tax_code": "52152002A0001"
+ },
+ {
+ "description": "A motherboard is the physical component in a computer that contains the computer's basic circuitry and other components",
+ "name": "Motherboards",
+ "product_tax_code": "43201513A0000"
+ },
+ {
+ "description": "Calculators",
+ "name": "Calculators",
+ "product_tax_code": "44101807A0000"
+ },
+ {
+ "description": "Axes/Hatchets",
+ "name": "Axes/Hatchets",
+ "product_tax_code": "27112005A0000"
+ },
+ {
+ "description": "Water conserving products are for conserving or retaining groundwater; recharging water tables; or decreasing ambient air temperature, and so limiting water evaporation. Examples include soil sufactants, a soaker or drip-irrigation hose, a moisture control for a sprinkler or irrigation system, a rain barrel or an alternative rain and moisture collection system, a permeable ground cover surface that allows water to reach underground basins, aquifers or water collection points.",
+ "name": "Water Conserving Products",
+ "product_tax_code": "21102500A0001"
+ },
+ {
+ "description": "Domestic clothes drying appliances carrying Energy Star rating.",
+ "name": "Clothes drying machine - Energy Star",
+ "product_tax_code": "52141602A0000"
+ },
+ {
+ "description": "Software - Prewritten, electronic delivery - Business Use",
+ "name": "Software - Prewritten, electronic delivery - Business Use",
+ "product_tax_code": "43230000A9200"
+ },
+ {
+ "description": "Software - Custom, electronic delivery - Business Use",
+ "name": "Software - Custom, electronic delivery - Business Use",
+ "product_tax_code": "43230000A9201"
+ },
+ {
+ "description": "Food and Beverage - Sugar and Sugar Substitutes",
+ "name": "Food and Beverage - Sugar and Sugar Substitutes",
+ "product_tax_code": "50161900A0000"
+ },
+ {
+ "description": "Food and Beverage - Eggs and egg products",
+ "name": "Food and Beverage - Eggs and egg products",
+ "product_tax_code": "50131600A0000"
+ },
+ {
+ "description": "Food and Beverage - Coffee, coffee substitutes and tea",
+ "name": "Food and Beverage - Coffee, coffee substitutes and tea",
+ "product_tax_code": "50201700A0000"
+ },
+ {
+ "description": "Food and Beverage - Candy",
+ "name": "Food and Beverage - Candy",
+ "product_tax_code": "50161800A0000"
+ },
+ {
+ "description": "Food and Beverage - Butter, Margarine, Shortening and Cooking Oils",
+ "name": "Food and Beverage - Butter, Margarine, Shortening and Cooking Oils",
+ "product_tax_code": "50151500A0000"
+ },
+ {
+ "description": "Clothing - Facial shields",
+ "name": "Clothing - Facial shields",
+ "product_tax_code": "46181702A0001"
+ },
+ {
+ "description": "Clothing - Hard hats",
+ "name": "Clothing - Hard hats",
+ "product_tax_code": "46181701A0001"
+ },
+ {
+ "description": "Clothing - Cleanroom footwear",
+ "name": "Clothing - Cleanroom footwear",
+ "product_tax_code": "46181603A0001"
+ },
+ {
+ "description": "Clothing - Fire retardant footwear",
+ "name": "Clothing - Fire retardant footwear",
+ "product_tax_code": "46181601A0001"
+ },
+ {
+ "description": "Clothing - Protective pants",
+ "name": "Clothing - Protective pants",
+ "product_tax_code": "46181527A0001"
+ },
+ {
+ "description": "Clothing - Garters",
+ "name": "Clothing - Garters",
+ "product_tax_code": "53102509A0000"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered electronically (includes support services only - no updates/upgrades)",
+ "name": "Software maintenance and support - Optional, custom, electronic delivery (support services only)",
+ "product_tax_code": "81112200A2222"
+ },
+ {
+ "description": "Software maintenance and support - Mandatory maintenance and support charges for prewritten software including items delivered by load and leave",
+ "name": "Software maintenance and support - Mandatory, prewritten, load and leave delivery",
+ "product_tax_code": "81112200A1310"
+ },
+ {
+ "description": "Software maintenance and support - Mandatory maintenance and support charges for prewritten software including items delivered electronically",
+ "name": "Software maintenance and support - Mandatory, prewritten, electronic delivery",
+ "product_tax_code": "81112200A1210"
+ },
+ {
+ "description": "Electronic software documentation or user manuals - For prewritten software & delivered electronically",
+ "name": "Electronic software documentation or user manuals - Prewritten, electronic delivery",
+ "product_tax_code": "55111601A1200"
+ },
+ {
+ "description": "Clothing - Fur Ear muffs or scarves",
+ "name": "Clothing - Fur Ear muffs or scarves",
+ "product_tax_code": "53102502A0001"
+ },
+ {
+ "description": "Clothing - Safety glasses",
+ "name": "Clothing - Safety glasses",
+ "product_tax_code": "46181802A0001"
+ },
+ {
+ "description": "Software - Prewritten & delivered on tangible media",
+ "name": "Software - Prewritten, tangible media",
+ "product_tax_code": "43230000A1100"
+ },
+ {
+ "description": "Mainframe administration services\r\n",
+ "name": "Mainframe administration services\r\n",
+ "product_tax_code": "81111802A0000"
+ },
+ {
+ "description": "Co-location service",
+ "name": "Co-location service",
+ "product_tax_code": "81111814A0000"
+ },
+ {
+ "description": "Information management system for mine action IMSMA\r\n",
+ "name": "Information management system for mine action IMSMA\r\n",
+ "product_tax_code": "81111710A0000"
+ },
+ {
+ "description": "Local area network LAN maintenance or support",
+ "name": "Local area network LAN maintenance or support",
+ "product_tax_code": "81111803A0000"
+ },
+ {
+ "description": "Data center services",
+ "name": "Data center services",
+ "product_tax_code": "81112003A0000"
+ },
+ {
+ "description": "Wide area network WAN maintenance or support",
+ "name": "Wide area network WAN maintenance or support",
+ "product_tax_code": "81111804A0000"
+ },
+ {
+ "description": "Electronic data interchange EDI design\r\n",
+ "name": "Electronic data interchange EDI design\r\n",
+ "product_tax_code": "81111703A0000"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for prewritten software including items delivered on tangible media (includes support services only - no updates/upgrades)",
+ "name": "Software maintenance and support - Optional, prewritten, tangible media (support services only)",
+ "product_tax_code": "81112200A1122"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for prewritten software including items delivered on tangible media (includes software updates/upgrades)",
+ "name": "Software maintenance and support - Optional, prewritten, tangible media (incl. updates/upgrades)",
+ "product_tax_code": "81112200A1121"
+ },
+ {
+ "description": "Clothing - Safety sleeves",
+ "name": "Clothing - Safety sleeves",
+ "product_tax_code": "46181516A0001"
+ },
+ {
+ "description": "Clothing - Fire retardant apparel",
+ "name": "Clothing - Fire retardant apparel",
+ "product_tax_code": "46181508A0001"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for prewritten software including items delivered by load and leave (includes support services only - no updates/upgrades)",
+ "name": "Software maintenance and support - Optional, prewritten, load and leave delivery (support services only)",
+ "product_tax_code": "81112200A1322"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for prewritten software including items delivered by load and leave (includes software updates/upgrades)",
+ "name": "Software maintenance and support - Optional, prewritten, load and leave delivery (incl. updates/upgrades)",
+ "product_tax_code": "81112200A1321"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for prewritten software including items delivered electronically (includes support services only - no updates/upgrades)",
+ "name": "Software maintenance and support - Optional, prewritten, electronic delivery (support services only)",
+ "product_tax_code": "81112200A1222"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered on tangible media (includes support services only - no updates/upgrades)",
+ "name": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered on tangible media (includes support services only - no updates/upgrades)\r\n",
+ "product_tax_code": "81112200A2122"
+ },
+ {
+ "description": "Clothing - Protective ponchos",
+ "name": "Clothing - Protective ponchos",
+ "product_tax_code": "46181506A0001"
+ },
+ {
+ "description": "Clothing - Protective gloves",
+ "name": "Clothing - Protective gloves",
+ "product_tax_code": "46181504A0001"
+ },
+ {
+ "description": "Clothing - Synthetic Fur Vest",
+ "name": "Clothing - Synthetic Fur Vest",
+ "product_tax_code": "53103100A0002"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered on tangible media (includes software updates/upgrades)",
+ "name": "Software maintenance and support - Optional, custom, tangible media (incl. updates/upgrades)",
+ "product_tax_code": "81112200A2121"
+ },
+ {
+ "description": "Computer graphics service\r\n",
+ "name": "Computer graphics service\r\n",
+ "product_tax_code": "81111512A0000"
+ },
+ {
+ "description": "Proprietary or licensed systems maintenance or support",
+ "name": "Proprietary or licensed systems maintenance or support",
+ "product_tax_code": "81111805A0000"
+ },
+ {
+ "description": "Software - Prewritten & delivered electronically",
+ "name": "Software - Prewritten, electronic delivery",
+ "product_tax_code": "43230000A1200"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for prewritten software including items delivered electronically (includes software updates/upgrades)",
+ "name": "Software maintenance and support - Optional, prewritten, electronic delivery (incl. updates/upgrades)",
+ "product_tax_code": "81112200A1221"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered by load and leave (includes support services only - no updates/upgrades)",
+ "name": "Software maintenance and support - Optional, custom, load and leave delivery (support services only)",
+ "product_tax_code": "81112200A2322"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered by load and leave (includes software updates/upgrades)",
+ "name": "Software maintenance and support - Optional, custom, load and leave delivery (incl. updates/upgrades)",
+ "product_tax_code": "81112200A2321"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered electronically (includes software updates/upgrades)",
+ "name": "Software maintenance and support - Optional, custom, electronic delivery (incl. updates/upgrades)",
+ "product_tax_code": "81112200A2221"
+ },
+ {
+ "description": "Software maintenance and support - Mandatory maintenance and support charges for custom software including items delivered on tangible media",
+ "name": "Software maintenance and support - Mandatory, custom, tangible media",
+ "product_tax_code": "81112200A2110"
+ },
+ {
+ "description": "Software maintenance and support - Mandatory maintenance and support charges for custom software including items delivered electronically",
+ "name": "Software maintenance and support - Mandatory, custom, electronic delivery",
+ "product_tax_code": "81112200A2210"
+ },
+ {
+ "description": "Food and Beverage - Fish and seafood",
+ "name": "Food and Beverage - Fish and seafood",
+ "product_tax_code": "50121500A0000"
+ },
+ {
+ "description": "Food and Beverage - Ice cubes",
+ "name": "Food and Beverage - Ice cubes",
+ "product_tax_code": "50202302A0000"
+ },
+ {
+ "description": "Food and Beverage - Cooking Ingredients",
+ "name": "Food and Beverage - Cooking Ingredients",
+ "product_tax_code": "50181700A0000"
+ },
+ {
+ "description": "Food and Beverage - Cocoa and Cocoa products",
+ "name": "Food and Beverage - Cocoa and Cocoa products",
+ "product_tax_code": "50161511A0000"
+ },
+ {
+ "description": "Food and Beverage - Baby foods and formulas",
+ "name": "Food and Beverage - Baby foods and formulas",
+ "product_tax_code": "42231800A0000"
+ },
+ {
+ "description": "Clothing - Hazardous material protective footwear",
+ "name": "Clothing - Hazardous material protective footwear",
+ "product_tax_code": "46181602A0001"
+ },
+ {
+ "description": "Clothing - Welder gloves",
+ "name": "Clothing - Welder gloves",
+ "product_tax_code": "46181540A0001"
+ },
+ {
+ "description": "Clothing - Protective shirts",
+ "name": "Clothing - Protective shirts",
+ "product_tax_code": "46181526A0001"
+ },
+ {
+ "description": "Gift Cards",
+ "name": "Gift Cards",
+ "product_tax_code": "14111803A0001"
+ },
+ {
+ "description": "Clothing - Leg protectors",
+ "name": "Clothing - Leg protectors",
+ "product_tax_code": "46181520A0001"
+ },
+ {
+ "description": "Clothing - Protective coveralls",
+ "name": "Clothing - Protective coveralls",
+ "product_tax_code": "46181503A0001"
+ },
+ {
+ "description": "Internet or intranet client application development services\r\n",
+ "name": "Internet or intranet client application development services\r\n",
+ "product_tax_code": "81111509A0000"
+ },
+ {
+ "description": "Database design\r\n",
+ "name": "Database design\r\n",
+ "product_tax_code": "81111704A0000"
+ },
+ {
+ "description": "Computer programmers\r\n",
+ "name": "Computer programmers\r\n",
+ "product_tax_code": "81111600A0000"
+ },
+ {
+ "description": "Clothing - Synthetic Fur Hat",
+ "name": "Clothing - Synthetic Fur Hat",
+ "product_tax_code": "53102504A0002"
+ },
+ {
+ "description": "System or application programming management service\r\n",
+ "name": "System or application programming management service\r\n",
+ "product_tax_code": "81111511A0000"
+ },
+ {
+ "description": "Food and Beverage - Fruit",
+ "name": "Food and Beverage - Fruit",
+ "product_tax_code": "50300000A0000"
+ },
+ {
+ "description": "Food and Beverage - Vegetables",
+ "name": "Food and Beverage - Vegetables",
+ "product_tax_code": "50400000A0000"
+ },
+ {
+ "description": "Food and Beverage - Dried fruit, unsweetened",
+ "name": "Food and Beverage - Dried fruit, unsweetened",
+ "product_tax_code": "50320000A0000"
+ },
+ {
+ "description": "Food and Beverage - Snack Foods",
+ "name": "Food and Beverage - Snack Foods",
+ "product_tax_code": "50192100A0000"
+ },
+ {
+ "description": "Food and Beverage - Processed Nuts and Seeds",
+ "name": "Food and Beverage - Nuts and seeds that have been processed or treated by salting, spicing, smoking, roasting, or other means",
+ "product_tax_code": "50101716A0001"
+ },
+ {
+ "description": "Food and Beverage - Non-Alcoholic Beer, Wine",
+ "name": "Food and Beverage - Non-Alcoholic Beer, Wine",
+ "product_tax_code": "50202300A0001"
+ },
+ {
+ "description": "Food and Beverage - Ice Cream, sold in container less than one pint",
+ "name": "Food and Beverage - Ice Cream, sold in container less than one pint",
+ "product_tax_code": "50192304A0000"
+ },
+ {
+ "description": "Food and Beverage - Alcoholic beverages - Spirits",
+ "name": "Food and Beverage - Alcoholic beverages - Spirits",
+ "product_tax_code": "50202206A0000"
+ },
+ {
+ "description": "Food and Beverage - Wine",
+ "name": "Food and Beverage - Alcoholic beverages - Wine",
+ "product_tax_code": "50202203A0000"
+ },
+ {
+ "description": "Electronic content bundle - Delivered electronically with less than permanent rights of usage and streamed",
+ "name": "Electronic content bundle - Delivered electronically with less than permanent rights of usage and streamed",
+ "product_tax_code": "55111500A9220"
+ },
+ {
+ "description": "Clothing - Welding masks",
+ "name": "Clothing - Welding masks",
+ "product_tax_code": "46181703A0001"
+ },
+ {
+ "description": "Clothing - Protective wear dispenser",
+ "name": "Clothing - Protective wear dispenser",
+ "product_tax_code": "46181553A0001"
+ },
+ {
+ "description": "Clothing - Anti cut gloves",
+ "name": "Clothing - Anti cut gloves",
+ "product_tax_code": "46181536A0001"
+ },
+ {
+ "description": "Clothing - Reflective apparel or accessories",
+ "name": "Clothing - Reflective apparel or accessories",
+ "product_tax_code": "46181531A0001"
+ },
+ {
+ "description": "Clothing - Heat resistant clothing",
+ "name": "Clothing - Heat resistant clothing",
+ "product_tax_code": "46181518A0001"
+ },
+ {
+ "description": "Clothing - Cleanroom apparel",
+ "name": "Clothing - Cleanroom apparel",
+ "product_tax_code": "46181512A0001"
+ },
+ {
+ "description": "Clothing - Hazardous material protective apparel",
+ "name": "Clothing - Hazardous material protective apparel",
+ "product_tax_code": "46181509A0001"
+ },
+ {
+ "description": "Clothing - Safety vests",
+ "name": "Clothing - Safety vests",
+ "product_tax_code": "46181507A0001"
+ },
+ {
+ "description": "Clothing - Protective knee pads",
+ "name": "Clothing - Protective knee pads",
+ "product_tax_code": "46181505A0001"
+ },
+ {
+ "description": "Clothing - Bullet proof vests",
+ "name": "Clothing - Bullet proof vests",
+ "product_tax_code": "46181502A0001"
+ },
+ {
+ "description": "Clothing - Vest or waistcoats",
+ "name": "Clothing - Vest or waistcoats",
+ "product_tax_code": "53103100A0000"
+ },
+ {
+ "description": "Clothing - Prisoner uniform",
+ "name": "Clothing - Prisoner uniform",
+ "product_tax_code": "53102716A0000"
+ },
+ {
+ "description": "Clothing - Paramedic uniforms",
+ "name": "Clothing - Paramedic uniforms",
+ "product_tax_code": "53102712A0000"
+ },
+ {
+ "description": "Clothing - Ambulance officers uniforms",
+ "name": "Clothing - Ambulance officers uniforms",
+ "product_tax_code": "53102709A0000"
+ },
+ {
+ "description": "Clothing - Doctors coat",
+ "name": "Clothing - Doctors coat",
+ "product_tax_code": "53102707A0000"
+ },
+ {
+ "description": "Clothing - Sweat bands",
+ "name": "Clothing - Sweat bands",
+ "product_tax_code": "53102506A0000"
+ },
+ {
+ "description": "Clothing - Helmet parts or accessories",
+ "name": "Clothing - Helmet parts or accessories",
+ "product_tax_code": "46181706A0001"
+ },
+ {
+ "description": "Clothing - Fur Vest",
+ "name": "Clothing - Fur Vest",
+ "product_tax_code": "53103100A0001"
+ },
+ {
+ "description": "Clothing - Fur Gloves",
+ "name": "Clothing - Fur Gloves",
+ "product_tax_code": "53102503A0001"
+ },
+ {
+ "description": "Clothing - Motorcycle helmets",
+ "name": "Clothing - Motorcycle helmets",
+ "product_tax_code": "46181705A0001"
+ },
+ {
+ "description": "Operating system programming services\r\n",
+ "name": "Operating system programming services\r\n",
+ "product_tax_code": "81111505A0000"
+ },
+ {
+ "description": "Local area network communications design\r\n",
+ "name": "Local area network communications design\r\n",
+ "product_tax_code": "81111702A0000"
+ },
+ {
+ "description": "Clothing - Eye shields",
+ "name": "Clothing - Eye shields",
+ "product_tax_code": "46181803A0001"
+ },
+ {
+ "description": "Clothing - Welders helmet",
+ "name": "Clothing - Welders helmet",
+ "product_tax_code": "46181711A0001"
+ },
+ {
+ "description": "Clothing - Footwear covers",
+ "name": "Clothing - Footwear covers",
+ "product_tax_code": "46181606A0001"
+ },
+ {
+ "description": "Clothing - Cooling vest",
+ "name": "Clothing - Cooling vest",
+ "product_tax_code": "46181554A0001"
+ },
+ {
+ "description": "Clothing - Protective mesh jacket",
+ "name": "Clothing - Protective mesh jacket",
+ "product_tax_code": "46181551A0001"
+ },
+ {
+ "description": "Clothing - Protective scarf",
+ "name": "Clothing - Protective scarf",
+ "product_tax_code": "46181550A0001"
+ },
+ {
+ "description": "Clothing - Neck gaitor",
+ "name": "Clothing - Neck gaitor",
+ "product_tax_code": "46181549A0001"
+ },
+ {
+ "description": "Clothing - Welder bib",
+ "name": "Clothing - Welder bib",
+ "product_tax_code": "46181548A0001"
+ },
+ {
+ "description": "Clothing - Waterproof cap cover",
+ "name": "Clothing - Waterproof cap cover",
+ "product_tax_code": "46181547A0001"
+ },
+ {
+ "description": "Clothing - Waterproof suit",
+ "name": "Clothing - Waterproof suit",
+ "product_tax_code": "46181545A0001"
+ },
+ {
+ "description": "Clothing - Waterproof trousers or pants",
+ "name": "Clothing - Waterproof trousers or pants",
+ "product_tax_code": "46181544A0001"
+ },
+ {
+ "description": "Clothing - Protective mittens",
+ "name": "Clothing - Protective mittens",
+ "product_tax_code": "46181542A0001"
+ },
+ {
+ "description": "Clothing - Chemical resistant gloves",
+ "name": "Clothing - Chemical resistant gloves",
+ "product_tax_code": "46181541A0001"
+ },
+ {
+ "description": "Clothing - Anti vibratory gloves",
+ "name": "Clothing - Anti vibratory gloves",
+ "product_tax_code": "46181539A0001"
+ },
+ {
+ "description": "Clothing - Thermal gloves",
+ "name": "Clothing - Thermal gloves",
+ "product_tax_code": "46181538A0001"
+ },
+ {
+ "description": "Clothing - Insulated gloves",
+ "name": "Clothing - Insulated gloves",
+ "product_tax_code": "46181537A0001"
+ },
+ {
+ "description": "Clothing - Protective socks or hosiery",
+ "name": "Clothing - Protective socks or hosiery",
+ "product_tax_code": "46181535A0001"
+ },
+ {
+ "description": "Clothing - Protective wristbands",
+ "name": "Clothing - Protective wristbands",
+ "product_tax_code": "46181534A0001"
+ },
+ {
+ "description": "Clothing - Protective coats",
+ "name": "Clothing - Protective coats",
+ "product_tax_code": "46181533A0001"
+ },
+ {
+ "description": "Clothing - Insulated clothing for cold environments",
+ "name": "Clothing - Insulated clothing for cold environments",
+ "product_tax_code": "46181529A0001"
+ },
+ {
+ "description": "Clothing - Protective frock",
+ "name": "Clothing - Protective frock",
+ "product_tax_code": "46181528A0001"
+ },
+ {
+ "description": "Clothing - Safety hoods",
+ "name": "Clothing - Safety hoods",
+ "product_tax_code": "46181522A0001"
+ },
+ {
+ "description": "Clothing - Insulated or flotation suits",
+ "name": "Clothing - Insulated or flotation suits",
+ "product_tax_code": "46181517A0001"
+ },
+ {
+ "description": "Clothing - Elbow protectors",
+ "name": "Clothing - Elbow protectors",
+ "product_tax_code": "46181514A0001"
+ },
+ {
+ "description": "Clothing - Protective aprons",
+ "name": "Clothing - Protective aprons",
+ "product_tax_code": "46181501A0001"
+ },
+ {
+ "description": "Clothing - Shoes",
+ "name": "Clothing - Shoes",
+ "product_tax_code": "53111600A0000"
+ },
+ {
+ "description": "Clothing - Athletic wear",
+ "name": "Clothing - Athletic wear",
+ "product_tax_code": "53102900A0000"
+ },
+ {
+ "description": "Clothing - Folkloric clothing",
+ "name": "Clothing - Folkloric clothing",
+ "product_tax_code": "53102200A0000"
+ },
+ {
+ "description": "Clothing - Overalls or coveralls",
+ "name": "Clothing - Overalls or coveralls",
+ "product_tax_code": "53102100A0000"
+ },
+ {
+ "description": "Clothing - Dresses or skirts or saris or kimonos",
+ "name": "Clothing - Dresses or skirts or saris or kimonos",
+ "product_tax_code": "53102000A0000"
+ },
+ {
+ "description": "Clothing - Suits",
+ "name": "Clothing - Suits",
+ "product_tax_code": "53101900A0000"
+ },
+ {
+ "description": "Clothing - Sport uniform",
+ "name": "Clothing - Sport uniform",
+ "product_tax_code": "53102717A0000"
+ },
+ {
+ "description": "Clothing - Judicial robe",
+ "name": "Clothing - Judicial robe",
+ "product_tax_code": "53102714A0000"
+ },
+ {
+ "description": "Clothing - Ushers uniforms",
+ "name": "Clothing - Ushers uniforms",
+ "product_tax_code": "53102713A0000"
+ },
+ {
+ "description": "Clothing - Nurses uniforms",
+ "name": "Clothing - Nurses uniforms",
+ "product_tax_code": "53102708A0000"
+ },
+ {
+ "description": "Clothing - School uniforms",
+ "name": "Clothing - School uniforms",
+ "product_tax_code": "53102705A0000"
+ },
+ {
+ "description": "Clothing - Institutional food preparation or service attire",
+ "name": "Clothing - Institutional food preparation or service attire",
+ "product_tax_code": "53102704A0000"
+ },
+ {
+ "description": "Clothing - Police uniforms",
+ "name": "Clothing - Police uniforms",
+ "product_tax_code": "53102703A0000"
+ },
+ {
+ "description": "Clothing - Customs uniforms",
+ "name": "Clothing - Customs uniforms",
+ "product_tax_code": "53102702A0000"
+ },
+ {
+ "description": "Clothing - Bandannas",
+ "name": "Clothing - Bandannas",
+ "product_tax_code": "53102511A0000"
+ },
+ {
+ "description": "Clothing - Armbands",
+ "name": "Clothing - Armbands",
+ "product_tax_code": "53102508A0000"
+ },
+ {
+ "description": "Clothing - Caps",
+ "name": "Clothing - Caps",
+ "product_tax_code": "53102516A0000"
+ },
+ {
+ "description": "Clothing - Protective finger cots",
+ "name": "Clothing - Protective finger cots",
+ "product_tax_code": "46181530A0001"
+ },
+ {
+ "description": "Application programming services\r\n",
+ "name": "Application programming services\r\n",
+ "product_tax_code": "81111504A0000"
+ },
+ {
+ "description": "Application implementation services\r\n",
+ "name": "Application implementation services\r\n",
+ "product_tax_code": "81111508A0000"
+ },
+ {
+ "description": "Clothing - Synthetic Fur Ear muffs or scarves",
+ "name": "Clothing - Synthetic Fur Ear muffs or scarves",
+ "product_tax_code": "53102502A0002"
+ },
+ {
+ "description": "Clothing - Fur Poncho or Cape",
+ "name": "Clothing - Fur Poncho or Cape",
+ "product_tax_code": "53101806A0001"
+ },
+ {
+ "description": "Food and Beverage - Vitamins and Supplements - labeled with nutritional facts",
+ "name": "Food and Beverage - Vitamins and Supplements - labeled with nutritional facts",
+ "product_tax_code": "50501500A0001"
+ },
+ {
+ "description": "Food and Beverage - Nuts and seeds",
+ "name": "Food and Beverage - Nuts and seeds",
+ "product_tax_code": "50101716A0000"
+ },
+ {
+ "description": "Food and Beverage - Milk Substitutes",
+ "name": "Food and Beverage - Milk Substitutes",
+ "product_tax_code": "50151515A9000"
+ },
+ {
+ "description": "Food and Beverage - Milk and milk products",
+ "name": "Food and Beverage - Milk and milk products",
+ "product_tax_code": "50131700A0000"
+ },
+ {
+ "description": "Food and Beverage - Cheese",
+ "name": "Food and Beverage - Cheese",
+ "product_tax_code": "50131800A0000"
+ },
+ {
+ "description": "Clothing - Sandals",
+ "name": "Clothing - Sandals",
+ "product_tax_code": "53111800A0000"
+ },
+ {
+ "description": "Clothing - Pajamas or nightshirts or robes",
+ "name": "Clothing - Pajamas or nightshirts or robes",
+ "product_tax_code": "53102600A0000"
+ },
+ {
+ "description": "Clothing - Sweaters",
+ "name": "Clothing - Sweaters",
+ "product_tax_code": "53101700A0000"
+ },
+ {
+ "description": "Clothing - Slacks or trousers or shorts",
+ "name": "Clothing - Slacks or trousers or shorts",
+ "product_tax_code": "53101500A0000"
+ },
+ {
+ "description": "Clothing - Firefighter uniform",
+ "name": "Clothing - Firefighter uniform",
+ "product_tax_code": "53102718A0000"
+ },
+ {
+ "description": "Clothing - Salon smocks",
+ "name": "Clothing - Salon smocks",
+ "product_tax_code": "53102711A0000"
+ },
+ {
+ "description": "Clothing - Military uniforms",
+ "name": "Clothing - Military uniforms",
+ "product_tax_code": "53102701A0000"
+ },
+ {
+ "description": "Clothing - Heel pads",
+ "name": "Clothing - Heel pads",
+ "product_tax_code": "53112003A0000"
+ },
+ {
+ "description": "Clothing - Shoelaces",
+ "name": "Clothing - Shoelaces",
+ "product_tax_code": "53112002A0000"
+ },
+ {
+ "description": "Clothing - Infant swaddles or buntings or receiving blankets",
+ "name": "Clothing - Infant swaddles or buntings or receiving blankets",
+ "product_tax_code": "53102608A0000"
+ },
+ {
+ "description": "Clothing - Hats",
+ "name": "Clothing - Hats",
+ "product_tax_code": "53102503A0000"
+ },
+ {
+ "description": "Clothing - Ties or scarves or mufflers",
+ "name": "Clothing - Ties or scarves or mufflers",
+ "product_tax_code": "53102502A0000"
+ },
+ {
+ "description": "Clothing - Belts or suspenders",
+ "name": "Clothing - Belts or suspenders",
+ "product_tax_code": "53102501A0000"
+ },
+ {
+ "description": "Clothing - Tights",
+ "name": "Clothing - Tights",
+ "product_tax_code": "53102404A0000"
+ },
+ {
+ "description": "Clothing - Disposable youth training pants",
+ "name": "Clothing - Disposable youth training pants",
+ "product_tax_code": "53102311A0000"
+ },
+ {
+ "description": "Clothing - Undershirts",
+ "name": "Clothing - Undershirts",
+ "product_tax_code": "53102301A0000"
+ },
+ {
+ "description": "Clothing - Insulated cold weather shoe",
+ "name": "Clothing - Insulated cold weather shoe",
+ "product_tax_code": "46181610A0000"
+ },
+ {
+ "description": "Food and Beverage - Grains, Rice, Cereal",
+ "name": "Food and Beverage - Grains, Rice, Cereal",
+ "product_tax_code": "50221200A0000"
+ },
+ {
+ "description": "Clothing - Shirts",
+ "name": "Clothing - Shirts",
+ "product_tax_code": "53101600A0000"
+ },
+ {
+ "description": "Clothing - Safety boots",
+ "name": "Clothing - Safety boots",
+ "product_tax_code": "46181604A0000"
+ },
+ {
+ "description": "Clothing - Shin guards",
+ "name": "Clothing - Shin guards",
+ "product_tax_code": "49161525A0001"
+ },
+ {
+ "description": "Clothing - Athletic supporter",
+ "name": "Clothing - Athletic supporter",
+ "product_tax_code": "49161517A0001"
+ },
+ {
+ "description": "Clothing - Cleated or spiked shoes",
+ "name": "Clothing - Cleated or spiked shoes",
+ "product_tax_code": "53111900A0002"
+ },
+ {
+ "description": "Wide area network communications design\r\n",
+ "name": "Wide area network communications design\r\n\r\n",
+ "product_tax_code": "81111701A0000"
+ },
+ {
+ "description": "Systems integration design\r\n",
+ "name": "Systems integration design\r\n",
+ "product_tax_code": "81111503A0000"
+ },
+ {
+ "description": "Clothing - Bridal Gown",
+ "name": "Clothing - Bridal Gown",
+ "product_tax_code": "53101801A0004"
+ },
+ {
+ "description": "Clothing - Waterproof cap",
+ "name": "Clothing - Waterproof cap",
+ "product_tax_code": "46181546A0000"
+ },
+ {
+ "description": "Food and Beverage - Yogurt",
+ "name": "Food and Beverage - Yogurt",
+ "product_tax_code": "50131800A0001"
+ },
+ {
+ "description": "Food and Beverage - Nut Butters",
+ "name": "Food and Beverage - Nut Butters",
+ "product_tax_code": "50480000A9000"
+ },
+ {
+ "description": "Food and Beverage - Jams and Jellies",
+ "name": "Food and Beverage - Jams and Jellies",
+ "product_tax_code": "50192401A0000"
+ },
+ {
+ "description": "Food and Beverage - Honey, Maple Syrup",
+ "name": "Food and Beverage - Honey, Maple Syrup",
+ "product_tax_code": "50161509A0000"
+ },
+ {
+ "description": "Food and Beverage - Foods for Immediate Consumption",
+ "name": "Food and Beverage - Foods for Immediate Consumption",
+ "product_tax_code": "90100000A0001"
+ },
+ {
+ "description": "Food and Beverage - Bread and Flour Products",
+ "name": "Food and Beverage - Bread and Flour Products",
+ "product_tax_code": "50180000A0000"
+ },
+ {
+ "description": "Clothing - Overshoes",
+ "name": "Clothing - Overshoes",
+ "product_tax_code": "53112000A0000"
+ },
+ {
+ "description": "Clothing - Athletic footwear",
+ "name": "Clothing - Athletic footwear",
+ "product_tax_code": "53111900A0000"
+ },
+ {
+ "description": "Clothing - Slippers",
+ "name": "Clothing - Slippers",
+ "product_tax_code": "53111700A0000"
+ },
+ {
+ "description": "Clothing - Boots",
+ "name": "Clothing - Boots",
+ "product_tax_code": "53111500A0000"
+ },
+ {
+ "description": "Clothing - T-Shirts",
+ "name": "Clothing - T-Shirts",
+ "product_tax_code": "53103000A0000"
+ },
+ {
+ "description": "Clothing - Swimwear",
+ "name": "Clothing - Swimwear",
+ "product_tax_code": "53102800A0000"
+ },
+ {
+ "description": "Clothing - Coats or jackets",
+ "name": "Clothing - Coats or jackets",
+ "product_tax_code": "53101800A0000"
+ },
+ {
+ "description": "Clothing - Prison officer uniform",
+ "name": "Clothing - Prison officer uniform",
+ "product_tax_code": "53102715A0000"
+ },
+ {
+ "description": "Clothing - Corporate uniforms",
+ "name": "Clothing - Corporate uniforms",
+ "product_tax_code": "53102710A0000"
+ },
+ {
+ "description": "Clothing - Security uniforms",
+ "name": "Clothing - Security uniforms",
+ "product_tax_code": "53102706A0000"
+ },
+ {
+ "description": "Clothing - Chevrons",
+ "name": "Clothing - Chevrons",
+ "product_tax_code": "53102518A0000"
+ },
+ {
+ "description": "Clothing - Disposable work coat",
+ "name": "Clothing - Disposable work coat",
+ "product_tax_code": "53103201A0000"
+ },
+ {
+ "description": "Clothing - Bath robes",
+ "name": "Clothing - Bath robes",
+ "product_tax_code": "53102606A0000"
+ },
+ {
+ "description": "Clothing - Bib",
+ "name": "Clothing - Bib",
+ "product_tax_code": "53102521A0000"
+ },
+ {
+ "description": "Clothing - Gloves or mittens",
+ "name": "Clothing - Gloves or mittens",
+ "product_tax_code": "53102504A0000"
+ },
+ {
+ "description": "Clothing - Mouth guards",
+ "name": "Clothing - Mouth guards",
+ "product_tax_code": "42152402A0001"
+ },
+ {
+ "description": "Clothing - Boxing gloves",
+ "name": "Clothing - Boxing gloves",
+ "product_tax_code": "49171600A0000"
+ },
+ {
+ "description": "Clothing - Golf shoes",
+ "name": "Clothing - Golf shoes",
+ "product_tax_code": "53111900A0004"
+ },
+ {
+ "description": "Clothing - Bowling shoes",
+ "name": "Clothing - Bowling shoes",
+ "product_tax_code": "53111900A0003"
+ },
+ {
+ "description": "Internet or intranet server application development services\r\n",
+ "name": "Internet or intranet server application development services\r\n",
+ "product_tax_code": "81111510A0000"
+ },
+ {
+ "description": "Data conversion service\r\n",
+ "name": "Data conversion service\r\n",
+ "product_tax_code": "81112010A0000"
+ },
+ {
+ "description": "Client or server programming services\r\n",
+ "name": "Client or server programming services\r\n",
+ "product_tax_code": "81111506A0000"
+ },
+ {
+ "description": "Clothing - Ballet or tap shoes",
+ "name": "Clothing - Ballet or tap shoes",
+ "product_tax_code": "53111900A0001"
+ },
+ {
+ "description": "Clothing - Golf gloves",
+ "name": "Clothing - Golf gloves",
+ "product_tax_code": "49211606A0000"
+ },
+ {
+ "description": "Hardware as a service (HaaS)",
+ "name": "Hardware as a service (HaaS)",
+ "product_tax_code": "81161900A0000"
+ },
+ {
+ "description": "Cloud-based platform as a service (PaaS) - Personal Use",
+ "name": "Cloud-based platform as a service (PaaS) - Personal Use",
+ "product_tax_code": "81162100A0000"
+ },
+ {
+ "description": "Clothing - Panty hose",
+ "name": "Clothing - Panty hose",
+ "product_tax_code": "53102403A0000"
+ },
+ {
+ "description": "Clothing - Brassieres",
+ "name": "Clothing - Brassieres",
+ "product_tax_code": "53102304A0000"
+ },
+ {
+ "description": "Clothing - Protective sandals",
+ "name": "Clothing - Protective sandals",
+ "product_tax_code": "46181608A0000"
+ },
+ {
+ "description": "Clothing - Tuxedo or Formalwear",
+ "name": "Clothing - Tuxedo or Formalwear",
+ "product_tax_code": "53101801A0001"
+ },
+ {
+ "description": "Clothing - Lab coats",
+ "name": "Clothing - Lab coats",
+ "product_tax_code": "46181532A0000"
+ },
+ {
+ "description": "Systems planning services\r\n",
+ "name": "Systems planning services\r\n",
+ "product_tax_code": "81111707A0000"
+ },
+ {
+ "description": "Food and Beverage - Vitamins and Supplements",
+ "name": "Food and Beverage - Vitamins and Supplements - labeled with supplement facts",
+ "product_tax_code": "50501500A0000"
+ },
+ {
+ "description": "Food and Beverage - Jello and pudding mixes",
+ "name": "Food and Beverage - Jello and pudding mixes",
+ "product_tax_code": "50192404A0000"
+ },
+ {
+ "description": "Food and Beverage - Cooking spices",
+ "name": "Food and Beverage - Cooking spices",
+ "product_tax_code": "50171500A0000"
+ },
+ {
+ "description": "Food and Beverage - Alcoholic beverages - Beer/Malt Beverages",
+ "name": "Food and Beverage - Alcoholic beverages - Beer/Malt Beverages",
+ "product_tax_code": "50202201A0000"
+ },
+ {
+ "description": "Food and Beverage - Ice Cream, packaged",
+ "name": "Food and Beverage - Ice Cream, packaged",
+ "product_tax_code": "50192303A0000"
+ },
+ {
+ "description": "Electronic content bundle - Delivered electronically with permanent rights of usage and streamed",
+ "name": "Electronic content bundle - Delivered electronically with permanent rights of usage and streamed",
+ "product_tax_code": "55111500A9210"
+ },
+ {
+ "description": "Clothing - Roller skates or roller blades",
+ "name": "Clothing - Roller skates or roller blades",
+ "product_tax_code": "49221509A0000"
+ },
+ {
+ "description": "Clothing - Ice Skates",
+ "name": "Clothing - Ice Skates",
+ "product_tax_code": "49151602A0000"
+ },
+ {
+ "description": "Clothing - Life vests or preservers ",
+ "name": "Clothing - Life vests or preservers ",
+ "product_tax_code": "46161604A0000"
+ },
+ {
+ "description": "Clothing - Swim goggles",
+ "name": "Clothing - Swim goggles",
+ "product_tax_code": "49141606A0000"
+ },
+ {
+ "description": "Clothing - Bowling gloves",
+ "name": "Clothing - Bowling gloves",
+ "product_tax_code": "49211606A0002"
+ },
+ {
+ "description": "Fire Extinguishers",
+ "name": "Fire Extinguishers",
+ "product_tax_code": "46191601A0000"
+ },
+ {
+ "description": "Carbon Monoxide Detectors",
+ "name": "Carbon Monoxide Detectors",
+ "product_tax_code": "46191509A0001"
+ },
+ {
+ "description": "Ladder used for home emergency evacuation.",
+ "name": "Emergency/rescue ladder",
+ "product_tax_code": "30191501A0001"
+ },
+ {
+ "description": "Candles to be used a light source.",
+ "name": "Candles",
+ "product_tax_code": "39112604A0001"
+ },
+ {
+ "description": "Non-electric water container to store water for emergency usage.",
+ "name": "Water storage container",
+ "product_tax_code": "24111810A0001"
+ },
+ {
+ "description": "Duct Tape",
+ "name": "Duct Tape",
+ "product_tax_code": "31201501A0000"
+ },
+ {
+ "description": "Gas-powered chainsaw.",
+ "name": "Garden chainsaw",
+ "product_tax_code": "27112038A0000"
+ },
+ {
+ "description": "Chainsaw accessories include chains, lubricants, motor oil, chain sharpeners, bars, wrenches, carrying cases, repair parts, safety apparel.",
+ "name": "Chainsaw accessories",
+ "product_tax_code": "27112038A0001"
+ },
+ {
+ "description": "Shower curtain/liner used to keep water from escaping a showering area.",
+ "name": "Shower Curtain or Liner",
+ "product_tax_code": "30181607A0000"
+ },
+ {
+ "description": "Dish towels used for kitchenware drying.",
+ "name": "Dish towels",
+ "product_tax_code": "52121601A0000"
+ },
+ {
+ "description": "A bumper/liner that borders the interior walls/slats of the crib to help protect the baby.",
+ "name": "Crib bumpers/liners",
+ "product_tax_code": "56101804A0001"
+ },
+ {
+ "description": "A small mat/rug used to cover portion of bathroom floor.",
+ "name": "Bath Mats/rugs",
+ "product_tax_code": "52101507A0000"
+ },
+ {
+ "description": "A handheld computer that is capable of plotting graphs, solving simultaneous equations, and performing other tasks with variables.",
+ "name": "Graphing Calculators",
+ "product_tax_code": "44101808A0001"
+ },
+ {
+ "description": "Portable locks used by students in a school setting to prevent use, theft, vandalism or harm.",
+ "name": "Padlocks - Student",
+ "product_tax_code": "46171501A0001"
+ },
+ {
+ "description": "Domestic clothes washing appliances carrying Energy Star rating.",
+ "name": "Clothes Washing Machine - Energy Star",
+ "product_tax_code": "52141601A0000"
+ },
+ {
+ "description": "WaterSense labeled showerheads.",
+ "name": "Showerheads - WaterSense",
+ "product_tax_code": "30181801A0000"
+ },
+ {
+ "description": "Domestic dish washing appliances carrying Energy Star rating.",
+ "name": "Dishwashers - Energy Star",
+ "product_tax_code": "52141505A0000"
+ },
+ {
+ "description": "WaterSense labeled sprinkler body is the exterior shell that connects to the irrigation system piping and houses the spray nozzle that applies water on the landscape.",
+ "name": "Spray Water Sprinkler Bodies - WaterSense",
+ "product_tax_code": "21101803A0001"
+ },
+ {
+ "description": "Ropes and Cords",
+ "name": "Ropes and Cords",
+ "product_tax_code": "31151500A0000"
+ },
+ {
+ "description": "Light emitting diode (LED) bulbs carrying an Energy Star rating.",
+ "name": "LED Bulbs - Energy Star",
+ "product_tax_code": "39101628A0001"
+ },
+ {
+ "description": "WaterSense labeled bathroom sink faucets and accessories.",
+ "name": "Bathroom Faucets - WaterSense",
+ "product_tax_code": "30181702A0001"
+ },
+ {
+ "description": "Cables with industry standard connection and termination configurations used to connect various peripherals and equipment to computers.",
+ "name": "Computer Cables",
+ "product_tax_code": "43202222A0001"
+ },
+ {
+ "description": "Canned software delivered electronically that is used for non-recreational purposes, such as Antivirus, Database, Educational, Financial, Word processing, etc.",
+ "name": "Software - Prewritten, Electronic delivery - Non-recreational",
+ "product_tax_code": "43230000A1102"
+ },
+ {
+ "description": "Clothing - Baseball batting gloves",
+ "name": "Clothing - Baseball batting gloves",
+ "product_tax_code": "49211606A0001"
+ },
+ {
+ "description": "Cloud-based platform as a service (PaaS) - Business Use",
+ "name": "Cloud-based platform as a service (PaaS) - Business Use",
+ "product_tax_code": "81162100A9000"
+ },
+ {
+ "description": "Cloud-based Infrastructure as a service (IaaS) - Personal Use",
+ "name": "Cloud-based infrastructure as a service (IaaS) - Personal Use",
+ "product_tax_code": "81162200A0000"
+ },
+ {
+ "description": "Clothing - Costume Mask",
+ "name": "Clothing - Costume Mask",
+ "product_tax_code": "60122800A0000"
+ },
+ {
+ "description": "Clothing - Ski boots",
+ "name": "Clothing - Ski boots",
+ "product_tax_code": "53111900A0005"
+ },
+ {
+ "description": "Personal computer PC application design\r\n",
+ "name": "Personal computer PC application design\r\n",
+ "product_tax_code": "81111502A0000"
+ },
+ {
+ "description": "Network planning services\r\n",
+ "name": "Network planning services\r\n",
+ "product_tax_code": "81111706A0000"
+ },
+ {
+ "description": "ERP or database applications programming services\r\n",
+ "name": "ERP or database applications programming services\r\n",
+ "product_tax_code": "81111507A0000"
+ },
+ {
+ "description": "Content or data classification services\r\n",
+ "name": "Content or data classification services\r\n",
+ "product_tax_code": "81112009A0000"
+ },
+ {
+ "description": "Clothing - Prom Dress",
+ "name": "Clothing - Prom Dress",
+ "product_tax_code": "53101801A0003"
+ },
+ {
+ "description": "Clothing - Formal Dress",
+ "name": "Clothing - Formal Dress",
+ "product_tax_code": "53101801A0002"
+ },
+ {
+ "description": "Clothing - Handkerchiefs",
+ "name": "Clothing - Handkerchiefs",
+ "product_tax_code": "53102512A0000"
+ },
+ {
+ "description": "Clothing - Protective lens",
+ "name": "Clothing - Protective lens",
+ "product_tax_code": "46181811A0001"
+ },
+ {
+ "description": "Clothing - Body shaping garments",
+ "name": "Clothing - Body shaping garments",
+ "product_tax_code": "53102307A0000"
+ },
+ {
+ "description": "Clothing - Underpants",
+ "name": "Clothing - Underpants",
+ "product_tax_code": "53102303A0000"
+ },
+ {
+ "description": "Clothing - Waterproof boot",
+ "name": "Clothing - Waterproof boot",
+ "product_tax_code": "46181611A0000"
+ },
+ {
+ "description": "Electronic software documentation or user manuals - For prewritten software & delivered by load and leave",
+ "name": "Electronic software documentation or user manuals - Prewritten, load and leave delivery",
+ "product_tax_code": "55111601A1300"
+ },
+ {
+ "description": "Electronic software documentation or user manuals - For custom software & delivered on tangible media",
+ "name": "Electronic software documentation or user manuals - Custom, tangible media",
+ "product_tax_code": "55111601A2100"
+ },
+ {
+ "description": "Electronic software documentation or user manuals - For custom software & delivered by load and leave",
+ "name": "Electronic software documentation or user manuals - Custom, load and leave delivery",
+ "product_tax_code": "55111601A2300"
+ },
+ {
+ "description": "Electronic software documentation or user manuals - For custom software & delivered electronically",
+ "name": "Electronic software documentation or user manuals - Custom, electronic delivery",
+ "product_tax_code": "55111601A2200"
+ },
+ {
+ "description": "Electronic publications and music - Streamed",
+ "name": "Electronic publications and music - Streamed",
+ "product_tax_code": "55111500A1500"
+ },
+ {
+ "description": "Electronic publications and music - Delivered electronically with permanent rights of usage",
+ "name": "Electronic publications and music - Delivered electronically with permanent rights of usage",
+ "product_tax_code": "55111500A1210"
+ },
+ {
+ "description": "Electronic publications and music - Delivered electronically with less than permanent rights of usage",
+ "name": "Electronic publications and music - Delivered electronically with less than permanent rights of usage",
+ "product_tax_code": "55111500A1220"
+ },
+ {
+ "description": "Software - Custom & delivered on tangible media",
+ "name": "Software - Custom, tangible media",
+ "product_tax_code": "43230000A2100"
+ },
+ {
+ "description": "Software - Prewritten & delivered by digital keycode printed on tangible media",
+ "name": "Software - Prewritten, delivered by digital keycode printed on tangible media",
+ "product_tax_code": "43230000A1400"
+ },
+ {
+ "description": "Software - Prewritten & delivered by load and leave",
+ "name": "Software - Prewritten, load and leave delivery",
+ "product_tax_code": "43230000A1300"
+ },
+ {
+ "description": "Internet cloud storage service\r\n",
+ "name": "Internet cloud storage service\r\n",
+ "product_tax_code": "81111513A0000"
+ },
+ {
+ "description": "Computer or network or internet security\r\n",
+ "name": "Computer or network or internet security\r\n",
+ "product_tax_code": "81111801A0000"
+ },
+ {
+ "description": "Document scanning service\r\n",
+ "name": "Document scanning service\r\n",
+ "product_tax_code": "81112005A0000"
+ },
+ {
+ "description": "Cloud-based software as a service (SaaS) - Business Use",
+ "name": "Cloud-based software as a service (SaaS) - Business Use",
+ "product_tax_code": "81162000A9000"
+ },
+ {
+ "description": "Demining geographical or geospatial information system GIS\r\n",
+ "name": "Demining geographical or geospatial information system GIS\r\n",
+ "product_tax_code": "81111709A0000"
+ },
+ {
+ "description": "Content or data standardization services\r\n",
+ "name": "Content or data standardization services\r\n",
+ "product_tax_code": "81112007A0000"
+ },
+ {
+ "description": "Data processing or preparation services\r\n",
+ "name": "Data processing or preparation services\r\n",
+ "product_tax_code": "81112002A0000"
+ },
+ {
+ "description": "Database analysis service\r\n",
+ "name": "Database analysis service\r\n",
+ "product_tax_code": "81111806A0000"
+ },
+ {
+ "description": "Electronic software documentation or user manuals - For prewritten software & delivered on tangible media",
+ "name": "Electronic software documentation or user manuals - Prewritten, tangible media",
+ "product_tax_code": "55111601A1100"
+ },
+ {
+ "description": "Cloud-based software as a service (SaaS) - Personal Use",
+ "name": "Cloud-based software as a service (SaaS) - Personal Use",
+ "product_tax_code": "81162000A0000"
+ },
+ {
+ "description": "Clothing - Costume",
+ "name": "Clothing - Costume",
+ "product_tax_code": "60141401A0000"
+ },
+ {
+ "description": "Online data processing service\r\n",
+ "name": "Online data processing service\r\n",
+ "product_tax_code": "81112001A0000"
+ },
+ {
+ "description": "System usability services\r\n",
+ "name": "System usability services\r\n",
+ "product_tax_code": "81111820A0000"
+ },
+ {
+ "description": "Services that provide both essential proactive and reactive operations and maintenance support.",
+ "name": "IT Support Services",
+ "product_tax_code": "81111811A0000"
+ },
+ {
+ "description": "System analysis service\r\n",
+ "name": "System analysis service\r\n",
+ "product_tax_code": "81111808A0000"
+ },
+ {
+ "description": "Data storage service\r\n",
+ "name": "Data storage service\r\n",
+ "product_tax_code": "81112006A0000"
+ },
+ {
+ "description": "Quality assurance services\r\n",
+ "name": "Quality assurance services\r\n",
+ "product_tax_code": "81111819A0000"
+ },
+ {
+ "description": "Software - Custom & delivered by load & leave",
+ "name": "Software - Custom, load and leave delivery",
+ "product_tax_code": "43230000A2300"
+ },
+ {
+ "description": "Food and Beverage - Meat Sticks, Meat Jerky",
+ "name": "Food and Beverage - Meat Sticks, Meat Jerky",
+ "product_tax_code": "50112000A0000"
+ },
+ {
+ "description": "Clothing - Synthetic Fur Poncho or Cape",
+ "name": "Clothing - Synthetic Fur Poncho or Cape",
+ "product_tax_code": "53101806A0002"
+ },
+ {
+ "description": "Clothing - Wetsuit",
+ "name": "Clothing - Wetsuit",
+ "product_tax_code": "49141506A0000"
+ },
+ {
+ "description": "Cloud-based business process as a service - Business Use",
+ "name": "Cloud-based business process as a service - Business Use",
+ "product_tax_code": "81162300A9000"
+ },
+ {
+ "description": "Cloud-based infrastructure as a service (IaaS) - Business Use",
+ "name": "Cloud-based infrastructure as a service (IaaS) - Business Use",
+ "product_tax_code": "81162200A9000"
+ },
+ {
+ "description": "Clothing - Belt Buckle",
+ "name": "Clothing - Belt Buckle",
+ "product_tax_code": "53102501A0001"
+ },
+ {
+ "description": "Clothing - Shower Cap",
+ "name": "Clothing - Shower Cap",
+ "product_tax_code": "53131601A0000"
+ },
+ {
+ "description": "Clothing - Eye shield garters",
+ "name": "Clothing - Eye shield garters",
+ "product_tax_code": "46181809A0001"
+ },
+ {
+ "description": "Clothing - Socks",
+ "name": "Clothing - Socks",
+ "product_tax_code": "53102402A0000"
+ },
+ {
+ "description": "Clothing - Stockings",
+ "name": "Clothing - Stockings",
+ "product_tax_code": "53102401A0000"
+ },
+ {
+ "description": "Food and Beverage - Meat and meat products",
+ "name": "Food and Beverage - Meat and meat products",
+ "product_tax_code": "50110000A0000"
+ },
+ {
+ "description": "Clothing - Slips",
+ "name": "Clothing - Slips",
+ "product_tax_code": "53102302A0000"
+ },
+ {
+ "description": "Clothing - Goggle protective covers",
+ "name": "Clothing - Goggle protective covers",
+ "product_tax_code": "46181808A0001"
+ },
+ {
+ "description": "Clothing - Goggles",
+ "name": "Clothing - Goggles",
+ "product_tax_code": "46181804A0001"
+ },
+ {
+ "description": "Clothing - Football receiver gloves",
+ "name": "Clothing - Football receiver gloves",
+ "product_tax_code": "49211606A0004"
+ },
+ {
+ "description": "Disaster recovery services",
+ "name": "Disaster recovery services",
+ "product_tax_code": "81112004A0000"
+ },
+ {
+ "description": "Clothing - Mountain climbing boot",
+ "name": "Clothing - Mountain climbing boot",
+ "product_tax_code": "46181613A0000"
+ },
+ {
+ "description": "Software maintenance and support - Mandatory maintenance and support charges for prewritten software including items delivered on tangible media",
+ "name": "Software maintenance and support - Mandatory, prewritten, tangible media",
+ "product_tax_code": "81112200A1110"
+ },
+ {
+ "description": "Clothing - Military boot",
+ "name": "Clothing - Military boot",
+ "product_tax_code": "46181612A0000"
+ },
+ {
+ "description": "Carbonated beverages marketed as energy drinks, carrying a Supplement Facts Label, that contain a blend of energy enhancing vitamins, minerals, herbals, stimulants, etc.",
+ "name": "Energy Beverages - Carbonated - with Supplement Facts Label",
+ "product_tax_code": "50202309A0001"
+ },
+ {
+ "description": "Non-carbonated beverages marketed as energy drinks, carrying a Supplement Facts Label, that contain a blend of energy enhancing vitamins, minerals, herbals, stimulants, etc.",
+ "name": "Energy Beverages - Non-Carbonated - with Supplement Facts Label",
+ "product_tax_code": "50202309A0000"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with tangible personal property, with the food comprising 90% or more of the overall value of the bundle, where all food consists of candy (not containing flour).",
+ "name": "Food/TPP Bundle - with Food 90% or more - Food is all Candy",
+ "product_tax_code": "50193400A0001"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with tangible personal property, with the food comprising less 90% or more of the overall value of the bundle.",
+ "name": "Food/TPP Bundle - with Food 90% or more",
+ "product_tax_code": "50193400A0000"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with tangible personal property, with the food comprising between 76% and 89% of the overall value of the bundle, where all food consists of candy (not containing flour).",
+ "name": "Food/TPP Bundle - with Food between 76% and 89% - Food is all Candy",
+ "product_tax_code": "50193400A0005"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with tangible personal property, with the food comprising between 76% and 89% of the overall value of the bundle.",
+ "name": "Food/TPP Bundle - with Food between 76% and 89%",
+ "product_tax_code": "50193400A0004"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with tangible personal property, with the food comprising between 50% and 75% of the overall value of the bundle, where all food consists of candy (not containing flour).",
+ "name": "Food/TPP Bundle - with Food between 50% and 75% - Food is all Candy",
+ "product_tax_code": "50193400A0003"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with tangible personal property, with the food comprising between 50% and 75% of the overall value of the bundle.",
+ "name": "Food/TPP Bundle - with Food between 50% and 75%",
+ "product_tax_code": "50193400A0002"
+ },
+ {
+ "description": "Food/TPP Bundle - with Food less than 50%",
+ "name": "Food/TPP Bundle - with Food less than 50%",
+ "product_tax_code": "50193400A0006"
+ },
+ {
+ "description": "Ready to drink beverages, not containing milk, formulated and labled for their nutritional value, such as increased caloric or protein intake and containing natrual or artificial sweeteners.",
+ "name": "Nutritional Supplement/protein drinks, shakes - contains no milk",
+ "product_tax_code": "50501703A0000"
+ },
+ {
+ "description": "Ready to drink beverages, containing milk, formulated and labled for their nutritional value, such as increased caloric or protein intake.",
+ "name": "Nutritional Supplement/protein drinks, shakes - contains milk",
+ "product_tax_code": "50501703A0001"
+ },
+ {
+ "description": "Powdered mixes to be reconstituted into a drinkable beverage using water.",
+ "name": "Powdered Drink Mixes - to be mixed with water",
+ "product_tax_code": "50202311A0000"
+ },
+ {
+ "description": "Powdered mixes to be reconstituted into a drinkable beverage using milk or a milk substitute.",
+ "name": "Powdered Drink Mixes - to be mixed with milk",
+ "product_tax_code": "50202311A0001"
+ },
+ {
+ "description": "Food and Beverage - Granola Bars, Cereal Bars, Energy Bars, Protein Bars containing no flour",
+ "name": "Food and Beverage - Granola Bars, Cereal Bars, Energy Bars, Protein Bars containing no flour",
+ "product_tax_code": "50221202A0002"
+ },
+ {
+ "description": "Food and Beverage - Granola Bars, Cereal Bars, Energy Bars, Protein Bars containing flour",
+ "name": "Food and Beverage - Granola Bars, Cereal Bars, Energy Bars, Protein Bars containing flour",
+ "product_tax_code": "50221202A0001"
+ },
+ {
+ "description": "Nutritional supplement in powder form, dairy based or plant based, focused on increasing ones intake of protein for various benefits.",
+ "name": "Protein Powder",
+ "product_tax_code": "50501703A0002"
+ },
+ {
+ "description": "Ready to drink non-carbonated beverage containing tea with natural or artificial sweeteners.",
+ "name": "Bottled tea - non-carbonated - sweetened",
+ "product_tax_code": "50201712A0003"
+ },
+ {
+ "description": "Ready to drink non-carbonated beverage containing tea without natural or artificial sweeteners.",
+ "name": "Bottled tea - non-carbonated - unsweetened",
+ "product_tax_code": "50201712A0000"
+ },
+ {
+ "description": "Ready to drink carbonated beverage containing tea with natural or artificial sweeteners.",
+ "name": "Bottled tea - carbonated - sweetened",
+ "product_tax_code": "50201712A0002"
+ },
+ {
+ "description": "Ready to drink carbonated beverage containing tea and without any natural or artificial sweeteners.",
+ "name": "Bottled tea - carbonated - unsweetened",
+ "product_tax_code": "50201712A0001"
+ },
+ {
+ "description": "Ready to drink coffee based beverage containing milk or milk substitute.",
+ "name": "Bottled coffee - containing milk or milk substitute",
+ "product_tax_code": "50201708A0002"
+ },
+ {
+ "description": "Ready to drink coffee based beverage not containing milk, containing natural or artificial sweetener.",
+ "name": "Bottled coffee - no milk - sweetened",
+ "product_tax_code": "50201708A0001"
+ },
+ {
+ "description": "Ready to drink coffee based beverage containing neither milk nor natural or artificial sweeteners.",
+ "name": "Bottled coffee - no milk - unsweetened",
+ "product_tax_code": "50201708A0000"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 51 - 69% natural vegetable juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 51-69% vegetable juice",
+ "product_tax_code": "50202306A0008"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 1 - 9% natural fruit juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 1-9% fruit juice",
+ "product_tax_code": "50202306A0001"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 70 - 99% natural fruit juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 70-99% fruit juice",
+ "product_tax_code": "50202304A0010"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 51 - 69% natural vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 51-69% vegetable juice",
+ "product_tax_code": "50202304A0009"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 25 - 50% natural vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 25-50% vegetable juice",
+ "product_tax_code": "50202304A0007"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 10 - 24% natural fruit juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 10-24% fruit juice",
+ "product_tax_code": "50202304A0004"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 70 - 99% natural vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 70-99% vegetable juice",
+ "product_tax_code": "50202304A0011"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and zero natural fruit or vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - No fruit or vegetable juice",
+ "product_tax_code": "50202304A0001"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 51 - 69% natural fruit juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 51-69% fruit juice",
+ "product_tax_code": "50202304A0008"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 1 - 9% natural vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 1 -9% vegetable juice",
+ "product_tax_code": "50202304A0003"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 1 - 9% natural fruit juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 1-9% fruit juice",
+ "product_tax_code": "50202304A0002"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 10 - 24% natural vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 10-24% vegetable juice",
+ "product_tax_code": "50202304A0005"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 25 - 50% natural fruit juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 25-50% fruit juice",
+ "product_tax_code": "50202304A0006"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 100% natural fruit or vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 100% fruit or vegetable juice",
+ "product_tax_code": "50202304A0000"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and zero natural fruit or vegetable juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - No fruit or vegetable juice",
+ "product_tax_code": "50202306A0000"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 70 - 99% natural vegetable juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 70-99% vegetable juice",
+ "product_tax_code": "50202306A0010"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 70 - 99% natural fruit juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 70-99% fruit juice",
+ "product_tax_code": "50202306A0009"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 51 - 69% natural fruit juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 51-69% fruit juice",
+ "product_tax_code": "50202306A0007"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 25 - 50% natural vegetable juice. This does not flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 25-50% vegetable juice",
+ "product_tax_code": "50202306A0006"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 25 - 50% natural fruit juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 25-50% fruit juice",
+ "product_tax_code": "50202306A0005"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 100% natural fruit or vegetable juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 100% fruit or vegetable juice",
+ "product_tax_code": "50202306A0011"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 10 - 24% natural vegetable juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 10-24% vegetable juice",
+ "product_tax_code": "50202306A0004"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 10 - 24% natural fruit juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 10-24% fruit juice",
+ "product_tax_code": "50202306A0003"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 1 - 9% natural vegetable juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 1 -9% vegetable juice",
+ "product_tax_code": "50202306A0002"
+ },
+ {
+ "description": "Bottled Water for human consumption, unsweetened, non-carbonated. Does not include distilled water.",
+ "name": "Bottled Water",
+ "product_tax_code": "50202301A0000"
+ },
+ {
+ "description": "Bottled Water for human consumption, containing natural or artificial sweeteners, non-carbonated.",
+ "name": "Bottled Water - Flavored",
+ "product_tax_code": "50202301A0001"
+ },
+ {
+ "description": "Bottled Water for human consumption, unsweetened, carbonated naturally. Includes carbonated waters containing only natural flavors or essences.",
+ "name": "Bottled Water - Carbonated Naturally",
+ "product_tax_code": "50202301A0003"
+ },
+ {
+ "description": "Bottled Water for human consumption, unsweetened, carbonated artificially during bottling process. Includes carbonated waters containing only natural flavors or essences.",
+ "name": "Bottled Water - Carbonated Artificially",
+ "product_tax_code": "50202301A0002"
+ },
+ {
+ "description": "Bottled Water for human consumption, containing natural or artificial sweeteners, carbonated.",
+ "name": "Bottled Water - Carbonated - Sweetened",
+ "product_tax_code": "50202301A0004"
+ },
+ {
+ "description": "Clothing - Sequins for use in clothing",
+ "name": "Clothing - Sequins for use in clothing",
+ "product_tax_code": "60123900A0000"
+ },
+ {
+ "description": "Clothing - Synthetic Fur Gloves",
+ "name": "Clothing - Synthetic Fur Gloves",
+ "product_tax_code": "53102503A0002"
+ },
+ {
+ "description": "Clothing - Synthetic Fur Coat or Jacket",
+ "name": "Clothing - Synthetic Fur Coat or Jacket",
+ "product_tax_code": "53101800A0002"
+ },
+ {
+ "description": "Clothing - Fur Hat",
+ "name": "Clothing - Fur Hat",
+ "product_tax_code": "53102504A0001"
+ },
+ {
+ "description": "Clothing - Fur Coat or Jacket",
+ "name": "Clothing - Fur Coat or Jacket",
+ "product_tax_code": "53101800A0001"
+ },
+ {
+ "description": "Cloud-based business process as a service",
+ "name": "Cloud-based business process as a service - Personal Use",
+ "product_tax_code": "81162300A0000"
+ },
+ {
+ "description": "Clothing - Shoulder pads for sports",
+ "name": "Clothing - Shoulder pads for sports",
+ "product_tax_code": "46181506A0002"
+ },
+ {
+ "description": "Mainframe software applications design\r\n",
+ "name": "Mainframe software applications design\r\n",
+ "product_tax_code": "81111501A0000"
+ },
+ {
+ "description": "Clothing - Safety shoes",
+ "name": "Clothing - Safety shoes",
+ "product_tax_code": "46181605A0000"
+ },
+ {
+ "description": "Clothing - Protective hood",
+ "name": "Clothing - Protective hood",
+ "product_tax_code": "46181710A0001"
+ },
+ {
+ "description": "Clothing - Face protection kit",
+ "name": "Clothing - Face protection kit",
+ "product_tax_code": "46181709A0001"
+ },
+ {
+ "description": "Clothing - Protective hair net",
+ "name": "Clothing - Protective hair net",
+ "product_tax_code": "46181708A0001"
+ },
+ {
+ "description": "Clothing - Facial shields parts or accessories",
+ "name": "Clothing - Facial shields parts or accessories",
+ "product_tax_code": "46181707A0001"
+ },
+ {
+ "description": "Clothing - Safety helmets",
+ "name": "Clothing - Safety helmets",
+ "product_tax_code": "46181704A0001"
+ },
+ {
+ "description": "Clothing - Poncho",
+ "name": "Clothing - Poncho",
+ "product_tax_code": "53101806A0000"
+ },
+ {
+ "description": "Clothing - Protective insole",
+ "name": "Clothing - Protective insole",
+ "product_tax_code": "46181609A0000"
+ },
+ {
+ "description": "Clothing - Protective clogs",
+ "name": "Clothing - Protective clogs",
+ "product_tax_code": "46181607A0000"
+ },
+ {
+ "description": "Clothing - Waterproof jacket or raincoat",
+ "name": "Clothing - Waterproof jacket or raincoat",
+ "product_tax_code": "46181543A0000"
+ },
+ {
+ "description": "Systems architecture\r\n",
+ "name": "Systems architecture\r\n",
+ "product_tax_code": "81111705A0000"
+ },
+ {
+ "description": "System installation service\r\n",
+ "name": "System installation service\r\n",
+ "product_tax_code": "81111809A0000"
+ },
+ {
+ "description": "Software maintenance and support - Mandatory maintenance and support charges for custom software including items delivered by load and leave",
+ "name": "Software maintenance and support - Mandatory, custom, load and leave delivery",
+ "product_tax_code": "81112200A2310"
+ },
+ {
+ "description": "Software coding service\r\n",
+ "name": "Software coding service\r\n",
+ "product_tax_code": "81111810A0000"
+ },
+ {
+ "description": "Software - Custom & delivered electronically",
+ "name": "Software - Custom, electronic delivery",
+ "product_tax_code": "43230000A2200"
+ },
+ {
+ "description": "Bathing suits and swim suits",
+ "name": "Clothing - Swimwear",
+ "product_tax_code": "20041"
+ },
+ {
+ "description": "Miscellaneous services which are not subject to a service-specific tax levy. This category will only treat services as taxable if the jurisdiction taxes services generally.",
+ "name": "General Services",
+ "product_tax_code": "19000"
+ },
+ {
+ "description": "Services provided to educate users on the proper use of a product. Live training in person",
+ "name": "Training Services - Live",
+ "product_tax_code": "19004"
+ },
+ {
+ "description": "Admission charges associated with entry to an event.",
+ "name": "Admission Services",
+ "product_tax_code": "19003"
+ },
+ {
+ "description": "Service of providing usage of a parking space.",
+ "name": "Parking Services",
+ "product_tax_code": "19002"
+ },
+ {
+ "description": "A charge separately stated from any sale of the product itself for the installation of tangible personal property. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Installation Services",
+ "product_tax_code": "10040"
+ },
+ {
+ "description": "Services rendered for advertising which do not include the exchange of tangible personal property.",
+ "name": "Advertising Services",
+ "product_tax_code": "19001"
+ },
+ {
+ "description": "Digital products transferred electronically, meaning obtained by the purchaser by means other than tangible storage media.",
+ "name": "Digital Goods",
+ "product_tax_code": "31000"
+ },
+ {
+ "description": " All human wearing apparel suitable for general use",
+ "name": "Clothing",
+ "product_tax_code": "20010"
+ },
+ {
+ "description": "An over-the-counter drug is a substance that contains a label identifying it as a drug and including a \"drug facts\" panel or a statement of active ingredients, that can be obtained without a prescription. A drug can be intended for internal (ingestible, implant, injectable) or external (topical) application to the human body.",
+ "name": "Over-the-Counter Drugs",
+ "product_tax_code": "51010"
+ },
+ {
+ "description": "A substance that can only be obtained via a prescription of a licensed professional. A drug is a compound, substance, or preparation, and any component thereof, not including food or food ingredients, dietary supplements, or alcoholic beverages, that is: recognized in the official United States pharmacopoeia, official homeopathic pharmacopoeia of the United States, or official national formulary, and supplement to any of them; intended for use in the diagnosis, cure, mitigation, treatment, or prevention of disease; or intended to affect the structure or any function of the body. A drug can be intended for internal (ingestible, implant, injectable) or external (topical) application to the human body.",
+ "name": "Prescription Drugs",
+ "product_tax_code": "51020"
+ },
+ {
+ "description": "Food for humans consumption, unprepared",
+ "name": "Food & Groceries",
+ "product_tax_code": "40030"
+ },
+ {
+ "description": "Pre-written software, delivered electronically, but access remotely.",
+ "name": "Software as a Service",
+ "product_tax_code": "30070"
+ },
+ {
+ "description": "Periodicals, printed, sold by subscription",
+ "name": "Magazines & Subscriptions",
+ "product_tax_code": "81300"
+ },
+ {
+ "description": "Books, printed",
+ "name": "Books",
+ "product_tax_code": "81100"
+ },
+ {
+ "description": "Periodicals, printed, sold individually",
+ "name": "Magazine",
+ "product_tax_code": "81310"
+ },
+ {
+ "description": "Textbooks, printed",
+ "name": "Textbook",
+ "product_tax_code": "81110"
+ },
+ {
+ "description": "Religious books and manuals, printed",
+ "name": "Religious books",
+ "product_tax_code": "81120"
+ },
+ {
+ "description": "Non-food dietary supplements",
+ "name": "Supplements",
+ "product_tax_code": "40020"
+ },
+ {
+ "description": "Candy",
+ "name": "Candy",
+ "product_tax_code": "40010"
+ },
+ {
+ "description": "Soft drinks. Soda and similar drinks. Does not include water, juice, or milk.",
+ "name": "Soft Drinks",
+ "product_tax_code": "40050"
+ },
+ {
+ "description": "Bottled water for human consumption.",
+ "name": "Bottled Water",
+ "product_tax_code": "40060"
+ },
+ {
+ "description": "Ready to eat foods intended to be consumed on site by humans. Foods not considered to be Food & Grocery (not food for home consumption or food which requires further preparation to consume).",
+ "name": "Prepared Foods",
+ "product_tax_code": "41000"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/regional/united_states/setup.py b/erpnext/regional/united_states/setup.py
index 24ab1cf049f..25982b81227 100644
--- a/erpnext/regional/united_states/setup.py
+++ b/erpnext/regional/united_states/setup.py
@@ -2,13 +2,44 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+import os
+import json
+from frappe.permissions import add_permission, update_permission_property
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
def setup(company=None, patch=True):
+ # Company independent fixtures should be called only once at the first company setup
+ if frappe.db.count('Company', {'country': 'United States'}) <=1:
+ setup_company_independent_fixtures(patch=patch)
+
+def setup_company_independent_fixtures(company=None, patch=True):
+ add_product_tax_categories()
make_custom_fields()
+ add_permissions()
+ frappe.enqueue('erpnext.regional.united_states.setup.add_product_tax_categories', now=False)
add_print_formats()
+# Product Tax categories imported from taxjar api
+def add_product_tax_categories():
+ with open(os.path.join(os.path.dirname(__file__), 'product_tax_category_data.json'), 'r') as f:
+ tax_categories = json.loads(f.read())
+ create_tax_categories(tax_categories['categories'])
+
+def create_tax_categories(data):
+ for d in data:
+ tax_category = frappe.new_doc('Product Tax Category')
+ tax_category.description = d.get("description")
+ tax_category.product_tax_code = d.get("product_tax_code")
+ tax_category.category_name = d.get("name")
+ try:
+ tax_category.db_insert()
+ except frappe.DuplicateEntryError:
+ pass
+
+
def make_custom_fields(update=True):
custom_fields = {
'Supplier': [
@@ -30,10 +61,29 @@ def make_custom_fields(update=True):
'Quotation': [
dict(fieldname='exempt_from_sales_tax', fieldtype='Check', insert_after='taxes_and_charges',
label='Is customer exempted from sales tax?')
+ ],
+ 'Sales Invoice Item': [
+ dict(fieldname='product_tax_category', fieldtype='Link', insert_after='description', options='Product Tax Category',
+ label='Product Tax Category', fetch_from='item_code.product_tax_category'),
+ dict(fieldname='tax_collectable', fieldtype='Currency', insert_after='net_amount',
+ label='Tax Collectable', read_only=1),
+ dict(fieldname='taxable_amount', fieldtype='Currency', insert_after='tax_collectable',
+ label='Taxable Amount', read_only=1)
+ ],
+ 'Item': [
+ dict(fieldname='product_tax_category', fieldtype='Link', insert_after='item_group', options='Product Tax Category',
+ label='Product Tax Category')
]
}
create_custom_fields(custom_fields, update=update)
+def add_permissions():
+ doctype = "Product Tax Category"
+ for role in ('Accounts Manager', 'Accounts User', 'System Manager','Item Manager', 'Stock Manager'):
+ add_permission(doctype, role, 0)
+ update_permission_property(doctype, role, 0, 'write', 1)
+ update_permission_property(doctype, role, 0, 'create', 1)
+
def add_print_formats():
frappe.reload_doc("regional", "print_format", "irs_1099_form")
frappe.db.set_value("Print Format", "IRS 1099 Form", "disabled", 0)
diff --git a/erpnext/regional/united_states/test_united_states.py b/erpnext/regional/united_states/test_united_states.py
index 513570ed6df..19e9a3546f8 100644
--- a/erpnext/regional/united_states/test_united_states.py
+++ b/erpnext/regional/united_states/test_united_states.py
@@ -1,8 +1,11 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import unittest
+
+import frappe
+
from erpnext.regional.report.irs_1099.irs_1099 import execute as execute_1099_report
diff --git a/erpnext/restaurant/doctype/restaurant/restaurant.py b/erpnext/restaurant/doctype/restaurant/restaurant.py
index 0bb7b692c75..486afc3a11e 100644
--- a/erpnext/restaurant/doctype/restaurant/restaurant.py
+++ b/erpnext/restaurant/doctype/restaurant/restaurant.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class Restaurant(Document):
pass
diff --git a/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py b/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py
index adce5c73352..5b78bb2f45a 100644
--- a/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py
+++ b/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'restaurant',
diff --git a/erpnext/restaurant/doctype/restaurant/test_restaurant.py b/erpnext/restaurant/doctype/restaurant/test_restaurant.py
index 3ba7f5785eb..574cd1f9e4a 100644
--- a/erpnext/restaurant/doctype/restaurant/test_restaurant.py
+++ b/erpnext/restaurant/doctype/restaurant/test_restaurant.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
test_records = [
diff --git a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py
index 952c46769b7..632f4850d8a 100644
--- a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py
+++ b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class RestaurantMenu(Document):
def validate(self):
for d in self.items:
diff --git a/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py
index 29f95fd8b1f..00cbf358d6f 100644
--- a/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py
+++ b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py
@@ -3,9 +3,10 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
test_records = [
dict(doctype='Item', item_code='Food Item 1',
item_group='Products', is_stock_item=0),
diff --git a/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py
index cc86bb3165e..5d095f49a8e 100644
--- a/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py
+++ b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class RestaurantMenuItem(Document):
pass
diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py
index 357deaac007..1ed5921f350 100644
--- a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py
+++ b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py
@@ -3,11 +3,16 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, json
-from frappe.model.document import Document
+
+import json
+
+import frappe
from frappe import _
+from frappe.model.document import Document
+
from erpnext.controllers.queries import item_query
+
class RestaurantOrderEntry(Document):
pass
diff --git a/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py
index e0c051b1ad7..ee8928b13a1 100644
--- a/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py
+++ b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class RestaurantOrderEntryItem(Document):
pass
diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py
index f96de44c3d6..f6d2a7c8cc4 100644
--- a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py
+++ b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py
@@ -3,11 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
+
from datetime import timedelta
+
+from frappe.model.document import Document
from frappe.utils import get_datetime
+
class RestaurantReservation(Document):
def validate(self):
if not self.reservation_end_time:
diff --git a/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py
index 71681b2f183..885da724aa0 100644
--- a/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py
+++ b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestRestaurantReservation(unittest.TestCase):
pass
diff --git a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py
index d5ea9d53981..0b5d6352711 100644
--- a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py
+++ b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py
@@ -3,10 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, re
+
+import re
+
from frappe.model.document import Document
from frappe.model.naming import make_autoname
+
class RestaurantTable(Document):
def autoname(self):
prefix = re.sub('-+', '-', self.restaurant.replace(' ', '-'))
diff --git a/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py
index ffdb6f742a3..44059aee607 100644
--- a/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py
+++ b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
test_records = [
diff --git a/erpnext/selling/doctype/campaign/campaign.py b/erpnext/selling/doctype/campaign/campaign.py
index 10945428aee..09fea9a987c 100644
--- a/erpnext/selling/doctype/campaign/campaign.py
+++ b/erpnext/selling/doctype/campaign/campaign.py
@@ -2,11 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
from frappe.model.document import Document
from frappe.model.naming import set_name_by_naming_series
+
class Campaign(Document):
def autoname(self):
if frappe.defaults.get_global_default('campaign_naming_by') != 'Naming Series':
diff --git a/erpnext/selling/doctype/campaign/campaign_dashboard.py b/erpnext/selling/doctype/campaign/campaign_dashboard.py
index 3cef560c32f..990ebaae79c 100644
--- a/erpnext/selling/doctype/campaign/campaign_dashboard.py
+++ b/erpnext/selling/doctype/campaign/campaign_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'campaign_name',
diff --git a/erpnext/selling/doctype/campaign/test_campaign.py b/erpnext/selling/doctype/campaign/test_campaign.py
index 8c6617fe79a..bcb985b50f7 100644
--- a/erpnext/selling/doctype/campaign/test_campaign.py
+++ b/erpnext/selling/doctype/campaign/test_campaign.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Campaign')
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 27e9f08e8d6..2946cd9a172 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -2,20 +2,26 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import json
-from frappe.model.naming import set_name_by_naming_series
-from frappe import _, msgprint
+
+import frappe
import frappe.defaults
-from frappe.utils import flt, cint, cstr, today, get_formatted_email
+from frappe import _, msgprint
+from frappe.contacts.address_and_contact import (
+ delete_contact_and_address,
+ load_address_and_contact,
+)
from frappe.desk.reportview import build_match_conditions, get_filters_cond
-from erpnext.utilities.transaction_base import TransactionBase
-from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this
-from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
-from frappe.model.rename_doc import update_linked_doctypes
from frappe.model.mapper import get_mapped_doc
+from frappe.model.naming import set_name_by_naming_series
+from frappe.model.rename_doc import update_linked_doctypes
+from frappe.utils import cint, cstr, flt, get_formatted_email, today
from frappe.utils.user import get_users_with_role
+from erpnext.accounts.party import get_dashboard_info, validate_party_accounts
+from erpnext.utilities.transaction_base import TransactionBase
+
class Customer(TransactionBase):
def get_feed(self):
@@ -286,30 +292,6 @@ class Customer(TransactionBase):
.format(frappe.bold(self.customer_name))
)
- def create_onboarding_docs(self, args):
- defaults = frappe.defaults.get_defaults()
- company = defaults.get('company') or \
- frappe.db.get_single_value('Global Defaults', 'default_company')
-
- for i in range(1, args.get('max_count')):
- customer = args.get('customer_name_' + str(i))
- if customer:
- try:
- doc = frappe.get_doc({
- 'doctype': self.doctype,
- 'customer_name': customer,
- 'customer_type': 'Company',
- 'customer_group': _('Commercial'),
- 'territory': defaults.get('country'),
- 'company': company
- }).insert()
-
- if args.get('customer_email_' + str(i)):
- create_contact(customer, self.doctype,
- doc.name, args.get("customer_email_" + str(i)))
- except frappe.NameError:
- pass
-
def create_contact(contact, party_type, party, email):
"""Create contact based on given contact name"""
contact = contact.split(' ')
diff --git a/erpnext/selling/doctype/customer/test_customer.js b/erpnext/selling/doctype/customer/test_customer.js
deleted file mode 100644
index 65b81af32c1..00000000000
--- a/erpnext/selling/doctype/customer/test_customer.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Customer", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Customer
- () => frappe.tests.make('Customer', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index 5b337313d3d..73daa85986b 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -3,13 +3,14 @@
from __future__ import unicode_literals
-import frappe
import unittest
-from erpnext.accounts.party import get_due_date
+import frappe
from frappe.test_runner import make_test_records
-from erpnext.exceptions import PartyFrozen, PartyDisabled
from frappe.utils import flt
+
+from erpnext.accounts.party import get_due_date
+from erpnext.exceptions import PartyDisabled, PartyFrozen
from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding
from erpnext.tests.utils import create_test_contact_and_address
@@ -19,6 +20,7 @@ test_records = frappe.get_test_records('Customer')
from six import iteritems
+
class TestCustomer(unittest.TestCase):
def setUp(self):
if not frappe.get_value('Item', '_Test Item'):
@@ -253,10 +255,10 @@ class TestCustomer(unittest.TestCase):
return get_customer_outstanding('_Test Customer', '_Test Company')
def test_customer_credit_limit(self):
- from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
- from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
+ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
+ from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
outstanding_amt = self.get_customer_outstanding_amount()
credit_limit = get_credit_limit('_Test Customer', '_Test Company')
diff --git a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py
index 60a4a9a5d25..53bcc1b102e 100644
--- a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py
+++ b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class CustomerCreditLimit(Document):
pass
diff --git a/erpnext/selling/doctype/industry_type/industry_type.py b/erpnext/selling/doctype/industry_type/industry_type.py
index 7a30d6524a0..6d413ece2e7 100644
--- a/erpnext/selling/doctype/industry_type/industry_type.py
+++ b/erpnext/selling/doctype/industry_type/industry_type.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class IndustryType(Document):
pass
diff --git a/erpnext/selling/doctype/industry_type/test_industry_type.py b/erpnext/selling/doctype/industry_type/test_industry_type.py
index ebc6366155e..d6cf79ba89b 100644
--- a/erpnext/selling/doctype/industry_type/test_industry_type.py
+++ b/erpnext/selling/doctype/industry_type/test_industry_type.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Industry Type')
diff --git a/erpnext/selling/doctype/installation_note/installation_note.py b/erpnext/selling/doctype/installation_note/installation_note.py
index ffcbb2daf09..128a9415c87 100644
--- a/erpnext/selling/doctype/installation_note/installation_note.py
+++ b/erpnext/selling/doctype/installation_note/installation_note.py
@@ -2,15 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
+from frappe import _
from frappe.utils import cstr, getdate
-from frappe import _
from erpnext.stock.utils import get_valid_serial_nos
-
from erpnext.utilities.transaction_base import TransactionBase
+
class InstallationNote(TransactionBase):
def __init__(self, *args, **kwargs):
super(InstallationNote, self).__init__(*args, **kwargs)
diff --git a/erpnext/selling/doctype/installation_note/test_installation_note.py b/erpnext/selling/doctype/installation_note/test_installation_note.py
index 553d070da0f..abfda9cd6b8 100644
--- a/erpnext/selling/doctype/installation_note/test_installation_note.py
+++ b/erpnext/selling/doctype/installation_note/test_installation_note.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Installation Note')
diff --git a/erpnext/selling/doctype/installation_note_item/installation_note_item.py b/erpnext/selling/doctype/installation_note_item/installation_note_item.py
index 7e1205231bb..862c2a1bb51 100644
--- a/erpnext/selling/doctype/installation_note_item/installation_note_item.py
+++ b/erpnext/selling/doctype/installation_note_item/installation_note_item.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class InstallationNoteItem(Document):
pass
diff --git a/erpnext/selling/doctype/product_bundle/product_bundle.py b/erpnext/selling/doctype/product_bundle/product_bundle.py
index ae3482f402b..4c73916f852 100644
--- a/erpnext/selling/doctype/product_bundle/product_bundle.py
+++ b/erpnext/selling/doctype/product_bundle/product_bundle.py
@@ -2,13 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
+from frappe import _
+from frappe.model.document import Document
from frappe.utils import get_link_to_form
-from frappe import _
-
-from frappe.model.document import Document
class ProductBundle(Document):
def autoname(self):
diff --git a/erpnext/selling/doctype/product_bundle/test_product_bundle.py b/erpnext/selling/doctype/product_bundle/test_product_bundle.py
index 7d1d372b111..13bd2a30923 100644
--- a/erpnext/selling/doctype/product_bundle/test_product_bundle.py
+++ b/erpnext/selling/doctype/product_bundle/test_product_bundle.py
@@ -3,8 +3,8 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Product Bundle')
def make_product_bundle(parent, items, qty=None):
diff --git a/erpnext/selling/doctype/product_bundle_item/product_bundle_item.py b/erpnext/selling/doctype/product_bundle_item/product_bundle_item.py
index 8721bfad866..5f71a27f369 100644
--- a/erpnext/selling/doctype/product_bundle_item/product_bundle_item.py
+++ b/erpnext/selling/doctype/product_bundle_item/product_bundle_item.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ProductBundleItem(Document):
pass
diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js
index 5a0d9c90655..474cf56fc1b 100644
--- a/erpnext/selling/doctype/quotation/quotation.js
+++ b/erpnext/selling/doctype/quotation/quotation.js
@@ -18,6 +18,8 @@ frappe.ui.form.on('Quotation', {
}
});
+ frm.set_df_property('packed_items', 'cannot_add_rows', true);
+ frm.set_df_property('packed_items', 'cannot_delete_rows', true);
},
refresh: function(frm) {
diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json
index 3eba62bc193..43a44900fcb 100644
--- a/erpnext/selling/doctype/quotation/quotation.json
+++ b/erpnext/selling/doctype/quotation/quotation.json
@@ -43,6 +43,8 @@
"ignore_pricing_rule",
"items_section",
"items",
+ "bundle_items_section",
+ "packed_items",
"pricing_rule_details",
"pricing_rules",
"sec_break23",
@@ -926,6 +928,24 @@
"label": "Lost Reasons",
"options": "Quotation Lost Reason Detail",
"read_only": 1
+ },
+ {
+ "depends_on": "packed_items",
+ "fieldname": "packed_items",
+ "fieldtype": "Table",
+ "label": "Bundle Items",
+ "options": "Packed Item",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "packed_items",
+ "depends_on": "packed_items",
+ "fieldname": "bundle_items_section",
+ "fieldtype": "Section Break",
+ "label": "Bundle Items",
+ "options": "fa fa-suitcase",
+ "print_hide": 1
}
],
"icon": "fa fa-shopping-cart",
@@ -933,7 +953,7 @@
"is_submittable": 1,
"links": [],
"max_attachments": 1,
- "modified": "2020-10-30 13:58:59.212060",
+ "modified": "2021-08-27 20:10:07.864951",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation",
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index e4f8a475816..e9644cc722b 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -2,10 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.mapper import get_mapped_doc
-from frappe.utils import flt, nowdate, getdate
from frappe import _
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import flt, getdate, nowdate
from erpnext.controllers.selling_controller import SellingController
@@ -31,6 +32,9 @@ class Quotation(SellingController):
if self.items:
self.with_items = 1
+ from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
+ make_packing_list(self)
+
def validate_valid_till(self):
if self.valid_till and getdate(self.valid_till) < getdate(self.transaction_date):
frappe.throw(_("Valid till date cannot be before transaction date"))
@@ -270,7 +274,7 @@ def _make_customer(source_name, ignore_permissions=False):
customer = frappe.get_doc(customer_doclist)
customer.flags.ignore_permissions = ignore_permissions
if quotation.get("party_name") == "Shopping Cart":
- customer.customer_group = frappe.db.get_value("Shopping Cart Settings", None,
+ customer.customer_group = frappe.db.get_value("E Commerce Settings", None,
"default_customer_group")
try:
diff --git a/erpnext/selling/doctype/quotation/quotation_dashboard.py b/erpnext/selling/doctype/quotation/quotation_dashboard.py
index d1bb788937b..9586cb10b59 100644
--- a/erpnext/selling/doctype/quotation/quotation_dashboard.py
+++ b/erpnext/selling/doctype/quotation/quotation_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'prevdoc_docname',
diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py
index 527a999aefa..a44089a9ce4 100644
--- a/erpnext/selling/doctype/quotation/test_quotation.py
+++ b/erpnext/selling/doctype/quotation/test_quotation.py
@@ -2,10 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import flt, add_days, nowdate, add_months, getdate
import unittest
+import frappe
+from frappe.utils import add_days, add_months, flt, getdate, nowdate
+
test_dependencies = ["Product Bundle"]
@@ -133,8 +134,10 @@ class TestQuotation(unittest.TestCase):
def test_create_quotation_with_margin(self):
from erpnext.selling.doctype.quotation.quotation import make_sales_order
- from erpnext.selling.doctype.sales_order.sales_order \
- import make_delivery_note, make_sales_invoice
+ from erpnext.selling.doctype.sales_order.sales_order import (
+ make_delivery_note,
+ make_sales_invoice,
+ )
rate_with_margin = flt((1500*18.75)/100 + 1500)
@@ -226,9 +229,87 @@ class TestQuotation(unittest.TestCase):
expired_quotation.reload()
self.assertEqual(expired_quotation.status, "Expired")
+ def test_product_bundle_mapping_on_creating_so(self):
+ from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+ from erpnext.selling.doctype.quotation.quotation import make_sales_order
+ from erpnext.stock.doctype.item.test_item import make_item
+
+ make_item("_Test Product Bundle", {"is_stock_item": 0})
+ make_item("_Test Bundle Item 1", {"is_stock_item": 1})
+ make_item("_Test Bundle Item 2", {"is_stock_item": 1})
+
+ make_product_bundle("_Test Product Bundle",
+ ["_Test Bundle Item 1", "_Test Bundle Item 2"])
+
+ quotation = make_quotation(item_code="_Test Product Bundle", qty=1, rate=100)
+ sales_order = make_sales_order(quotation.name)
+
+ quotation_item = [quotation.items[0].item_code, quotation.items[0].rate, quotation.items[0].qty, quotation.items[0].amount]
+ so_item = [sales_order.items[0].item_code, sales_order.items[0].rate, sales_order.items[0].qty, sales_order.items[0].amount]
+
+ self.assertEqual(quotation_item, so_item)
+
+ quotation_packed_items = [
+ [quotation.packed_items[0].parent_item, quotation.packed_items[0].item_code, quotation.packed_items[0].qty],
+ [quotation.packed_items[1].parent_item, quotation.packed_items[1].item_code, quotation.packed_items[1].qty]
+ ]
+ so_packed_items = [
+ [sales_order.packed_items[0].parent_item, sales_order.packed_items[0].item_code, sales_order.packed_items[0].qty],
+ [sales_order.packed_items[1].parent_item, sales_order.packed_items[1].item_code, sales_order.packed_items[1].qty]
+ ]
+
+ self.assertEqual(quotation_packed_items, so_packed_items)
+
+ def test_product_bundle_price_calculation_when_calculate_bundle_price_is_unchecked(self):
+ from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+ from erpnext.stock.doctype.item.test_item import make_item
+
+ make_item("_Test Product Bundle", {"is_stock_item": 0})
+ bundle_item1 = make_item("_Test Bundle Item 1", {"is_stock_item": 1})
+ bundle_item2 = make_item("_Test Bundle Item 2", {"is_stock_item": 1})
+
+ make_product_bundle("_Test Product Bundle",
+ ["_Test Bundle Item 1", "_Test Bundle Item 2"])
+
+ bundle_item1.valuation_rate = 100
+ bundle_item1.save()
+
+ bundle_item2.valuation_rate = 200
+ bundle_item2.save()
+
+ quotation = make_quotation(item_code="_Test Product Bundle", qty=2, rate=100)
+ self.assertEqual(quotation.items[0].amount, 200)
+
+ def test_product_bundle_price_calculation_when_calculate_bundle_price_is_checked(self):
+ from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+ from erpnext.stock.doctype.item.test_item import make_item
+
+ make_item("_Test Product Bundle", {"is_stock_item": 0})
+ make_item("_Test Bundle Item 1", {"is_stock_item": 1})
+ make_item("_Test Bundle Item 2", {"is_stock_item": 1})
+
+ make_product_bundle("_Test Product Bundle",
+ ["_Test Bundle Item 1", "_Test Bundle Item 2"])
+
+ enable_calculate_bundle_price()
+
+ quotation = make_quotation(item_code="_Test Product Bundle", qty=2, rate=100, do_not_submit=1)
+ quotation.packed_items[0].rate = 100
+ quotation.packed_items[1].rate = 200
+ quotation.save()
+
+ self.assertEqual(quotation.items[0].amount, 600)
+ self.assertEqual(quotation.items[0].rate, 300)
+
+ enable_calculate_bundle_price(enable=0)
test_records = frappe.get_test_records('Quotation')
+def enable_calculate_bundle_price(enable=1):
+ selling_settings = frappe.get_doc("Selling Settings")
+ selling_settings.editable_bundle_item_rates = enable
+ selling_settings.save()
+
def get_quotation_dict(party_name=None, item_code=None):
if not party_name:
party_name = '_Test Customer'
diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json
index 8b53902d32f..31a95896bc1 100644
--- a/erpnext/selling/doctype/quotation_item/quotation_item.json
+++ b/erpnext/selling/doctype/quotation_item/quotation_item.json
@@ -649,7 +649,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2021-02-23 01:13:54.670763",
+ "modified": "2021-07-15 12:40:51.074820",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation Item",
diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.py b/erpnext/selling/doctype/quotation_item/quotation_item.py
index 7384871ed44..ea472497299 100644
--- a/erpnext/selling/doctype/quotation_item/quotation_item.py
+++ b/erpnext/selling/doctype/quotation_item/quotation_item.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class QuotationItem(Document):
pass
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index e3b41e66fbc..1961371d0b8 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -43,6 +43,9 @@ frappe.ui.form.on("Sales Order", {
}
}
});
+
+ frm.set_df_property('packed_items', 'cannot_add_rows', true);
+ frm.set_df_property('packed_items', 'cannot_delete_rows', true);
},
refresh: function(frm) {
if(frm.doc.docstatus === 1 && frm.doc.status !== 'Closed'
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index 38ea5c81d49..85282ca1a07 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -55,6 +55,8 @@
"items_section",
"scan_barcode",
"items",
+ "packing_list",
+ "packed_items",
"pricing_rule_details",
"pricing_rules",
"section_break_31",
@@ -101,8 +103,6 @@
"in_words",
"advance_paid",
"disable_rounded_total",
- "packing_list",
- "packed_items",
"payment_schedule_section",
"payment_terms_template",
"payment_schedule",
@@ -1019,6 +1019,7 @@
{
"collapsible": 1,
"collapsible_depends_on": "packed_items",
+ "depends_on": "packed_items",
"fieldname": "packing_list",
"fieldtype": "Section Break",
"hide_days": 1,
@@ -1029,14 +1030,14 @@
"print_hide": 1
},
{
+ "depends_on": "packed_items",
"fieldname": "packed_items",
"fieldtype": "Table",
"hide_days": 1,
"hide_seconds": 1,
"label": "Packed Items",
"options": "Packed Item",
- "print_hide": 1,
- "read_only": 1
+ "print_hide": 1
},
{
"fieldname": "payment_schedule_section",
@@ -1511,7 +1512,7 @@
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2021-08-17 20:15:26.531553",
+ "modified": "2021-09-01 15:12:24.115483",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index bba54018aef..93676094218 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -2,24 +2,32 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import json
+
+import frappe
import frappe.utils
-from frappe.utils import cstr, flt, getdate, cint, nowdate, add_days, get_link_to_form, strip_html
from frappe import _
-from six import string_types
-from frappe.model.utils import get_fetch_values
-from frappe.model.mapper import get_mapped_doc
-from erpnext.stock.stock_balance import update_bin_qty, get_reserved_qty
-from frappe.desk.notifications import clear_doctype_notifications
from frappe.contacts.doctype.address.address import get_company_address
+from frappe.desk.notifications import clear_doctype_notifications
+from frappe.model.mapper import get_mapped_doc
+from frappe.model.utils import get_fetch_values
+from frappe.utils import add_days, cint, cstr, flt, get_link_to_form, getdate, nowdate, strip_html
+from six import string_types
+
+from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
+ unlink_inter_company_doc,
+ update_linked_doc,
+ validate_inter_company_party,
+)
from erpnext.controllers.selling_controller import SellingController
+from erpnext.manufacturing.doctype.production_plan.production_plan import (
+ get_items_for_material_requests,
+)
from erpnext.selling.doctype.customer.customer import check_credit_limit
-from erpnext.stock.doctype.item.item import get_item_defaults
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
-from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests
-from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\
- unlink_inter_company_doc
+from erpnext.stock.doctype.item.item import get_item_defaults
+from erpnext.stock.stock_balance import get_reserved_qty, update_bin_qty
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@@ -718,8 +726,7 @@ def make_maintenance_schedule(source_name, target_doc=None):
"doctype": "Maintenance Schedule Item",
"field_map": {
"parent": "sales_order"
- },
- "add_if_empty": True
+ }
}
}, target_doc)
@@ -745,8 +752,7 @@ def make_maintenance_visit(source_name, target_doc=None):
"field_map": {
"parent": "prevdoc_docname",
"parenttype": "prevdoc_doctype"
- },
- "add_if_empty": True
+ }
}
}, target_doc)
@@ -949,11 +955,52 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None):
"pricing_rules"
],
"postprocess": update_item,
- "condition": lambda doc: doc.ordered_qty < doc.stock_qty and doc.item_code in items_to_map
+ "condition": lambda doc: doc.ordered_qty < doc.stock_qty and doc.item_code in items_to_map and not is_product_bundle(doc.item_code)
+ },
+ "Packed Item": {
+ "doctype": "Purchase Order Item",
+ "field_map": [
+ ["parent", "sales_order"],
+ ["uom", "uom"],
+ ["conversion_factor", "conversion_factor"],
+ ["parent_item", "product_bundle"],
+ ["rate", "rate"]
+ ],
+ "field_no_map": [
+ "price_list_rate",
+ "item_tax_template",
+ "discount_percentage",
+ "discount_amount",
+ "supplier",
+ "pricing_rules"
+ ],
}
}, target_doc, set_missing_values)
+
+ set_delivery_date(doc.items, source_name)
+
return doc
+def set_delivery_date(items, sales_order):
+ delivery_dates = frappe.get_all(
+ 'Sales Order Item',
+ filters = {
+ 'parent': sales_order
+ },
+ fields = ['delivery_date', 'item_code']
+ )
+
+ delivery_by_item = frappe._dict()
+ for date in delivery_dates:
+ delivery_by_item[date.item_code] = date.delivery_date
+
+ for item in items:
+ if item.product_bundle:
+ item.schedule_date = delivery_by_item[item.product_bundle]
+
+def is_product_bundle(item_code):
+ return frappe.db.exists('Product Bundle', item_code)
+
@frappe.whitelist()
def make_work_orders(items, sales_order, company, project=None):
'''Make Work Orders against the given Sales Order for the given `items`'''
diff --git a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
index 2a71c27009f..ee3c707b5b8 100644
--- a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
+++ b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'sales_order',
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.js b/erpnext/selling/doctype/sales_order/test_sales_order.js
deleted file mode 100644
index 57ed19b6965..00000000000
--- a/erpnext/selling/doctype/sales_order/test_sales_order.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Sales Order", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially('Sales Order', [
- // insert a new Sales Order
- () => frappe.tests.make([
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index d685fbff82b..62ea44df435 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1,21 +1,29 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import json
import unittest
+
import frappe
import frappe.permissions
-from frappe.utils import flt, add_days, nowdate, getdate
from frappe.core.doctype.user_permission.test_user_permission import create_user
-from erpnext.selling.doctype.sales_order.sales_order \
- import make_material_request, make_delivery_note, make_sales_invoice, WarehouseRequired
-from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
-from erpnext.selling.doctype.sales_order.sales_order import make_work_orders
+from frappe.utils import add_days, flt, getdate, nowdate
+
from erpnext.controllers.accounts_controller import update_child_qty_rate
-from erpnext.selling.doctype.sales_order.sales_order import make_raw_material_request
from erpnext.manufacturing.doctype.blanket_order.test_blanket_order import make_blanket_order
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+from erpnext.selling.doctype.sales_order.sales_order import (
+ WarehouseRequired,
+ make_delivery_note,
+ make_material_request,
+ make_raw_material_request,
+ make_sales_invoice,
+ make_work_orders,
+)
from erpnext.stock.doctype.item.test_item import make_item
+from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+
class TestSalesOrder(unittest.TestCase):
@@ -162,8 +170,8 @@ class TestSalesOrder(unittest.TestCase):
self.assertEqual(so.get("items")[0].delivered_qty, 9)
# Make return deliver note, sales invoice and check quantity
- from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+ from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-3, do_not_submit=True)
dn1.items[0].against_sales_order = so.name
@@ -444,8 +452,8 @@ class TestSalesOrder(unittest.TestCase):
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Sales Order', trans_item, so.name)
def test_update_child_with_precision(self):
- from frappe.model.meta import get_field_precision
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
+ from frappe.model.meta import get_field_precision
precision = get_field_precision(frappe.get_meta("Sales Order Item").get_field("rate"))
@@ -731,9 +739,11 @@ class TestSalesOrder(unittest.TestCase):
frappe.db.set_value("Stock Settings", None, "auto_insert_price_list_rate_if_missing", 1)
def test_drop_shipping(self):
- from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_default_supplier, \
- update_status as so_update_status
from erpnext.buying.doctype.purchase_order.purchase_order import update_status
+ from erpnext.selling.doctype.sales_order.sales_order import (
+ make_purchase_order_for_default_supplier,
+ )
+ from erpnext.selling.doctype.sales_order.sales_order import update_status as so_update_status
# make items
po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 1, "delivered_by_supplier": 1})
@@ -815,8 +825,10 @@ class TestSalesOrder(unittest.TestCase):
so.cancel()
def test_drop_shipping_partial_order(self):
- from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_default_supplier, \
- update_status as so_update_status
+ from erpnext.selling.doctype.sales_order.sales_order import (
+ make_purchase_order_for_default_supplier,
+ )
+ from erpnext.selling.doctype.sales_order.sales_order import update_status as so_update_status
# make items
po_item1 = make_item("_Test Item for Drop Shipping 1", {"is_stock_item": 1, "delivered_by_supplier": 1})
@@ -869,7 +881,9 @@ class TestSalesOrder(unittest.TestCase):
def test_drop_shipping_full_for_default_suppliers(self):
"""Test if multiple POs are generated in one go against different default suppliers."""
- from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_default_supplier
+ from erpnext.selling.doctype.sales_order.sales_order import (
+ make_purchase_order_for_default_supplier,
+ )
if not frappe.db.exists("Item", "_Test Item for Drop Shipping 1"):
make_item("_Test Item for Drop Shipping 1", {"is_stock_item": 1, "delivered_by_supplier": 1})
@@ -1043,8 +1057,7 @@ class TestSalesOrder(unittest.TestCase):
}]
})
so.submit()
- from erpnext.manufacturing.doctype.work_order.test_work_order import \
- make_wo_order_test_record
+ from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
work_order = make_wo_order_test_record(item=item.item_code,
qty=1, do_not_save=True)
work_order.fg_warehouse = "_Test Warehouse - _TC"
@@ -1052,8 +1065,9 @@ class TestSalesOrder(unittest.TestCase):
work_order.submit()
make_stock_entry(item_code=item.item_code, target="_Test Warehouse - _TC", qty=1)
item_serial_no = frappe.get_doc("Serial No", {"item_code": item.item_code})
- from erpnext.manufacturing.doctype.work_order.work_order import \
- make_stock_entry as make_production_stock_entry
+ from erpnext.manufacturing.doctype.work_order.work_order import (
+ make_stock_entry as make_production_stock_entry,
+ )
se = frappe.get_doc(make_production_stock_entry(work_order.name, "Manufacture", 1))
se.submit()
reserved_serial_no = se.get("items")[2].serial_no
@@ -1085,8 +1099,9 @@ class TestSalesOrder(unittest.TestCase):
si = make_sales_invoice(so.name)
si.update_stock = 0
si.submit()
- from erpnext.accounts.doctype.sales_invoice.sales_invoice import \
- make_delivery_note as make_delivery_note_from_invoice
+ from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
+ make_delivery_note as make_delivery_note_from_invoice,
+ )
dn = make_delivery_note_from_invoice(si.name)
dn.save()
dn.submit()
@@ -1123,6 +1138,7 @@ class TestSalesOrder(unittest.TestCase):
def test_cancel_sales_order_after_cancel_payment_entry(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
+
# make a sales order
so = make_sales_order()
@@ -1232,7 +1248,9 @@ class TestSalesOrder(unittest.TestCase):
self.assertRaises(frappe.ValidationError, so.cancel)
def test_payment_terms_are_fetched_when_creating_sales_invoice(self):
- from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
+ from erpnext.accounts.doctype.payment_entry.test_payment_entry import (
+ create_payment_terms_template,
+ )
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
automatically_fetch_payment_terms()
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.py b/erpnext/selling/doctype/sales_order_item/sales_order_item.py
index 62afef3e170..772aa6c8ae5 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.py
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.py
@@ -2,10 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
from frappe.model.document import Document
+
class SalesOrderItem(Document):
pass
diff --git a/erpnext/selling/doctype/sales_partner_type/sales_partner_type.py b/erpnext/selling/doctype/sales_partner_type/sales_partner_type.py
index 68d289f0189..bdabef2fdbe 100644
--- a/erpnext/selling/doctype/sales_partner_type/sales_partner_type.py
+++ b/erpnext/selling/doctype/sales_partner_type/sales_partner_type.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class SalesPartnerType(Document):
pass
diff --git a/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.js b/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.js
deleted file mode 100644
index 3ed7b46e1d9..00000000000
--- a/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Sales Partner Type", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Sales Partner Type
- () => frappe.tests.make('Sales Partner Type', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.py b/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.py
index fb8f8b0417a..895b0ecf00a 100644
--- a/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.py
+++ b/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestSalesPartnerType(unittest.TestCase):
pass
diff --git a/erpnext/selling/doctype/sales_team/sales_team.py b/erpnext/selling/doctype/sales_team/sales_team.py
index 28bea254d68..9b542c0eead 100644
--- a/erpnext/selling/doctype/sales_team/sales_team.py
+++ b/erpnext/selling/doctype/sales_team/sales_team.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class SalesTeam(Document):
pass
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json
index f01934b7e6b..28c7e5a4f53 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.json
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.json
@@ -6,24 +6,32 @@
"document_type": "Other",
"engine": "InnoDB",
"field_order": [
+ "customer_defaults_section",
"cust_master_name",
- "campaign_naming_by",
"customer_group",
+ "column_break_4",
"territory",
- "selling_price_list",
- "close_opportunity_after_days",
+ "crm_settings_section",
+ "campaign_naming_by",
"default_valid_till",
- "column_break_5",
+ "column_break_9",
+ "close_opportunity_after_days",
+ "item_price_settings_section",
+ "selling_price_list",
+ "maintain_same_rate_action",
+ "role_to_override_stop_action",
+ "column_break_15",
+ "maintain_same_sales_rate",
+ "editable_price_list_rate",
+ "validate_selling_price",
+ "editable_bundle_item_rates",
+ "transaction_settings_section",
"so_required",
"dn_required",
"sales_update_frequency",
- "maintain_same_sales_rate",
- "maintain_same_rate_action",
- "role_to_override_stop_action",
- "editable_price_list_rate",
+ "column_break_5",
"allow_multiple_items",
"allow_against_multiple_purchase_orders",
- "validate_selling_price",
"hide_tax_id"
],
"fields": [
@@ -75,10 +83,6 @@
"fieldtype": "Data",
"label": "Default Quotation Validity Days"
},
- {
- "fieldname": "column_break_5",
- "fieldtype": "Column Break"
- },
{
"fieldname": "so_required",
"fieldtype": "Select",
@@ -152,6 +156,48 @@
"fieldtype": "Link",
"label": "Role Allowed to Override Stop Action",
"options": "Role"
+ },
+ {
+ "fieldname": "column_break_15",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "editable_bundle_item_rates",
+ "fieldtype": "Check",
+ "label": "Calculate Product Bundle Price based on Child Items' Rates"
+ },
+ {
+ "fieldname": "customer_defaults_section",
+ "fieldtype": "Section Break",
+ "label": "Customer Defaults"
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "crm_settings_section",
+ "fieldtype": "Section Break",
+ "label": "CRM Settings"
+ },
+ {
+ "fieldname": "column_break_9",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "item_price_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Item Price Settings"
+ },
+ {
+ "fieldname": "transaction_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Transaction Settings"
+ },
+ {
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
}
],
"icon": "fa fa-cog",
@@ -159,7 +205,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-04-04 20:18:12.814624",
+ "modified": "2021-09-06 22:05:06.139820",
"modified_by": "Administrator",
"module": "Selling",
"name": "Selling Settings",
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.py b/erpnext/selling/doctype/selling_settings/selling_settings.py
index b219e7ecce0..5bed43e4609 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.py
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.py
@@ -4,17 +4,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-import frappe.defaults
-from frappe.utils import cint
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
+from frappe.model.document import Document
+from frappe.utils import cint
from frappe.utils.nestedset import get_root_of
-from frappe.model.document import Document
class SellingSettings(Document):
def on_update(self):
self.toggle_hide_tax_id()
+ self.toggle_editable_rate_for_bundle_items()
def validate(self):
for key in ["cust_master_name", "campaign_naming_by", "customer_group", "territory",
@@ -33,6 +34,11 @@ class SellingSettings(Document):
make_property_setter(doctype, "tax_id", "hidden", self.hide_tax_id, "Check", validate_fields_for_doctype=False)
make_property_setter(doctype, "tax_id", "print_hide", self.hide_tax_id, "Check", validate_fields_for_doctype=False)
+ def toggle_editable_rate_for_bundle_items(self):
+ editable_bundle_item_rates = cint(self.editable_bundle_item_rates)
+
+ make_property_setter("Packed Item", "rate", "read_only", not(editable_bundle_item_rates), "Check", validate_fields_for_doctype=False)
+
def set_default_customer_group_and_territory(self):
if not self.customer_group:
self.customer_group = get_root_of('Customer Group')
diff --git a/erpnext/selling/doctype/selling_settings/test_selling_settings.py b/erpnext/selling/doctype/selling_settings/test_selling_settings.py
index 961a54de0a8..572a110cc3e 100644
--- a/erpnext/selling/doctype/selling_settings/test_selling_settings.py
+++ b/erpnext/selling/doctype/selling_settings/test_selling_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestSellingSettings(unittest.TestCase):
pass
diff --git a/erpnext/selling/doctype/sms_center/sms_center.py b/erpnext/selling/doctype/sms_center/sms_center.py
index 87846a84d30..45aee4ea6f0 100644
--- a/erpnext/selling/doctype/sms_center/sms_center.py
+++ b/erpnext/selling/doctype/sms_center/sms_center.py
@@ -2,14 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-
-from frappe.utils import cstr
-from frappe import msgprint, _
-
-from frappe.model.document import Document
-
+from frappe import _, msgprint
from frappe.core.doctype.sms_settings.sms_settings import send_sms
+from frappe.model.document import Document
+from frappe.utils import cstr
+
class SMSCenter(Document):
@frappe.whitelist()
diff --git a/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json b/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json
deleted file mode 100644
index 92d00bcb380..00000000000
--- a/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "add_more_button": 1,
- "app": "ERPNext",
- "creation": "2019-11-15 14:44:10.065014",
- "docstatus": 0,
- "doctype": "Onboarding Slide",
- "domains": [],
- "help_links": [
- {
- "label": "Learn More",
- "video_id": "zsrrVDk6VBs"
- }
- ],
- "idx": 0,
- "image_src": "",
- "is_completed": 0,
- "max_count": 3,
- "modified": "2019-12-09 17:54:01.686006",
- "modified_by": "Administrator",
- "name": "Add A Few Customers",
- "owner": "Administrator",
- "ref_doctype": "Customer",
- "slide_desc": "",
- "slide_fields": [
- {
- "align": "",
- "fieldname": "customer_name",
- "fieldtype": "Data",
- "label": "Customer Name",
- "placeholder": "",
- "reqd": 1
- },
- {
- "align": "",
- "fieldtype": "Column Break",
- "reqd": 0
- },
- {
- "align": "",
- "fieldname": "customer_email",
- "fieldtype": "Data",
- "label": "Email ID",
- "reqd": 1
- }
- ],
- "slide_order": 40,
- "slide_title": "Add A Few Customers",
- "slide_type": "Create"
-}
\ No newline at end of file
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py
index 03c46bb2ae0..b4338c920a9 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -2,11 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, json
+
+import json
+
+import frappe
from frappe.utils.nestedset import get_root_of
-from frappe.utils import cint
-from erpnext.accounts.doctype.pos_profile.pos_profile import get_item_groups
+
from erpnext.accounts.doctype.pos_invoice.pos_invoice import get_stock_availability
+from erpnext.accounts.doctype.pos_profile.pos_profile import get_item_groups
+
def search_by_term(search_term, warehouse, price_list):
result = search_for_serial_or_batch_or_barcode_number(search_term) or {}
@@ -209,7 +213,6 @@ def check_opening_entry(user):
@frappe.whitelist()
def create_opening_voucher(pos_profile, company, balance_details):
- import json
balance_details = json.loads(balance_details)
new_pos_opening = frappe.get_doc({
diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js
index 63306adc6fa..7ddbf45fdb8 100644
--- a/erpnext/selling/page/point_of_sale/pos_payment.js
+++ b/erpnext/selling/page/point_of_sale/pos_payment.js
@@ -253,41 +253,6 @@ erpnext.PointOfSale.Payment = class {
}
}
- setup_listener_for_payments() {
- frappe.realtime.on("process_phone_payment", (data) => {
- const doc = this.events.get_frm().doc;
- const { response, amount, success, failure_message } = data;
- let message, title;
-
- if (success) {
- title = __("Payment Received");
- if (amount >= doc.grand_total) {
- frappe.dom.unfreeze();
- message = __("Payment of {0} received successfully.", [format_currency(amount, doc.currency, 0)]);
- this.events.submit_invoice();
- cur_frm.reload_doc();
-
- } else {
- message = __("Payment of {0} received successfully. Waiting for other requests to complete...", [format_currency(amount, doc.currency, 0)]);
- }
- } else if (failure_message) {
- message = failure_message;
- title = __("Payment Failed");
- }
-
- frappe.msgprint({ "message": message, "title": title });
- });
- }
-
- auto_set_remaining_amount() {
- const doc = this.events.get_frm().doc;
- const remaining_amount = doc.grand_total - doc.paid_amount;
- const current_value = this.selected_mode ? this.selected_mode.get_value() : undefined;
- if (!current_value && remaining_amount > 0 && this.selected_mode) {
- this.selected_mode.set_value(remaining_amount);
- }
- }
-
attach_shortcuts() {
const ctrl_label = frappe.utils.is_mac() ? '⌘' : 'Ctrl';
this.$component.find('.submit-order-btn').attr("title", `${ctrl_label}+Enter`);
@@ -332,6 +297,7 @@ erpnext.PointOfSale.Payment = class {
this.render_payment_mode_dom();
this.make_invoice_fields_control();
this.update_totals_section();
+ this.focus_on_default_mop();
}
edit_cart() {
@@ -413,17 +379,24 @@ erpnext.PointOfSale.Payment = class {
});
this[`${mode}_control`].toggle_label(false);
this[`${mode}_control`].set_value(p.amount);
+ });
+ this.render_loyalty_points_payment_mode();
+
+ this.attach_cash_shortcuts(doc);
+ }
+
+ focus_on_default_mop() {
+ const doc = this.events.get_frm().doc;
+ const payments = doc.payments;
+ payments.forEach(p => {
+ const mode = p.mode_of_payment.replace(/ +/g, "_").toLowerCase();
if (p.default) {
setTimeout(() => {
this.$payment_modes.find(`.${mode}.mode-of-payment-control`).parent().click();
}, 500);
}
});
-
- this.render_loyalty_points_payment_mode();
-
- this.attach_cash_shortcuts(doc);
}
attach_cash_shortcuts(doc) {
diff --git a/erpnext/selling/page/sales_funnel/sales_funnel.py b/erpnext/selling/page/sales_funnel/sales_funnel.py
index 78aaa49a668..043a3e7f0fa 100644
--- a/erpnext/selling/page/sales_funnel/sales_funnel.py
+++ b/erpnext/selling/page/sales_funnel/sales_funnel.py
@@ -2,11 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe import _
-from erpnext.accounts.report.utils import convert
+import frappe
import pandas as pd
+from frappe import _
+
+from erpnext.accounts.report.utils import convert
+
def validate_filters(from_date, to_date, company):
if from_date and to_date and (from_date >= to_date):
diff --git a/erpnext/selling/report/address_and_contacts/address_and_contacts.py b/erpnext/selling/report/address_and_contacts/address_and_contacts.py
index f295333322c..fea19f9f16d 100644
--- a/erpnext/selling/report/address_and_contacts/address_and_contacts.py
+++ b/erpnext/selling/report/address_and_contacts/address_and_contacts.py
@@ -2,10 +2,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from six.moves import range
-from six import iteritems
-import frappe
+import frappe
+from six import iteritems
+from six.moves import range
field_map = {
"Contact": [ "first_name", "last_name", "phone", "mobile_no", "email_id", "is_primary_contact" ],
diff --git a/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py b/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py
index 5523bad5715..c7040bef708 100644
--- a/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py
+++ b/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.utils import flt
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py
index f15f63d7bb7..a29b5c8a627 100644
--- a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py
+++ b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py
@@ -2,11 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import calendar
+
import frappe
from frappe import _
from frappe.utils import cint, cstr, getdate
+
def execute(filters=None):
common_columns = [
{
diff --git a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
index 6fb7666c2ce..ed2fbfd595c 100644
--- a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
+++ b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
@@ -2,10 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt
-from erpnext.selling.doctype.customer.customer import get_customer_outstanding, get_credit_limit
+
+from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py b/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py
index eb9273a5626..535d551cfab 100644
--- a/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py
+++ b/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py
@@ -4,10 +4,11 @@
from __future__ import unicode_literals
import frappe
+from frappe import _
+
from erpnext import get_default_company
from erpnext.accounts.party import get_party_details
from erpnext.stock.get_item_details import get_price_list_rate_for
-from frappe import _
def execute(filters=None):
diff --git a/erpnext/selling/report/inactive_customers/inactive_customers.py b/erpnext/selling/report/inactive_customers/inactive_customers.py
index e7aff36e828..c79efe24b78 100644
--- a/erpnext/selling/report/inactive_customers/inactive_customers.py
+++ b/erpnext/selling/report/inactive_customers/inactive_customers.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import cint
from frappe import _
+from frappe.utils import cint
+
def execute(filters=None):
if not filters: filters ={}
diff --git a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
index 1700fc7bdd5..539631240e1 100644
--- a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
+++ b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
@@ -2,11 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt
from frappe.utils.nestedset import get_descendants_of
+
def execute(filters=None):
filters = frappe._dict(filters or {})
if filters.from_date > filters.to_date:
diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py
index e89c45182fd..f241a3e13d9 100644
--- a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py
+++ b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py
@@ -2,10 +2,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt
+
def execute(filters=None):
columns = get_columns()
data = get_data()
diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py
index f2518f09f8e..95e332ac537 100644
--- a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py
+++ b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py
@@ -2,12 +2,16 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import unittest
-from frappe.utils import nowdate, add_months
-from erpnext.selling.report.pending_so_items_for_purchase_request.pending_so_items_for_purchase_request\
- import execute
+
+from frappe.utils import add_months, nowdate
+
from erpnext.selling.doctype.sales_order.sales_order import make_material_request
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
+from erpnext.selling.report.pending_so_items_for_purchase_request.pending_so_items_for_purchase_request import (
+ execute,
+)
class TestPendingSOItemsForPurchaseRequest(unittest.TestCase):
diff --git a/erpnext/selling/report/quotation_trends/quotation_trends.py b/erpnext/selling/report/quotation_trends/quotation_trends.py
index 968e2ff26f7..d2ee9a8b742 100644
--- a/erpnext/selling/report/quotation_trends/quotation_trends.py
+++ b/erpnext/selling/report/quotation_trends/quotation_trends.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe import _
-from erpnext.controllers.trends import get_columns, get_data
+
+from erpnext.controllers.trends import get_columns, get_data
+
def execute(filters=None):
if not filters: filters ={}
diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py
index d036a1cb095..56bcb3180a3 100644
--- a/erpnext/selling/report/sales_analytics/sales_analytics.py
+++ b/erpnext/selling/report/sales_analytics/sales_analytics.py
@@ -2,12 +2,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _, scrub
-from frappe.utils import getdate, flt, add_to_date, add_days
+from frappe.utils import add_days, add_to_date, flt, getdate
from six import iteritems
+
from erpnext.accounts.utils import get_fiscal_year
+
def execute(filters=None):
return Analytics(filters).run()
@@ -293,7 +296,7 @@ class Analytics(object):
return period
def get_period_date_ranges(self):
- from dateutil.relativedelta import relativedelta, MO
+ from dateutil.relativedelta import MO, relativedelta
from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date)
increment = {
diff --git a/erpnext/selling/report/sales_analytics/test_analytics.py b/erpnext/selling/report/sales_analytics/test_analytics.py
index 4d81a1e4dda..a1800993f4f 100644
--- a/erpnext/selling/report/sales_analytics/test_analytics.py
+++ b/erpnext/selling/report/sales_analytics/test_analytics.py
@@ -2,11 +2,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-import frappe.defaults
+
import unittest
-from erpnext.selling.report.sales_analytics.sales_analytics import execute
+
+import frappe
+
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
+from erpnext.selling.report.sales_analytics.sales_analytics import execute
+
class TestAnalytics(unittest.TestCase):
def test_sales_analytics(self):
diff --git a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
index 00dcd69c6e6..805c3d804fa 100644
--- a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
+++ b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
@@ -2,10 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import copy
+
+import frappe
from frappe import _
-from frappe.utils import flt, date_diff, getdate
+from frappe.utils import date_diff, flt, getdate
+
def execute(filters=None):
if not filters:
diff --git a/erpnext/selling/report/sales_order_trends/sales_order_trends.py b/erpnext/selling/report/sales_order_trends/sales_order_trends.py
index de7d3f2f778..89daf447781 100644
--- a/erpnext/selling/report/sales_order_trends/sales_order_trends.py
+++ b/erpnext/selling/report/sales_order_trends/sales_order_trends.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe import _
-from erpnext.controllers.trends import get_columns,get_data
+
+from erpnext.controllers.trends import get_columns, get_data
+
def execute(filters=None):
if not filters: filters ={}
diff --git a/erpnext/selling/report/sales_partner_commission_summary/sales_partner_commission_summary.py b/erpnext/selling/report/sales_partner_commission_summary/sales_partner_commission_summary.py
index 2c49d51a920..a84dec032e5 100644
--- a/erpnext/selling/report/sales_partner_commission_summary/sales_partner_commission_summary.py
+++ b/erpnext/selling/report/sales_partner_commission_summary/sales_partner_commission_summary.py
@@ -2,9 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import msgprint, _
-from frappe.utils import flt
+from frappe import _, msgprint
def execute(filters=None):
diff --git a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
index 89cfa16abe0..d4f49c71464 100644
--- a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
+++ b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
@@ -2,12 +2,16 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt
-from erpnext.accounts.utils import get_fiscal_year
+
+from erpnext.accounts.doctype.monthly_distribution.monthly_distribution import (
+ get_periodwise_distribution_data,
+)
from erpnext.accounts.report.financial_statements import get_period_list
-from erpnext.accounts.doctype.monthly_distribution.monthly_distribution import get_periodwise_distribution_data
+from erpnext.accounts.utils import get_fiscal_year
+
def get_data_column(filters, partner_doctype):
data = []
diff --git a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py
index 87ed5a8ea21..de21c4ad02d 100644
--- a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py
+++ b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py
@@ -2,8 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import get_data_column
+
+from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import (
+ get_data_column,
+)
+
def execute(filters=None):
data = []
diff --git a/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py b/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py
index f07293d8ec2..39ec072f6ba 100644
--- a/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py
+++ b/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py
@@ -2,9 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import msgprint, _
-from frappe.utils import flt
+from frappe import _, msgprint
def execute(filters=None):
diff --git a/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py b/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py
index 9917d72af86..13245b789ef 100644
--- a/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py
+++ b/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py
@@ -2,9 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import msgprint, _
-from frappe.utils import flt
+from frappe import _, msgprint
def execute(filters=None):
diff --git a/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py b/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py
index ea9bbab0c72..83a1c2ce75c 100644
--- a/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py
+++ b/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py
@@ -2,8 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import get_data_column
+
+from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import (
+ get_data_column,
+)
+
def execute(filters=None):
data = []
diff --git a/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py b/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py
index 41c7f765175..9dc2923b0a2 100644
--- a/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py
+++ b/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py
@@ -2,11 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import msgprint, _
-from frappe.utils import flt
+from frappe import _, msgprint
+
from erpnext import get_company_currency
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.py b/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.py
index b1d89cc3fb8..b340124a040 100644
--- a/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.py
+++ b/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.py
@@ -2,8 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import get_data_column
+
+from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import (
+ get_data_column,
+)
+
def execute(filters=None):
data = []
diff --git a/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py b/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py
index e8835001707..c334381b430 100644
--- a/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py
+++ b/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py
@@ -2,10 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from erpnext import get_default_currency
from frappe import _
+from erpnext import get_default_currency
+
+
def execute(filters=None):
filters = frappe._dict(filters)
columns = get_columns()
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 26ac630a32b..a068430c6c1 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -90,10 +90,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
this.frm.toggle_display("customer_name",
(this.frm.doc.customer_name && this.frm.doc.customer_name!==this.frm.doc.customer));
- if(this.frm.fields_dict.packed_items) {
- var packing_list_exists = (this.frm.doc.packed_items || []).length;
- this.frm.toggle_display("packing_list", packing_list_exists ? true : false);
- }
+
this.toggle_editable_price_list_rate();
},
@@ -246,7 +243,12 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
var editable_price_list_rate = cint(frappe.defaults.get_default("editable_price_list_rate"));
if(df && editable_price_list_rate) {
- df.read_only = 0;
+ const parent_field = frappe.meta.get_parentfield(this.frm.doc.doctype, this.frm.doc.doctype + " Item");
+ if (!this.frm.fields_dict[parent_field]) return;
+
+ this.frm.fields_dict[parent_field].grid.update_docfield_property(
+ 'price_list_rate', 'read_only', 0
+ );
}
},
diff --git a/erpnext/setup/default_energy_point_rules.py b/erpnext/setup/default_energy_point_rules.py
index 8dbccc497b7..c41d000215b 100644
--- a/erpnext/setup/default_energy_point_rules.py
+++ b/erpnext/setup/default_energy_point_rules.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
from frappe import _
doctype_rule_map = {
diff --git a/erpnext/setup/default_success_action.py b/erpnext/setup/default_success_action.py
index 827839f8b75..be072fc47f3 100644
--- a/erpnext/setup/default_success_action.py
+++ b/erpnext/setup/default_success_action.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
from frappe import _
doctype_list = [
diff --git a/erpnext/setup/doctype/authorization_control/authorization_control.py b/erpnext/setup/doctype/authorization_control/authorization_control.py
index fec5c7ca95d..332d7f438a7 100644
--- a/erpnext/setup/doctype/authorization_control/authorization_control.py
+++ b/erpnext/setup/doctype/authorization_control/authorization_control.py
@@ -2,11 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import cstr, flt, has_common, comma_or
-from frappe import session, _
+from frappe import _, session
+from frappe.utils import comma_or, cstr, flt, has_common
+
from erpnext.utilities.transaction_base import TransactionBase
+
class AuthorizationControl(TransactionBase):
def get_appr_user_role(self, det, doctype_name, total, based_on, condition, item, company):
amt_list, appr_users, appr_roles = [], [], []
diff --git a/erpnext/setup/doctype/authorization_rule/authorization_rule.py b/erpnext/setup/doctype/authorization_rule/authorization_rule.py
index eb8e6ebe78c..ab0f4201219 100644
--- a/erpnext/setup/doctype/authorization_rule/authorization_rule.py
+++ b/erpnext/setup/doctype/authorization_rule/authorization_rule.py
@@ -2,12 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-
-from frappe.utils import cstr, flt
-from frappe import _, msgprint
-
+from frappe import _
from frappe.model.document import Document
+from frappe.utils import cstr, flt
+
class AuthorizationRule(Document):
def check_duplicate_entry(self):
diff --git a/erpnext/setup/doctype/authorization_rule/test_authorization_rule.py b/erpnext/setup/doctype/authorization_rule/test_authorization_rule.py
index 332f1039921..8a0f6649078 100644
--- a/erpnext/setup/doctype/authorization_rule/test_authorization_rule.py
+++ b/erpnext/setup/doctype/authorization_rule/test_authorization_rule.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Authorization Rule')
diff --git a/erpnext/setup/doctype/brand/brand.json b/erpnext/setup/doctype/brand/brand.json
index a8f0674b1f8..45b4db81f1f 100644
--- a/erpnext/setup/doctype/brand/brand.json
+++ b/erpnext/setup/doctype/brand/brand.json
@@ -1,270 +1,111 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:brand",
- "beta": 0,
- "creation": "2013-02-22 01:27:54",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:brand",
+ "creation": "2013-02-22 01:27:54",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "brand",
+ "image",
+ "description",
+ "defaults",
+ "brand_defaults"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 1,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "brand",
- "fieldtype": "Data",
- "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": "Brand Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "brand",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_in_quick_entry": 1,
+ "fieldname": "brand",
+ "fieldtype": "Data",
+ "label": "Brand Name",
+ "oldfieldname": "brand",
+ "oldfieldtype": "Data",
+ "reqd": 1,
"unique": 1
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "fieldtype": "Text",
- "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": "Description",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "description",
- "oldfieldtype": "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,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "description",
+ "fieldtype": "Text",
+ "in_list_view": 1,
+ "label": "Description",
+ "oldfieldname": "description",
+ "oldfieldtype": "Text",
"width": "300px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "defaults",
- "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": "Defaults",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "defaults",
+ "fieldtype": "Section Break",
+ "label": "Defaults"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "brand_defaults",
- "fieldtype": "Table",
- "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": "Brand Defaults",
- "length": 0,
- "no_copy": 0,
- "options": "Item Default",
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldname": "brand_defaults",
+ "fieldtype": "Table",
+ "label": "Brand Defaults",
+ "options": "Item Default"
+ },
+ {
+ "fieldname": "image",
+ "fieldtype": "Attach Image",
+ "hidden": 1,
+ "label": "Image"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-certificate",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-10-23 23:18:06.067612",
- "modified_by": "Administrator",
- "module": "Setup",
- "name": "Brand",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-certificate",
+ "idx": 1,
+ "image_field": "image",
+ "links": [],
+ "modified": "2021-03-01 15:57:30.005783",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Brand",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 1,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Item Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Item Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Stock User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock User"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales User"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Purchase User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Purchase User"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User"
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 1,
- "sort_order": "ASC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
-}
+ ],
+ "quick_entry": 1,
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "ASC"
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/brand/brand.py b/erpnext/setup/doctype/brand/brand.py
index a8d1cf8ff2d..4cfb018c865 100644
--- a/erpnext/setup/doctype/brand/brand.py
+++ b/erpnext/setup/doctype/brand/brand.py
@@ -2,11 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import copy
+import frappe
from frappe.model.document import Document
+
class Brand(Document):
pass
diff --git a/erpnext/setup/doctype/brand/test_brand.py b/erpnext/setup/doctype/brand/test_brand.py
index 25ed86ef1dd..16873c9fc92 100644
--- a/erpnext/setup/doctype/brand/test_brand.py
+++ b/erpnext/setup/doctype/brand/test_brand.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Brand')
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 45d5ce0c1c7..f9f70264f6d 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -2,23 +2,24 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, os, json
-from frappe import _
-from frappe.utils import get_timestamp
-from frappe.utils import cint, today, formatdate
-import frappe.defaults
-from frappe.cache_manager import clear_defaults_cache
-
-from frappe.model.document import Document
-from frappe.contacts.address_and_contact import load_address_and_contact
-from frappe.utils.nestedset import NestedSet
-
-from past.builtins import cmp
import functools
+import json
+import os
+
+import frappe
+import frappe.defaults
+from frappe import _
+from frappe.cache_manager import clear_defaults_cache
+from frappe.contacts.address_and_contact import load_address_and_contact
+from frappe.utils import cint, formatdate, get_timestamp, today
+from frappe.utils.nestedset import NestedSet
+from past.builtins import cmp
+
from erpnext.accounts.doctype.account.account import get_account_currency
from erpnext.setup.setup_wizard.operations.taxes_setup import setup_taxes_and_charges
+
class Company(NestedSet):
nsm_parent_field = 'parent_company'
@@ -479,8 +480,9 @@ def update_company_current_month_sales(company):
def update_company_monthly_sales(company):
'''Cache past year monthly sales of every company based on sales invoices'''
- from frappe.utils.goal import get_monthly_results
import json
+
+ from frappe.utils.goal import get_monthly_results
filter_str = "company = {0} and status != 'Draft' and docstatus=1".format(frappe.db.escape(company))
month_to_value_dict = get_monthly_results("Sales Invoice", "base_grand_total",
"posting_date", filter_str, "sum")
diff --git a/erpnext/setup/doctype/company/company_dashboard.py b/erpnext/setup/doctype/company/company_dashboard.py
index 2d760284e5a..3afea098a0f 100644
--- a/erpnext/setup/doctype/company/company_dashboard.py
+++ b/erpnext/setup/doctype/company/company_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'graph': True,
diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py
index 1b7fd4fd5c8..abc4689a20e 100644
--- a/erpnext/setup/doctype/company/test_company.py
+++ b/erpnext/setup/doctype/company/test_company.py
@@ -2,12 +2,16 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-import unittest
import json
+import unittest
+
+import frappe
from frappe import _
from frappe.utils import random_string
-from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import get_charts_for_country
+
+from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import (
+ get_charts_for_country,
+)
test_ignore = ["Account", "Cost Center", "Payment Terms Template", "Salary Component", "Warehouse"]
test_dependencies = ["Fiscal Year"]
diff --git a/erpnext/setup/doctype/currency_exchange/currency_exchange.py b/erpnext/setup/doctype/currency_exchange/currency_exchange.py
index 6480f60f59c..0b86e293778 100644
--- a/erpnext/setup/doctype/currency_exchange/currency_exchange.py
+++ b/erpnext/setup/doctype/currency_exchange/currency_exchange.py
@@ -4,10 +4,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe import _, throw
from frappe.model.document import Document
-from frappe.utils import get_datetime_str, formatdate, nowdate, cint
+from frappe.utils import cint, formatdate, get_datetime_str, nowdate
+
class CurrencyExchange(Document):
def autoname(self):
diff --git a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.js b/erpnext/setup/doctype/currency_exchange/test_currency_exchange.js
deleted file mode 100644
index 19fde2e1481..00000000000
--- a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Currency Exchange", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Currency Exchange
- () => frappe.tests.make('Currency Exchange', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py b/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
index 4ff2dd7e0e9..1e159c96c59 100644
--- a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
+++ b/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
@@ -1,10 +1,13 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, unittest
-from frappe.utils import flt
+
+import unittest
+
+import frappe
+from frappe.utils import cint, flt
+
from erpnext.setup.utils import get_exchange_rate
-from frappe.utils import cint
test_records = frappe.get_test_records('Currency Exchange')
diff --git a/erpnext/setup/doctype/customer_group/customer_group.py b/erpnext/setup/doctype/customer_group/customer_group.py
index c06669b16b4..6e72810c561 100644
--- a/erpnext/setup/doctype/customer_group/customer_group.py
+++ b/erpnext/setup/doctype/customer_group/customer_group.py
@@ -2,11 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-
-
from frappe.utils.nestedset import NestedSet, get_root_of
+
+
class CustomerGroup(NestedSet):
nsm_parent_field = 'parent_customer_group'
def validate(self):
diff --git a/erpnext/setup/doctype/customer_group/test_customer_group.py b/erpnext/setup/doctype/customer_group/test_customer_group.py
index ec90b376cdc..e04b79b8f39 100644
--- a/erpnext/setup/doctype/customer_group/test_customer_group.py
+++ b/erpnext/setup/doctype/customer_group/test_customer_group.py
@@ -7,4 +7,5 @@ test_ignore = ["Price List"]
import frappe
+
test_records = frappe.get_test_records('Customer Group')
diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index 6fbd4cd78cf..4e9a8ccad87 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -2,19 +2,34 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe import _
-from frappe.utils import (fmt_money, formatdate, format_time, now_datetime,
- get_url_to_form, get_url_to_list, flt, get_link_to_report, add_to_date, today)
+
from datetime import timedelta
-from dateutil.relativedelta import relativedelta
-from frappe.core.doctype.user.user import STANDARD_USERS
+
+import frappe
import frappe.desk.notifications
+from dateutil.relativedelta import relativedelta
+from frappe import _
+from frappe.core.doctype.user.user import STANDARD_USERS
+from frappe.utils import (
+ add_to_date,
+ flt,
+ fmt_money,
+ format_time,
+ formatdate,
+ get_link_to_report,
+ get_url_to_form,
+ get_url_to_list,
+ now_datetime,
+ today,
+)
+
from erpnext.accounts.utils import get_balance_on, get_count_on, get_fiscal_year
user_specific_content = ["calendar_events", "todo_list"]
from frappe.model.document import Document
+
+
class EmailDigest(Document):
def __init__(self, *args, **kwargs):
super(EmailDigest, self).__init__(*args, **kwargs)
@@ -60,9 +75,6 @@ class EmailDigest(Document):
reference_name = self.name,
unsubscribe_message = _("Unsubscribe from this Email Digest"))
- frappe.set_user(original_user)
- frappe.set_user_lang(original_user)
-
def get_msg_html(self):
"""Build email digest content"""
frappe.flags.ignore_account_permission = True
diff --git a/erpnext/setup/doctype/email_digest/quotes.py b/erpnext/setup/doctype/email_digest/quotes.py
index 5451ee1daff..c77fe824ac9 100644
--- a/erpnext/setup/doctype/email_digest/quotes.py
+++ b/erpnext/setup/doctype/email_digest/quotes.py
@@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
+
import random
+
def get_random_quote():
quotes = [
("Start by doing what's necessary; then do what's possible; and suddenly you are doing the impossible.", "Francis of Assisi"),
diff --git a/erpnext/setup/doctype/email_digest/test_email_digest.py b/erpnext/setup/doctype/email_digest/test_email_digest.py
index afe693afd2f..b3d0ce325b8 100644
--- a/erpnext/setup/doctype/email_digest/test_email_digest.py
+++ b/erpnext/setup/doctype/email_digest/test_email_digest.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Email Digest')
diff --git a/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py b/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py
index 968c51c345b..5c8d695b6e5 100644
--- a/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py
+++ b/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class EmailDigestRecipient(Document):
pass
diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.py b/erpnext/setup/doctype/global_defaults/global_defaults.py
index a0ba1efb5b4..66d3b9ee480 100644
--- a/erpnext/setup/doctype/global_defaults/global_defaults.py
+++ b/erpnext/setup/doctype/global_defaults/global_defaults.py
@@ -2,11 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
"""Global Defaults"""
import frappe
import frappe.defaults
-from frappe.utils import cint
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
+from frappe.utils import cint
keydict = {
# "key in defaults": "key in Global Defaults"
@@ -22,6 +23,7 @@ keydict = {
from frappe.model.document import Document
+
class GlobalDefaults(Document):
def on_update(self):
diff --git a/erpnext/setup/doctype/global_defaults/test_global_defaults.js b/erpnext/setup/doctype/global_defaults/test_global_defaults.js
deleted file mode 100644
index 33634eb0f88..00000000000
--- a/erpnext/setup/doctype/global_defaults/test_global_defaults.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Global Defaults", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Global Defaults
- () => frappe.tests.make('Global Defaults', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/global_defaults/test_global_defaults.py b/erpnext/setup/doctype/global_defaults/test_global_defaults.py
index 0495af7b414..70a7c08c111 100644
--- a/erpnext/setup/doctype/global_defaults/test_global_defaults.py
+++ b/erpnext/setup/doctype/global_defaults/test_global_defaults.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestGlobalDefaults(unittest.TestCase):
pass
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 5fcad00af16..0943b22c028 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -2,19 +2,19 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import copy
+
+import frappe
from frappe import _
-from frappe.utils import nowdate, cint, cstr
+from frappe.utils import cint
from frappe.utils.nestedset import NestedSet
-from frappe.website.website_generator import WebsiteGenerator
from frappe.website.render import clear_cache
-from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
-from erpnext.shopping_cart.product_info import set_product_info_for_website
-from erpnext.utilities.product import get_qty_in_stock
+from frappe.website.website_generator import WebsiteGenerator
from six.moves.urllib.parse import quote
-from erpnext.shopping_cart.product_query import ProductQuery
-from erpnext.shopping_cart.filters import ProductFiltersBuilder
+
+from erpnext.e_commerce.product_data_engine.filters import ProductFiltersBuilder
+
class ItemGroup(NestedSet, WebsiteGenerator):
nsm_parent_field = 'parent_item_group'
@@ -69,34 +69,15 @@ class ItemGroup(NestedSet, WebsiteGenerator):
frappe.throw(frappe._("An item exists with same name ({0}), please change the item group name or rename the item").format(self.name), frappe.NameError)
def get_context(self, context):
- context.show_search=True
- context.page_length = cint(frappe.db.get_single_value('Products Settings', 'products_per_page')) or 6
+ context.show_search = True
+ context.body_class = "product-page"
+ context.page_length = cint(frappe.db.get_single_value('E Commerce Settings', 'products_per_page')) or 6
context.search_link = '/product_search'
- if frappe.form_dict:
- search = frappe.form_dict.search
- field_filters = frappe.parse_json(frappe.form_dict.field_filters)
- attribute_filters = frappe.parse_json(frappe.form_dict.attribute_filters)
- start = frappe.parse_json(frappe.form_dict.start)
- else:
- search = None
- attribute_filters = None
- field_filters = {}
- start = 0
-
- if not field_filters:
- field_filters = {}
-
- # Ensure the query remains within current item group & sub group
- field_filters['item_group'] = [ig[0] for ig in get_child_groups(self.name)]
-
- engine = ProductQuery()
- context.items = engine.query(attribute_filters, field_filters, search, start, item_group=self.name)
-
filter_engine = ProductFiltersBuilder(self.name)
context.field_filters = filter_engine.get_field_filters()
- context.attribute_filters = filter_engine.get_attribute_fitlers()
+ context.attribute_filters = filter_engine.get_attribute_filters()
context.update({
"parents": get_parent_item_groups(self.parent_item_group),
@@ -116,106 +97,40 @@ class ItemGroup(NestedSet, WebsiteGenerator):
values[f"slide_{index + 1}_image"] = slide.image
values[f"slide_{index + 1}_title"] = slide.heading
values[f"slide_{index + 1}_subtitle"] = slide.description
- values[f"slide_{index + 1}_theme"] = slide.theme or "Light"
- values[f"slide_{index + 1}_content_align"] = slide.content_align or "Centre"
- values[f"slide_{index + 1}_primary_action_label"] = slide.label
+ values[f"slide_{index + 1}_theme"] = slide.get("theme") or "Light"
+ values[f"slide_{index + 1}_content_align"] = slide.get("content_align") or "Centre"
values[f"slide_{index + 1}_primary_action"] = slide.url
context.slideshow = values
- context.breadcrumbs = 0
+ context.no_breadcrumbs = False
context.title = self.website_title or self.name
+ context.name = self.name
+ context.item_group_name = self.item_group_name
return context
def delete_child_item_groups_key(self):
frappe.cache().hdel("child_item_groups", self.name)
-@frappe.whitelist(allow_guest=True)
-def get_product_list_for_group(product_group=None, start=0, limit=10, search=None):
- if product_group:
- item_group = frappe.get_cached_doc('Item Group', product_group)
- if item_group.is_group:
- # return child item groups if the type is of "Is Group"
- return get_child_groups_for_list_in_html(item_group, start, limit, search)
+def get_child_groups_for_website(item_group_name, immediate=False):
+ """Returns child item groups *excluding* passed group."""
+ item_group = frappe.get_cached_value("Item Group", item_group_name, ["lft", "rgt"], as_dict=1)
+ filters = {
+ "lft": [">", item_group.lft],
+ "rgt": ["<", item_group.rgt],
+ "show_in_website": 1
+ }
- child_groups = ", ".join(frappe.db.escape(i[0]) for i in get_child_groups(product_group))
+ if immediate:
+ filters["parent_item_group"] = item_group_name
- # base query
- query = """select I.name, I.item_name, I.item_code, I.route, I.image, I.website_image, I.thumbnail, I.item_group,
- I.description, I.web_long_description as website_description, I.is_stock_item,
- case when (S.actual_qty - S.reserved_qty) > 0 then 1 else 0 end as in_stock, I.website_warehouse,
- I.has_batch_no
- from `tabItem` I
- left join tabBin S on I.item_code = S.item_code and I.website_warehouse = S.warehouse
- where I.show_in_website = 1
- and I.disabled = 0
- and (I.end_of_life is null or I.end_of_life='0000-00-00' or I.end_of_life > %(today)s)
- and (I.variant_of = '' or I.variant_of is null)
- and (I.item_group in ({child_groups})
- or I.name in (select parent from `tabWebsite Item Group` where item_group in ({child_groups})))
- """.format(child_groups=child_groups)
- # search term condition
- if search:
- query += """ and (I.web_long_description like %(search)s
- or I.item_name like %(search)s
- or I.name like %(search)s)"""
- search = "%" + cstr(search) + "%"
-
- query += """order by I.weightage desc, in_stock desc, I.modified desc limit %s, %s""" % (cint(start), cint(limit))
-
- data = frappe.db.sql(query, {"product_group": product_group,"search": search, "today": nowdate()}, as_dict=1)
- data = adjust_qty_for_expired_items(data)
-
- if cint(frappe.db.get_single_value("Shopping Cart Settings", "enabled")):
- for item in data:
- set_product_info_for_website(item)
-
- return data
-
-def get_child_groups_for_list_in_html(item_group, start, limit, search):
- search_filters = None
- if search_filters:
- search_filters = [
- dict(name = ('like', '%{}%'.format(search))),
- dict(description = ('like', '%{}%'.format(search)))
- ]
- data = frappe.db.get_all('Item Group',
- fields = ['name', 'route', 'description', 'image'],
- filters = dict(
- show_in_website = 1,
- parent_item_group = item_group.name,
- lft = ('>', item_group.lft),
- rgt = ('<', item_group.rgt),
- ),
- or_filters = search_filters,
- order_by = 'weightage desc, name asc',
- start = start,
- limit = limit
+ return frappe.get_all(
+ "Item Group",
+ filters=filters,
+ fields=["name", "route"]
)
- return data
-
-def adjust_qty_for_expired_items(data):
- adjusted_data = []
-
- for item in data:
- if item.get('has_batch_no') and item.get('website_warehouse'):
- stock_qty_dict = get_qty_in_stock(
- item.get('name'), 'website_warehouse', item.get('website_warehouse'))
- qty = stock_qty_dict.stock_qty[0][0] if stock_qty_dict.stock_qty else 0
- item['in_stock'] = 1 if qty else 0
- adjusted_data.append(item)
-
- return adjusted_data
-
-
-def get_child_groups(item_group_name):
- item_group = frappe.get_doc("Item Group", item_group_name)
- return frappe.db.sql("""select name
- from `tabItem Group` where lft>=%(lft)s and rgt<=%(rgt)s
- and show_in_website = 1""", {"lft": item_group.lft, "rgt": item_group.rgt})
-
def get_child_item_groups(item_group_name):
item_group = frappe.get_cached_value("Item Group",
item_group_name, ["lft", "rgt"], as_dict=1)
@@ -231,31 +146,33 @@ def get_item_for_list_in_html(context):
if (context.get("website_image") or "").startswith("files/"):
context["website_image"] = "/" + quote(context["website_image"])
- context["show_availability_status"] = cint(frappe.db.get_single_value('Products Settings',
+ context["show_availability_status"] = cint(frappe.db.get_single_value('E Commerce Settings',
'show_availability_status'))
products_template = 'templates/includes/products_as_list.html'
return frappe.get_template(products_template).render(context)
-def get_group_item_count(item_group):
- child_groups = ", ".join('"' + i[0] + '"' for i in get_child_groups(item_group))
- return frappe.db.sql("""select count(*) from `tabItem`
- where docstatus = 0 and show_in_website = 1
- and (item_group in (%s)
- or name in (select parent from `tabWebsite Item Group`
- where item_group in (%s))) """ % (child_groups, child_groups))[0][0]
+def get_parent_item_groups(item_group_name, from_item=False):
+ base_nav_page = {"name": _("Shop by Category"), "route":"/shop-by-category"}
+
+ if from_item and frappe.request.environ.get("HTTP_REFERER"):
+ # base page after 'Home' will vary on Item page
+ last_page = frappe.request.environ["HTTP_REFERER"].split('/')[-1]
+ if last_page and last_page in ("shop-by-category", "all-products"):
+ base_nav_page_title = " ".join(last_page.split("-")).title()
+ base_nav_page = {"name": _(base_nav_page_title), "route":"/"+last_page}
-def get_parent_item_groups(item_group_name):
base_parents = [
- {"name": frappe._("Home"), "route":"/"},
- {"name": frappe._("All Products"), "route":"/all-products"},
+ {"name": _("Home"), "route":"/"},
+ base_nav_page,
]
+
if not item_group_name:
return base_parents
- item_group = frappe.get_doc("Item Group", item_group_name)
+ item_group = frappe.db.get_value("Item Group", item_group_name, ["lft", "rgt"], as_dict=1)
parent_groups = frappe.db.sql("""select name, route from `tabItem Group`
where lft <= %s and rgt >= %s
and show_in_website=1
diff --git a/erpnext/setup/doctype/item_group/test_item_group.js b/erpnext/setup/doctype/item_group/test_item_group.js
deleted file mode 100644
index ea322e23d65..00000000000
--- a/erpnext/setup/doctype/item_group/test_item_group.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Item Group", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Item Group
- () => frappe.tests.make('Item Group', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/item_group/test_item_group.py b/erpnext/setup/doctype/item_group/test_item_group.py
index 745b13a5bed..a816f391c62 100644
--- a/erpnext/setup/doctype/item_group/test_item_group.py
+++ b/erpnext/setup/doctype/item_group/test_item_group.py
@@ -2,10 +2,18 @@
# License: GNU General Public License v3. See license.txt
from __future__ import print_function, unicode_literals
+
import unittest
+
import frappe
-from frappe.utils.nestedset import NestedSetRecursionError, NestedSetMultipleRootsError, \
- NestedSetChildExistsError, NestedSetInvalidMergeError, rebuild_tree, get_ancestors_of
+from frappe.utils.nestedset import (
+ NestedSetChildExistsError,
+ NestedSetInvalidMergeError,
+ NestedSetMultipleRootsError,
+ NestedSetRecursionError,
+ get_ancestors_of,
+ rebuild_tree,
+)
test_records = frappe.get_test_records('Item Group')
diff --git a/erpnext/setup/doctype/naming_series/naming_series.py b/erpnext/setup/doctype/naming_series/naming_series.py
index c1f9433b411..005cfec769a 100644
--- a/erpnext/setup/doctype/naming_series/naming_series.py
+++ b/erpnext/setup/doctype/naming_series/naming_series.py
@@ -2,15 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-
-from frappe.utils import cstr, cint
-from frappe import msgprint, throw, _
-
+from frappe import _, msgprint, throw
+from frappe.core.doctype.doctype.doctype import validate_series
from frappe.model.document import Document
from frappe.model.naming import parse_naming_series
from frappe.permissions import get_doctypes_with_read
-from frappe.core.doctype.doctype.doctype import validate_series
+from frappe.utils import cint, cstr
+
class NamingSeriesNotSetError(frappe.ValidationError): pass
@@ -79,7 +79,8 @@ class NamingSeries(Document):
options = self.scrub_options_list(ol)
# validate names
- for i in options: self.validate_series_name(i)
+ for i in options:
+ self.validate_series_name(i)
if options and self.user_must_always_select:
options = [''] + options
@@ -138,7 +139,7 @@ class NamingSeries(Document):
def validate_series_name(self, n):
import re
- if not re.match("^[\w\- /.#{}]*$", n, re.UNICODE):
+ if not re.match(r"^[\w\- \/.#{}]+$", n, re.UNICODE):
throw(_('Special Characters except "-", "#", ".", "/", "{" and "}" not allowed in naming series'))
@frappe.whitelist()
diff --git a/erpnext/setup/doctype/naming_series/test_naming_series.js b/erpnext/setup/doctype/naming_series/test_naming_series.js
deleted file mode 100644
index 22b664b2e6d..00000000000
--- a/erpnext/setup/doctype/naming_series/test_naming_series.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* 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()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/party_type/party_type.py b/erpnext/setup/doctype/party_type/party_type.py
index 96e60936a4b..8424c7fe938 100644
--- a/erpnext/setup/doctype/party_type/party_type.py
+++ b/erpnext/setup/doctype/party_type/party_type.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class PartyType(Document):
pass
diff --git a/erpnext/setup/doctype/party_type/test_party_type.js b/erpnext/setup/doctype/party_type/test_party_type.js
deleted file mode 100644
index c97dbc58c80..00000000000
--- a/erpnext/setup/doctype/party_type/test_party_type.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Party Type", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Party Type
- () => frappe.tests.make('Party Type', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/party_type/test_party_type.py b/erpnext/setup/doctype/party_type/test_party_type.py
index 079fe2fe3b7..e5f2908eb46 100644
--- a/erpnext/setup/doctype/party_type/test_party_type.py
+++ b/erpnext/setup/doctype/party_type/test_party_type.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Party Type')
diff --git a/erpnext/setup/doctype/print_heading/print_heading.py b/erpnext/setup/doctype/print_heading/print_heading.py
index 3d5cd2d6f9e..cf25638608b 100644
--- a/erpnext/setup/doctype/print_heading/print_heading.py
+++ b/erpnext/setup/doctype/print_heading/print_heading.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class PrintHeading(Document):
pass
diff --git a/erpnext/setup/doctype/print_heading/test_print_heading.py b/erpnext/setup/doctype/print_heading/test_print_heading.py
index b2be2e375e4..06f801a654e 100644
--- a/erpnext/setup/doctype/print_heading/test_print_heading.py
+++ b/erpnext/setup/doctype/print_heading/test_print_heading.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Print Heading')
diff --git a/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py b/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py
index 42c5a5a54fb..9131cc334a7 100644
--- a/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py
+++ b/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class QuotationLostReason(Document):
pass
diff --git a/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py b/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py
index f6b30b649b5..ab8d61f1ebe 100644
--- a/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py
+++ b/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Quotation Lost Reason')
diff --git a/erpnext/setup/doctype/quotation_lost_reason_detail/quotation_lost_reason_detail.py b/erpnext/setup/doctype/quotation_lost_reason_detail/quotation_lost_reason_detail.py
index 7bb8d02670e..434f24ea925 100644
--- a/erpnext/setup/doctype/quotation_lost_reason_detail/quotation_lost_reason_detail.py
+++ b/erpnext/setup/doctype/quotation_lost_reason_detail/quotation_lost_reason_detail.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QuotationLostReasonDetail(Document):
pass
diff --git a/erpnext/setup/doctype/sales_partner/sales_partner.py b/erpnext/setup/doctype/sales_partner/sales_partner.py
index 675f9ca560b..6c741a8fb44 100644
--- a/erpnext/setup/doctype/sales_partner/sales_partner.py
+++ b/erpnext/setup/doctype/sales_partner/sales_partner.py
@@ -2,10 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+from frappe.contacts.address_and_contact import load_address_and_contact
from frappe.utils import cstr, filter_strip_join
from frappe.website.website_generator import WebsiteGenerator
-from frappe.contacts.address_and_contact import load_address_and_contact
+
class SalesPartner(WebsiteGenerator):
website = frappe._dict(
diff --git a/erpnext/setup/doctype/sales_partner/test_sales_partner.py b/erpnext/setup/doctype/sales_partner/test_sales_partner.py
index 4548a4e19b5..6ece2390405 100644
--- a/erpnext/setup/doctype/sales_partner/test_sales_partner.py
+++ b/erpnext/setup/doctype/sales_partner/test_sales_partner.py
@@ -2,8 +2,8 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Sales Partner')
test_ignore = ["Item Group"]
diff --git a/erpnext/setup/doctype/sales_person/sales_person.py b/erpnext/setup/doctype/sales_person/sales_person.py
index 19c2e5b9543..c7cad6bb998 100644
--- a/erpnext/setup/doctype/sales_person/sales_person.py
+++ b/erpnext/setup/doctype/sales_person/sales_person.py
@@ -2,12 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt
from frappe.utils.nestedset import NestedSet, get_root_of
+
from erpnext import get_default_currency
+
class SalesPerson(NestedSet):
nsm_parent_field = 'parent_sales_person'
diff --git a/erpnext/setup/doctype/sales_person/sales_person_dashboard.py b/erpnext/setup/doctype/sales_person/sales_person_dashboard.py
index 662008ec8db..61c1ba46d35 100644
--- a/erpnext/setup/doctype/sales_person/sales_person_dashboard.py
+++ b/erpnext/setup/doctype/sales_person/sales_person_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'heatmap': True,
diff --git a/erpnext/setup/doctype/sales_person/test_sales_person.py b/erpnext/setup/doctype/sales_person/test_sales_person.py
index 8313cb45084..497aaad74f8 100644
--- a/erpnext/setup/doctype/sales_person/test_sales_person.py
+++ b/erpnext/setup/doctype/sales_person/test_sales_person.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
test_dependencies = ["Employee"]
import frappe
+
test_records = frappe.get_test_records('Sales Person')
test_ignore = ["Item Group"]
diff --git a/erpnext/setup/doctype/supplier_group/supplier_group.py b/erpnext/setup/doctype/supplier_group/supplier_group.py
index 9d84f9097b5..0ca35257926 100644
--- a/erpnext/setup/doctype/supplier_group/supplier_group.py
+++ b/erpnext/setup/doctype/supplier_group/supplier_group.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.utils.nestedset import NestedSet, get_root_of
+
class SupplierGroup(NestedSet):
nsm_parent_field = 'parent_supplier_group'
diff --git a/erpnext/setup/doctype/supplier_group/test_supplier_group.js b/erpnext/setup/doctype/supplier_group/test_supplier_group.js
deleted file mode 100644
index 976dd2cc4f3..00000000000
--- a/erpnext/setup/doctype/supplier_group/test_supplier_group.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Supplier Group", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Supplier Group
- () => frappe.tests.make('Supplier Group', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/supplier_group/test_supplier_group.py b/erpnext/setup/doctype/supplier_group/test_supplier_group.py
index 0e3d23d6bd3..b3a636635ec 100644
--- a/erpnext/setup/doctype/supplier_group/test_supplier_group.py
+++ b/erpnext/setup/doctype/supplier_group/test_supplier_group.py
@@ -4,4 +4,5 @@
from __future__ import unicode_literals
import frappe
+
test_records = frappe.get_test_records('Supplier Group')
diff --git a/erpnext/setup/doctype/target_detail/target_detail.py b/erpnext/setup/doctype/target_detail/target_detail.py
index 633be45d20b..89cd814f2d1 100644
--- a/erpnext/setup/doctype/target_detail/target_detail.py
+++ b/erpnext/setup/doctype/target_detail/target_detail.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class TargetDetail(Document):
pass
diff --git a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py
index 5b00ccbdbb3..8c9059f61ef 100644
--- a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py
+++ b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py
@@ -2,15 +2,17 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
+import json
+
import frappe
from frappe import _, throw
-import json
from frappe.model.document import Document
-from frappe.utils.jinja import validate_template
from frappe.utils import cint
-
+from frappe.utils.jinja import validate_template
from six import string_types
+
class TermsandConditions(Document):
def validate(self):
if self.terms:
diff --git a/erpnext/setup/doctype/terms_and_conditions/test_terms_and_conditions.py b/erpnext/setup/doctype/terms_and_conditions/test_terms_and_conditions.py
index 6fea78f46ae..abfa9214d64 100644
--- a/erpnext/setup/doctype/terms_and_conditions/test_terms_and_conditions.py
+++ b/erpnext/setup/doctype/terms_and_conditions/test_terms_and_conditions.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Terms and Conditions')
diff --git a/erpnext/setup/doctype/territory/territory.py b/erpnext/setup/doctype/territory/territory.py
index 7eefe77495c..f61796b9bdf 100644
--- a/erpnext/setup/doctype/territory/territory.py
+++ b/erpnext/setup/doctype/territory/territory.py
@@ -2,12 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import flt
-from frappe import _
+import frappe
+from frappe import _
+from frappe.utils import flt
from frappe.utils.nestedset import NestedSet, get_root_of
+
class Territory(NestedSet):
nsm_parent_field = 'parent_territory'
diff --git a/erpnext/setup/doctype/territory/test_territory.py b/erpnext/setup/doctype/territory/test_territory.py
index efe00c5a30b..a3aa866fff3 100644
--- a/erpnext/setup/doctype/territory/test_territory.py
+++ b/erpnext/setup/doctype/territory/test_territory.py
@@ -2,8 +2,8 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Territory')
test_ignore = ["Item Group"]
diff --git a/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
index 933a8c3bed8..aa0f79b4c86 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
+++ b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
@@ -3,9 +3,11 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
+
class TestTransactionDeletionRecord(unittest.TestCase):
def setUp(self):
create_company('Dunder Mifflin Paper Co')
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
index 8a491554801..efb038faccc 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
@@ -3,11 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe.utils import cint
+
import frappe
-from frappe.model.document import Document
from frappe import _
from frappe.desk.notifications import clear_notifications
+from frappe.model.document import Document
+from frappe.utils import cint
+
class TransactionDeletionRecord(Document):
def validate(self):
diff --git a/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
index 2176cb10deb..a113d504538 100644
--- a/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
+++ b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class TransactionDeletionRecordItem(Document):
pass
diff --git a/erpnext/setup/doctype/uom/test_uom.py b/erpnext/setup/doctype/uom/test_uom.py
index 330d30358d9..e222c134942 100644
--- a/erpnext/setup/doctype/uom/test_uom.py
+++ b/erpnext/setup/doctype/uom/test_uom.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('UOM')
diff --git a/erpnext/setup/doctype/uom/uom.py b/erpnext/setup/doctype/uom/uom.py
index 404b84b1134..f0e97b34e25 100644
--- a/erpnext/setup/doctype/uom/uom.py
+++ b/erpnext/setup/doctype/uom/uom.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class UOM(Document):
pass
diff --git a/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.js b/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.js
deleted file mode 100644
index afcf74ccb47..00000000000
--- a/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: UOM Conversion Factor", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new UOM Conversion Factor
- () => frappe.tests.make('UOM Conversion Factor', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.py b/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.py
index 04596efbca6..33795d6b5b2 100644
--- a/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.py
+++ b/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestUOMConversionFactor(unittest.TestCase):
pass
diff --git a/erpnext/setup/doctype/uom_conversion_factor/uom_conversion_factor.py b/erpnext/setup/doctype/uom_conversion_factor/uom_conversion_factor.py
index 3566c537c6c..45342e9fee9 100644
--- a/erpnext/setup/doctype/uom_conversion_factor/uom_conversion_factor.py
+++ b/erpnext/setup/doctype/uom_conversion_factor/uom_conversion_factor.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class UOMConversionFactor(Document):
pass
diff --git a/erpnext/setup/doctype/website_item_group/website_item_group.py b/erpnext/setup/doctype/website_item_group/website_item_group.py
index e416b509b98..2f720134484 100644
--- a/erpnext/setup/doctype/website_item_group/website_item_group.py
+++ b/erpnext/setup/doctype/website_item_group/website_item_group.py
@@ -4,9 +4,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class WebsiteItemGroup(Document):
pass
diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py
index bbee74cafb4..cdc83c14620 100644
--- a/erpnext/setup/install.py
+++ b/erpnext/setup/install.py
@@ -4,16 +4,18 @@
from __future__ import print_function, unicode_literals
import frappe
-from erpnext.accounts.doctype.cash_flow_mapper.default_cash_flow_mapper import DEFAULT_MAPPERS
-from .default_success_action import get_default_success_action
from frappe import _
-from frappe.utils import cint
-from frappe.installer import update_site_config
-from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
-from erpnext.setup.default_energy_point_rules import get_default_energy_point_rules
+from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
+from frappe.installer import update_site_config
+from frappe.utils import cint
from six import iteritems
+from erpnext.accounts.doctype.cash_flow_mapper.default_cash_flow_mapper import DEFAULT_MAPPERS
+from erpnext.setup.default_energy_point_rules import get_default_energy_point_rules
+
+from .default_success_action import get_default_success_action
+
default_mail_footer = """
"""
diff --git a/erpnext/setup/onboarding_slide/welcome_back_to_erpnext!/welcome_back_to_erpnext!.json b/erpnext/setup/onboarding_slide/welcome_back_to_erpnext!/welcome_back_to_erpnext!.json
deleted file mode 100644
index f00dc947d2c..00000000000
--- a/erpnext/setup/onboarding_slide/welcome_back_to_erpnext!/welcome_back_to_erpnext!.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "add_more_button": 0,
- "app": "ERPNext",
- "creation": "2019-12-04 19:21:39.995776",
- "docstatus": 0,
- "doctype": "Onboarding Slide",
- "domains": [],
- "help_links": [],
- "idx": 0,
- "image_src": "",
- "is_completed": 0,
- "max_count": 3,
- "modified": "2019-12-09 17:53:53.849953",
- "modified_by": "Administrator",
- "name": "Welcome back to ERPNext!",
- "owner": "Administrator",
- "slide_desc": "
Let's continue where you left from!
",
- "slide_fields": [],
- "slide_module": "Setup",
- "slide_order": 0,
- "slide_title": "Welcome back to ERPNext!",
- "slide_type": "Continue"
-}
\ No newline at end of file
diff --git a/erpnext/setup/onboarding_slide/welcome_to_erpnext!/welcome_to_erpnext!.json b/erpnext/setup/onboarding_slide/welcome_to_erpnext!/welcome_to_erpnext!.json
deleted file mode 100644
index 37eb67b1d7e..00000000000
--- a/erpnext/setup/onboarding_slide/welcome_to_erpnext!/welcome_to_erpnext!.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "add_more_button": 0,
- "app": "ERPNext",
- "creation": "2019-11-26 17:01:26.671859",
- "docstatus": 0,
- "doctype": "Onboarding Slide",
- "domains": [],
- "help_links": [],
- "idx": 0,
- "image_src": "",
- "is_completed": 0,
- "max_count": 0,
- "modified": "2019-12-22 21:26:28.414597",
- "modified_by": "Administrator",
- "name": "Welcome to ERPNext!",
- "owner": "Administrator",
- "slide_desc": "
Setting up an ERP can be overwhelming. But don't worry, we have got your back! This wizard will help you onboard to ERPNext in a short time!
",
- "slide_fields": [],
- "slide_module": "Setup",
- "slide_order": 1,
- "slide_title": "Welcome to ERPNext!",
- "slide_type": "Information"
-}
\ No newline at end of file
diff --git a/erpnext/setup/setup_wizard/data/dashboard_charts.py b/erpnext/setup/setup_wizard/data/dashboard_charts.py
index 9ce64eb9d92..5369bbab356 100644
--- a/erpnext/setup/setup_wizard/data/dashboard_charts.py
+++ b/erpnext/setup/setup_wizard/data/dashboard_charts.py
@@ -1,8 +1,10 @@
from __future__ import unicode_literals
-from frappe import _
-import frappe
+
import json
+import frappe
+
+
def get_company_for_dashboards():
company = frappe.defaults.get_defaults().company
if company:
diff --git a/erpnext/setup/setup_wizard/data/industry_type.py b/erpnext/setup/setup_wizard/data/industry_type.py
index 4fa9f8abb16..2c83a5c721c 100644
--- a/erpnext/setup/setup_wizard/data/industry_type.py
+++ b/erpnext/setup/setup_wizard/data/industry_type.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_industry_types():
return [
_('Accounting'),
diff --git a/erpnext/setup/setup_wizard/operations/company_setup.py b/erpnext/setup/setup_wizard/operations/company_setup.py
index 4833d93c4a7..4fb20dc8712 100644
--- a/erpnext/setup/setup_wizard/operations/company_setup.py
+++ b/erpnext/setup/setup_wizard/operations/company_setup.py
@@ -2,11 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import cstr, getdate
+
from .default_website import website_maker
-from erpnext.accounts.doctype.account.account import RootNotEditable
+
def create_fiscal_year_and_company(args):
if (args.get('fy_start_date')):
@@ -34,7 +36,7 @@ def create_fiscal_year_and_company(args):
def enable_shopping_cart(args):
# Needs price_lists
frappe.get_doc({
- "doctype": "Shopping Cart Settings",
+ "doctype": "E Commerce Settings",
"enabled": 1,
'company': args.get('company_name') ,
'price_list': frappe.db.get_value("Price List", {"selling": 1}),
diff --git a/erpnext/setup/setup_wizard/operations/default_website.py b/erpnext/setup/setup_wizard/operations/default_website.py
index 38b5c1470e7..2288ae06746 100644
--- a/erpnext/setup/setup_wizard/operations/default_website.py
+++ b/erpnext/setup/setup_wizard/operations/default_website.py
@@ -2,11 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
from frappe import _
from frappe.utils import nowdate
+
class website_maker(object):
def __init__(self, args):
self.args = args
diff --git a/erpnext/setup/setup_wizard/operations/defaults_setup.py b/erpnext/setup/setup_wizard/operations/defaults_setup.py
index 6dd0fb1403f..3f90f72b608 100644
--- a/erpnext/setup/setup_wizard/operations/defaults_setup.py
+++ b/erpnext/setup/setup_wizard/operations/defaults_setup.py
@@ -2,10 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import cstr, getdate
+
def set_default_settings(args):
# enable default currency
frappe.db.set_value("Currency", args.get("currency"), "enabled", 1)
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index cd49a180529..fc89e3ccf1f 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -3,16 +3,20 @@
from __future__ import unicode_literals
-import frappe, os, json
+import json
+import os
+import frappe
from frappe import _
+from frappe.desk.doctype.global_search_settings.global_search_settings import (
+ update_global_search_doctypes,
+)
from frappe.desk.page.setup_wizard.setup_wizard import make_records
from frappe.utils import cstr, getdate
-from frappe.desk.doctype.global_search_settings.global_search_settings import update_global_search_doctypes
+from frappe.utils.nestedset import rebuild_tree
from erpnext.accounts.doctype.account.account import RootNotEditable
from erpnext.regional.address_template.setup import set_up_address_templates
-from frappe.utils.nestedset import rebuild_tree
default_lead_sources = ["Existing Customer", "Reference", "Advertisement",
"Cold Calling", "Exhibition", "Supplier Reference", "Mass Mailing",
@@ -512,7 +516,7 @@ def create_bank_account(args):
pass
def update_shopping_cart_settings(args):
- shopping_cart = frappe.get_doc("Shopping Cart Settings")
+ shopping_cart = frappe.get_doc("E Commerce Settings")
shopping_cart.update({
"enabled": 1,
'company': args.company_name,
diff --git a/erpnext/setup/setup_wizard/operations/sample_data.py b/erpnext/setup/setup_wizard/operations/sample_data.py
index c6d9f0851b1..3aef40d3ebb 100644
--- a/erpnext/setup/setup_wizard/operations/sample_data.py
+++ b/erpnext/setup/setup_wizard/operations/sample_data.py
@@ -3,11 +3,15 @@
from __future__ import unicode_literals
+import json
+import os
+import random
+
import frappe
-from frappe.utils.make_random import add_random_children
import frappe.utils
-import random, os, json
from frappe import _
+from frappe.utils.make_random import add_random_children
+
def make_sample_data(domains, make_dependent = False):
"""Create a few opportunities, quotes, material requests, issues, todos, projects
diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py
index 09b91709642..90384a7da0b 100644
--- a/erpnext/setup/setup_wizard/operations/taxes_setup.py
+++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py
@@ -3,8 +3,8 @@
from __future__ import unicode_literals
-import os
import json
+import os
import frappe
from frappe import _
diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py
index f63d2695aa3..ecb07d53b7c 100644
--- a/erpnext/setup/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/setup_wizard/setup_wizard.py
@@ -6,7 +6,10 @@ from __future__ import unicode_literals
import frappe
from frappe import _
-from .operations import install_fixtures as fixtures, company_setup, sample_data
+from .operations import company_setup
+from .operations import install_fixtures as fixtures
+from .operations import sample_data
+
def get_setup_stages(args=None):
if frappe.db.sql("select name from tabCompany"):
@@ -106,7 +109,7 @@ def fin(args):
def make_sample_data(domains):
try:
sample_data.make_sample_data(domains)
- except:
+ except Exception:
# clear message
if frappe.message_log:
frappe.message_log.pop()
diff --git a/erpnext/setup/setup_wizard/utils.py b/erpnext/setup/setup_wizard/utils.py
index 4223f000a6b..30b88aecbcd 100644
--- a/erpnext/setup/setup_wizard/utils.py
+++ b/erpnext/setup/setup_wizard/utils.py
@@ -1,8 +1,10 @@
from __future__ import unicode_literals
-import json, os
+
+import json
+import os
from frappe.desk.page.setup_wizard.setup_wizard import setup_complete
-from erpnext.setup.setup_wizard import setup_wizard
+
def complete():
with open(os.path.join(os.path.dirname(__file__),
diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py
index 27237bf2cbe..c7746a64eb4 100644
--- a/erpnext/setup/utils.py
+++ b/erpnext/setup/utils.py
@@ -2,12 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt, add_days
-from frappe.utils import get_datetime_str, nowdate
+from frappe.utils import add_days, flt, get_datetime_str, nowdate
+
from erpnext import get_default_company
+
def get_root_of(doctype):
"""Get root element of a DocType with a tree structure"""
result = frappe.db.sql_list("""select name from `tab%s`
@@ -109,7 +111,7 @@ def get_exchange_rate(from_currency, to_currency, transaction_date=None, args=No
value = response.json()["result"]
cache.setex(name=key, time=21600, value=flt(value))
return flt(value)
- except:
+ except Exception:
frappe.log_error(title="Get Exchange Rate")
frappe.msgprint(_("Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually").format(from_currency, to_currency, transaction_date))
return 0.0
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
deleted file mode 100644
index 7a4bb20136f..00000000000
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
+++ /dev/null
@@ -1,212 +0,0 @@
-{
- "actions": [],
- "creation": "2013-06-19 15:57:32",
- "description": "Default settings for Shopping Cart",
- "doctype": "DocType",
- "document_type": "System",
- "engine": "InnoDB",
- "field_order": [
- "enabled",
- "store_page_docs",
- "display_settings",
- "show_attachments",
- "show_price",
- "show_stock_availability",
- "enable_variants",
- "column_break_7",
- "show_contact_us_button",
- "show_quantity_in_website",
- "show_apply_coupon_code_in_website",
- "allow_items_not_in_stock",
- "section_break_2",
- "company",
- "price_list",
- "column_break_4",
- "default_customer_group",
- "quotation_series",
- "section_break_8",
- "enable_checkout",
- "save_quotations_as_draft",
- "column_break_11",
- "payment_gateway_account",
- "payment_success_url"
- ],
- "fields": [
- {
- "default": "0",
- "fieldname": "enabled",
- "fieldtype": "Check",
- "in_list_view": 1,
- "label": "Enable Shopping Cart"
- },
- {
- "fieldname": "display_settings",
- "fieldtype": "Section Break",
- "label": "Display Settings"
- },
- {
- "default": "0",
- "fieldname": "show_attachments",
- "fieldtype": "Check",
- "label": "Show Public Attachments"
- },
- {
- "default": "0",
- "fieldname": "show_price",
- "fieldtype": "Check",
- "label": "Show Price"
- },
- {
- "default": "0",
- "fieldname": "show_stock_availability",
- "fieldtype": "Check",
- "label": "Show Stock Availability"
- },
- {
- "default": "0",
- "fieldname": "show_contact_us_button",
- "fieldtype": "Check",
- "label": "Show Contact Us Button"
- },
- {
- "default": "0",
- "depends_on": "show_stock_availability",
- "fieldname": "show_quantity_in_website",
- "fieldtype": "Check",
- "label": "Show Stock Quantity"
- },
- {
- "default": "0",
- "fieldname": "show_apply_coupon_code_in_website",
- "fieldtype": "Check",
- "label": "Show Apply Coupon Code"
- },
- {
- "default": "0",
- "fieldname": "allow_items_not_in_stock",
- "fieldtype": "Check",
- "label": "Allow items not in stock to be added to cart"
- },
- {
- "depends_on": "enabled",
- "fieldname": "section_break_2",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Company",
- "mandatory_depends_on": "eval: doc.enabled === 1",
- "options": "Company",
- "remember_last_selected_value": 1
- },
- {
- "description": "Prices will not be shown if Price List is not set",
- "fieldname": "price_list",
- "fieldtype": "Link",
- "label": "Price List",
- "mandatory_depends_on": "eval: doc.enabled === 1",
- "options": "Price List"
- },
- {
- "fieldname": "column_break_4",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "default_customer_group",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Default Customer Group",
- "mandatory_depends_on": "eval: doc.enabled === 1",
- "options": "Customer Group"
- },
- {
- "fieldname": "quotation_series",
- "fieldtype": "Select",
- "label": "Quotation Series",
- "mandatory_depends_on": "eval: doc.enabled === 1"
- },
- {
- "collapsible": 1,
- "collapsible_depends_on": "eval:doc.enable_checkout",
- "depends_on": "enabled",
- "fieldname": "section_break_8",
- "fieldtype": "Section Break",
- "label": "Checkout Settings"
- },
- {
- "default": "0",
- "fieldname": "enable_checkout",
- "fieldtype": "Check",
- "label": "Enable Checkout"
- },
- {
- "default": "Orders",
- "depends_on": "enable_checkout",
- "description": "After payment completion redirect user to selected page.",
- "fieldname": "payment_success_url",
- "fieldtype": "Select",
- "label": "Payment Success Url",
- "mandatory_depends_on": "enable_checkout",
- "options": "\nOrders\nInvoices\nMy Account"
- },
- {
- "fieldname": "column_break_11",
- "fieldtype": "Column Break"
- },
- {
- "depends_on": "enable_checkout",
- "fieldname": "payment_gateway_account",
- "fieldtype": "Link",
- "label": "Payment Gateway Account",
- "mandatory_depends_on": "enable_checkout",
- "options": "Payment Gateway Account"
- },
- {
- "fieldname": "column_break_7",
- "fieldtype": "Column Break"
- },
- {
- "default": "0",
- "fieldname": "enable_variants",
- "fieldtype": "Check",
- "label": "Enable Variants"
- },
- {
- "default": "0",
- "depends_on": "eval: doc.enable_checkout == 0",
- "fieldname": "save_quotations_as_draft",
- "fieldtype": "Check",
- "label": "Save Quotations as Draft"
- },
- {
- "depends_on": "doc.enabled",
- "fieldname": "store_page_docs",
- "fieldtype": "HTML"
- }
- ],
- "icon": "fa fa-shopping-cart",
- "idx": 1,
- "issingle": 1,
- "links": [],
- "modified": "2021-03-02 17:34:57.642565",
- "modified_by": "Administrator",
- "module": "Shopping Cart",
- "name": "Shopping Cart Settings",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "email": 1,
- "print": 1,
- "read": 1,
- "role": "Website Manager",
- "share": 1,
- "write": 1
- }
- ],
- "sort_field": "modified",
- "sort_order": "ASC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.js b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.js
deleted file mode 100644
index c8485e73fa3..00000000000
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Shopping Cart Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Shopping Cart Settings
- () => frappe.tests.make('Shopping Cart Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/shopping_cart/filters.py b/erpnext/shopping_cart/filters.py
deleted file mode 100644
index 7dfa09e2d62..00000000000
--- a/erpnext/shopping_cart/filters.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe import _dict
-
-class ProductFiltersBuilder:
- def __init__(self, item_group=None):
- if not item_group or item_group == "Products Settings":
- self.doc = frappe.get_doc("Products Settings")
- else:
- self.doc = frappe.get_doc("Item Group", item_group)
-
- self.item_group = item_group
-
- def get_field_filters(self):
- filter_fields = [row.fieldname for row in self.doc.filter_fields]
-
- meta = frappe.get_meta('Item')
- fields = [df for df in meta.fields if df.fieldname in filter_fields]
-
- filter_data = []
- for df in fields:
- filters, or_filters = {}, []
- if df.fieldtype == "Link":
- if self.item_group:
- or_filters.extend([
- ["item_group", "=", self.item_group],
- ["Website Item Group", "item_group", "=", self.item_group]
- ])
-
- values = frappe.get_all("Item", fields=[df.fieldname], filters=filters, or_filters=or_filters, distinct="True", pluck=df.fieldname)
- else:
- doctype = df.get_link_doctype()
-
- # apply enable/disable/show_in_website filter
- meta = frappe.get_meta(doctype)
-
- if meta.has_field('enabled'):
- filters['enabled'] = 1
- if meta.has_field('disabled'):
- filters['disabled'] = 0
- if meta.has_field('show_in_website'):
- filters['show_in_website'] = 1
-
- values = [d.name for d in frappe.get_all(doctype, filters)]
-
- # Remove None
- if None in values:
- values.remove(None)
-
- if values:
- filter_data.append([df, values])
-
- return filter_data
-
- def get_attribute_fitlers(self):
- attributes = [row.attribute for row in self.doc.filter_attributes]
- attribute_docs = [
- frappe.get_doc('Item Attribute', attribute) for attribute in attributes
- ]
-
- valid_attributes = []
-
- for attr_doc in attribute_docs:
- selected_attributes = []
- for attr in attr_doc.item_attribute_values:
- or_filters = []
- filters= [
- ["Item Variant Attribute", "attribute", "=", attr.parent],
- ["Item Variant Attribute", "attribute_value", "=", attr.attribute_value]
- ]
- if self.item_group:
- or_filters.extend([
- ["item_group", "=", self.item_group],
- ["Website Item Group", "item_group", "=", self.item_group]
- ])
-
- if frappe.db.get_all("Item", filters, or_filters=or_filters, limit=1):
- selected_attributes.append(attr)
-
- if selected_attributes:
- valid_attributes.append(
- _dict(
- item_attribute_values=selected_attributes,
- name=attr_doc.name
- )
- )
-
- return valid_attributes
diff --git a/erpnext/shopping_cart/product_query.py b/erpnext/shopping_cart/product_query.py
deleted file mode 100644
index 6c92d967d0c..00000000000
--- a/erpnext/shopping_cart/product_query.py
+++ /dev/null
@@ -1,159 +0,0 @@
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-import frappe
-from erpnext.shopping_cart.product_info import get_product_info_for_website
-
-class ProductQuery:
- """Query engine for product listing
-
- Attributes:
- cart_settings (Document): Settings for Cart
- fields (list): Fields to fetch in query
- filters (TYPE): Description
- or_filters (list): Description
- page_length (Int): Length of page for the query
- settings (Document): Products Settings DocType
- filters (list)
- or_filters (list)
- """
-
- def __init__(self):
- self.settings = frappe.get_doc("Products Settings")
- self.cart_settings = frappe.get_doc("Shopping Cart Settings")
- self.page_length = self.settings.products_per_page or 20
- self.fields = ['name', 'item_name', 'item_code', 'website_image', 'variant_of', 'has_variants',
- 'item_group', 'image', 'web_long_description', 'description', 'route', 'weightage']
- self.filters = []
- self.or_filters = [['show_in_website', '=', 1]]
- if not self.settings.get('hide_variants'):
- self.or_filters.append(['show_variant_in_website', '=', 1])
-
- def query(self, attributes=None, fields=None, search_term=None, start=0, item_group=None):
- """Summary
-
- Args:
- attributes (dict, optional): Item Attribute filters
- fields (dict, optional): Field level filters
- search_term (str, optional): Search term to lookup
- start (int, optional): Page start
-
- Returns:
- list: List of results with set fields
- """
- if fields: self.build_fields_filters(fields)
- if search_term: self.build_search_filters(search_term)
-
- result = []
- website_item_groups = []
-
- # if from item group page consider website item group table
- if item_group:
- website_item_groups = frappe.db.get_all(
- "Item",
- fields=self.fields + ["`tabWebsite Item Group`.parent as wig_parent"],
- filters=[["Website Item Group", "item_group", "=", item_group]]
- )
-
- if attributes:
- all_items = []
- for attribute, values in attributes.items():
- if not isinstance(values, list):
- values = [values]
-
- items = frappe.get_all(
- "Item",
- fields=self.fields,
- filters=[
- *self.filters,
- ["Item Variant Attribute", "attribute", "=", attribute],
- ["Item Variant Attribute", "attribute_value", "in", values],
- ],
- or_filters=self.or_filters,
- start=start,
- limit=self.page_length,
- order_by="weightage desc"
- )
-
- items_dict = {item.name: item for item in items}
-
- all_items.append(set(items_dict.keys()))
-
- result = [items_dict.get(item) for item in list(set.intersection(*all_items))]
- else:
- result = frappe.get_all(
- "Item",
- fields=self.fields,
- filters=self.filters,
- or_filters=self.or_filters,
- start=start,
- limit=self.page_length,
- order_by="weightage desc"
- )
-
- # Combine results having context of website item groups into item results
- if item_group and website_item_groups:
- items_list = {row.name for row in result}
- for row in website_item_groups:
- if row.wig_parent not in items_list:
- result.append(row)
-
- result = sorted(result, key=lambda x: x.get("weightage"), reverse=True)
-
- for item in result:
- product_info = get_product_info_for_website(item.item_code, skip_quotation_creation=True).get('product_info')
- if product_info:
- item.formatted_price = (product_info.get('price') or {}).get('formatted_price')
-
- return result
-
- def build_fields_filters(self, filters):
- """Build filters for field values
-
- Args:
- filters (dict): Filters
- """
- for field, values in filters.items():
- if not values:
- continue
-
- # handle multiselect fields in filter addition
- meta = frappe.get_meta('Item', cached=True)
- df = meta.get_field(field)
- if df.fieldtype == 'Table MultiSelect':
- child_doctype = df.options
- child_meta = frappe.get_meta(child_doctype, cached=True)
- fields = child_meta.get("fields")
- if fields:
- self.filters.append([child_doctype, fields[0].fieldname, 'IN', values])
- elif isinstance(values, list):
- # If value is a list use `IN` query
- self.filters.append([field, 'IN', values])
- else:
- # `=` will be faster than `IN` for most cases
- self.filters.append([field, '=', values])
-
- def build_search_filters(self, search_term):
- """Query search term in specified fields
-
- Args:
- search_term (str): Search candidate
- """
- # Default fields to search from
- default_fields = {'name', 'item_name', 'description', 'item_group'}
-
- # Get meta search fields
- meta = frappe.get_meta("Item")
- meta_fields = set(meta.get_search_fields())
-
- # Join the meta fields and default fields set
- search_fields = default_fields.union(meta_fields)
- try:
- if frappe.db.count('Item', cache=True) > 50000:
- search_fields.remove('description')
- except KeyError:
- pass
-
- # Build or filters for query
- search = '%{}%'.format(search_term)
- self.or_filters += [[field, 'like', search] for field in search_fields]
diff --git a/erpnext/startup/__init__.py b/erpnext/startup/__init__.py
index deef4ba4d68..3aa52979134 100644
--- a/erpnext/startup/__init__.py
+++ b/erpnext/startup/__init__.py
@@ -19,7 +19,6 @@
# default settings that can be made for a user.
from __future__ import unicode_literals
-
product_name = "ERPNext"
user_defaults = {
"Company": "company",
diff --git a/erpnext/startup/boot.py b/erpnext/startup/boot.py
index 2b80fb8dfa1..bb76f5a6f97 100644
--- a/erpnext/startup/boot.py
+++ b/erpnext/startup/boot.py
@@ -3,9 +3,11 @@
from __future__ import unicode_literals
+
import frappe
from frappe.utils import cint
+
def boot_session(bootinfo):
"""boot session - send website info if guest"""
diff --git a/erpnext/startup/filters.py b/erpnext/startup/filters.py
index 98210165dfa..c0ccf54d5f6 100644
--- a/erpnext/startup/filters.py
+++ b/erpnext/startup/filters.py
@@ -1,5 +1,5 @@
-import frappe
+
def get_filters_config():
filters_config = {
diff --git a/erpnext/startup/leaderboard.py b/erpnext/startup/leaderboard.py
index a89435d4866..60e67f8f580 100644
--- a/erpnext/startup/leaderboard.py
+++ b/erpnext/startup/leaderboard.py
@@ -1,8 +1,10 @@
-from __future__ import unicode_literals, print_function
+from __future__ import print_function, unicode_literals
+
import frappe
from frappe.utils import cint
+
def get_leaderboards():
leaderboards = {
"Customer": {
diff --git a/erpnext/startup/notifications.py b/erpnext/startup/notifications.py
index 8e880dc42e0..01bb344d15b 100644
--- a/erpnext/startup/notifications.py
+++ b/erpnext/startup/notifications.py
@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+
def get_notification_config():
notifications = { "for_doctype":
{
diff --git a/erpnext/stock/__init__.py b/erpnext/stock/__init__.py
index 283f7d5fdaf..575aa0fa5d0 100644
--- a/erpnext/stock/__init__.py
+++ b/erpnext/stock/__init__.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
import frappe
from frappe import _
diff --git a/erpnext/stock/dashboard/item_dashboard.py b/erpnext/stock/dashboard/item_dashboard.py
index 45e662807a0..df6b632d251 100644
--- a/erpnext/stock/dashboard/item_dashboard.py
+++ b/erpnext/stock/dashboard/item_dashboard.py
@@ -2,7 +2,8 @@ from __future__ import unicode_literals
import frappe
from frappe.model.db_query import DatabaseQuery
-from frappe.utils import flt, cint
+from frappe.utils import cint, flt
+
@frappe.whitelist()
def get_data(item_code=None, warehouse=None, item_group=None,
diff --git a/erpnext/stock/dashboard/warehouse_capacity_dashboard.py b/erpnext/stock/dashboard/warehouse_capacity_dashboard.py
index 70b030e48f2..5d8b703aa5e 100644
--- a/erpnext/stock/dashboard/warehouse_capacity_dashboard.py
+++ b/erpnext/stock/dashboard/warehouse_capacity_dashboard.py
@@ -2,10 +2,11 @@ from __future__ import unicode_literals
import frappe
from frappe.model.db_query import DatabaseQuery
-from frappe.utils import nowdate
-from frappe.utils import flt
+from frappe.utils import flt, nowdate
+
from erpnext.stock.utils import get_stock_balance
+
@frappe.whitelist()
def get_data(item_code=None, warehouse=None, parent_warehouse=None,
company=None, start=0, sort_by="stock_capacity", sort_order="desc"):
diff --git a/erpnext/stock/dashboard_chart_source/warehouse_wise_stock_value/warehouse_wise_stock_value.py b/erpnext/stock/dashboard_chart_source/warehouse_wise_stock_value/warehouse_wise_stock_value.py
index 2258532c6fe..1753002a819 100644
--- a/erpnext/stock/dashboard_chart_source/warehouse_wise_stock_value/warehouse_wise_stock_value.py
+++ b/erpnext/stock/dashboard_chart_source/warehouse_wise_stock_value/warehouse_wise_stock_value.py
@@ -2,11 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, json
+
+import frappe
from frappe import _
from frappe.utils.dashboard import cache_source
+
from erpnext.stock.utils import get_stock_value_from_bin
+
@frappe.whitelist()
@cache_source
def get(chart_name = None, chart = None, no_cache = None, filters = None, from_date = None,
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index b37ae3f4f61..76db581a063 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -2,15 +2,16 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-from six import text_type
+
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.model.naming import make_autoname, revert_series_if_last
-from frappe.utils import flt, cint, get_link_to_form
-from frappe.utils.jinja import render_template
+from frappe.utils import cint, flt, get_link_to_form
from frappe.utils.data import add_days
-from six import string_types
+from frappe.utils.jinja import render_template
+from six import text_type
+
class UnableToSelectBatchError(frappe.ValidationError):
pass
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index a85a0222b55..79989307efc 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -2,15 +2,17 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.exceptions import ValidationError
import unittest
-from erpnext.stock.doctype.batch.batch import get_batch_qty, UnableToSelectBatchError, get_batch_no
+import frappe
+from frappe.exceptions import ValidationError
from frappe.utils import cint, flt
+
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
+from erpnext.stock.doctype.batch.batch import UnableToSelectBatchError, get_batch_no, get_batch_qty
from erpnext.stock.get_item_details import get_item_details
+
class TestBatch(unittest.TestCase):
def test_item_has_batch_enabled(self):
self.assertRaises(ValidationError, frappe.get_doc({
diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py
index 43642013ce6..5fbc2d8dee1 100644
--- a/erpnext/stock/doctype/bin/bin.py
+++ b/erpnext/stock/doctype/bin/bin.py
@@ -2,10 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import flt, nowdate
-import frappe.defaults
from frappe.model.document import Document
+from frappe.utils import flt, nowdate
+
class Bin(Document):
def before_save(self):
diff --git a/erpnext/stock/doctype/bin/test_bin.py b/erpnext/stock/doctype/bin/test_bin.py
index fb32ce21407..f0dbe8c0dd8 100644
--- a/erpnext/stock/doctype/bin/test_bin.py
+++ b/erpnext/stock/doctype/bin/test_bin.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Bin')
diff --git a/erpnext/stock/doctype/customs_tariff_number/customs_tariff_number.py b/erpnext/stock/doctype/customs_tariff_number/customs_tariff_number.py
index b0b3e6afbf9..d484301572b 100644
--- a/erpnext/stock/doctype/customs_tariff_number/customs_tariff_number.py
+++ b/erpnext/stock/doctype/customs_tariff_number/customs_tariff_number.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class CustomsTariffNumber(Document):
pass
diff --git a/erpnext/stock/doctype/customs_tariff_number/test_customs_tariff_number.js b/erpnext/stock/doctype/customs_tariff_number/test_customs_tariff_number.js
deleted file mode 100644
index 85812d69739..00000000000
--- a/erpnext/stock/doctype/customs_tariff_number/test_customs_tariff_number.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Customs Tariff Number", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Customs Tariff Number
- () => frappe.tests.make('Customs Tariff Number', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/customs_tariff_number/test_customs_tariff_number.py b/erpnext/stock/doctype/customs_tariff_number/test_customs_tariff_number.py
index d7e03067e8e..7c9807c762b 100644
--- a/erpnext/stock/doctype/customs_tariff_number/test_customs_tariff_number.py
+++ b/erpnext/stock/doctype/customs_tariff_number/test_customs_tariff_number.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestCustomsTariffNumber(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index 958189614fd..fdc8763baa6 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -543,6 +543,7 @@
{
"collapsible": 1,
"collapsible_depends_on": "packed_items",
+ "depends_on": "packed_items",
"fieldname": "packing_list",
"fieldtype": "Section Break",
"label": "Packing List",
@@ -551,6 +552,7 @@
"print_hide": 1
},
{
+ "depends_on": "packed_items",
"fieldname": "packed_items",
"fieldtype": "Table",
"label": "Packed Items",
@@ -1306,7 +1308,7 @@
"idx": 146,
"is_submittable": 1,
"links": [],
- "modified": "2021-08-17 20:15:50.574966",
+ "modified": "2021-08-27 20:14:40.215231",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index f99a01b8202..5542cd00d4c 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -4,17 +4,17 @@
from __future__ import unicode_literals
import frappe
-import frappe.defaults
-from erpnext.controllers.selling_controller import SellingController
-from erpnext.stock.doctype.batch.batch import set_batch_nos
-from erpnext.stock.doctype.serial_no.serial_no import get_delivery_note_serial_no
from frappe import _
from frappe.contacts.doctype.address.address import get_company_address
from frappe.desk.notifications import clear_doctype_notifications
from frappe.model.mapper import get_mapped_doc
from frappe.model.utils import get_fetch_values
from frappe.utils import cint, flt
+
from erpnext.controllers.accounts_controller import get_taxes_and_charges
+from erpnext.controllers.selling_controller import SellingController
+from erpnext.stock.doctype.batch.batch import set_batch_nos
+from erpnext.stock.doctype.serial_no.serial_no import get_delivery_note_serial_no
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@@ -331,7 +331,7 @@ class DeliveryNote(SellingController):
credit_note_link = frappe.utils.get_link_to_form('Sales Invoice', return_invoice.name)
frappe.msgprint(_("Credit Note {0} has been created automatically").format(credit_note_link))
- except:
+ except Exception:
frappe.throw(_("Could not create Credit Note automatically, please uncheck 'Issue Credit Note' and submit again"))
def update_billed_amount_based_on_so(so_detail, update_modified=True):
@@ -668,8 +668,13 @@ def make_inter_company_purchase_receipt(source_name, target_doc=None):
return make_inter_company_transaction("Delivery Note", source_name, target_doc)
def make_inter_company_transaction(doctype, source_name, target_doc=None):
- from erpnext.accounts.doctype.sales_invoice.sales_invoice import (validate_inter_company_transaction,
- get_inter_company_details, update_address, update_taxes, set_purchase_references)
+ from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
+ get_inter_company_details,
+ set_purchase_references,
+ update_address,
+ update_taxes,
+ validate_inter_company_transaction,
+ )
if doctype == 'Delivery Note':
source_doc = frappe.get_doc(doctype, source_name)
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py b/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py
index 9db5db865f5..31fc708eabd 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'delivery_note',
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index b333a6b57ea..7fda94b269d 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -3,26 +3,40 @@
from __future__ import unicode_literals
-import unittest
-import frappe
+
import json
-import frappe.defaults
-from frappe.utils import nowdate, nowtime, cstr, flt
-from erpnext.stock.stock_ledger import get_previous_sle
-from erpnext.accounts.utils import get_balance_on
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries
-from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice, make_delivery_trip
-from erpnext.stock.doctype.stock_entry.test_stock_entry \
- import make_stock_entry, make_serialized_item, get_qty_after_transaction
-from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, SerialNoWarehouseError
-from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation \
- import create_stock_reconciliation, set_valuation_method
-from erpnext.selling.doctype.sales_order.test_sales_order \
- import make_sales_order, create_dn_against_so, automatically_fetch_payment_terms, compare_payment_schedules
+import unittest
+
+import frappe
+from frappe.utils import cstr, flt, nowdate, nowtime
+
from erpnext.accounts.doctype.account.test_account import get_inventory_account
-from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
-from erpnext.stock.doctype.item.test_item import make_item
+from erpnext.accounts.utils import get_balance_on
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+from erpnext.selling.doctype.sales_order.test_sales_order import (
+ automatically_fetch_payment_terms,
+ compare_payment_schedules,
+ create_dn_against_so,
+ make_sales_order,
+)
+from erpnext.stock.doctype.delivery_note.delivery_note import (
+ make_delivery_trip,
+ make_sales_invoice,
+)
+from erpnext.stock.doctype.item.test_item import make_item
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries
+from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError, get_serial_nos
+from erpnext.stock.doctype.stock_entry.test_stock_entry import (
+ get_qty_after_transaction,
+ make_serialized_item,
+ make_stock_entry,
+)
+from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
+ create_stock_reconciliation,
+ set_valuation_method,
+)
+from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
+from erpnext.stock.stock_ledger import get_previous_sle
class TestDeliveryNote(unittest.TestCase):
@@ -540,7 +554,10 @@ class TestDeliveryNote(unittest.TestCase):
def test_dn_billing_status_case2(self):
# SO -> SI and SO -> DN1, DN2
- from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note, make_sales_invoice
+ from erpnext.selling.doctype.sales_order.sales_order import (
+ make_delivery_note,
+ make_sales_invoice,
+ )
so = make_sales_order()
@@ -579,8 +596,10 @@ class TestDeliveryNote(unittest.TestCase):
def test_dn_billing_status_case3(self):
# SO -> DN1 -> SI and SO -> SI and SO -> DN2
- from erpnext.selling.doctype.sales_order.sales_order \
- import make_delivery_note, make_sales_invoice as make_sales_invoice_from_so
+ from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
+ from erpnext.selling.doctype.sales_order.sales_order import (
+ make_sales_invoice as make_sales_invoice_from_so,
+ )
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
so = make_sales_order()
@@ -626,8 +645,8 @@ class TestDeliveryNote(unittest.TestCase):
def test_dn_billing_status_case4(self):
# SO -> SI -> DN
- from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_delivery_note
+ from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
so = make_sales_order()
@@ -777,7 +796,9 @@ class TestDeliveryNote(unittest.TestCase):
self.assertTrue("TESTBATCH" in dn.packed_items[0].batch_no, "Batch number not added in packed item")
def test_payment_terms_are_fetched_when_creating_sales_invoice(self):
- from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
+ from erpnext.accounts.doctype.payment_entry.test_payment_entry import (
+ create_payment_terms_template,
+ )
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
automatically_fetch_payment_terms()
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py
index 8bd381a2ed3..693caabfb85 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class DeliveryNoteItem(Document):
pass
diff --git a/erpnext/stock/doctype/delivery_settings/delivery_settings.py b/erpnext/stock/doctype/delivery_settings/delivery_settings.py
index 909efda856f..c25907defeb 100644
--- a/erpnext/stock/doctype/delivery_settings/delivery_settings.py
+++ b/erpnext/stock/doctype/delivery_settings/delivery_settings.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class DeliverySettings(Document):
pass
diff --git a/erpnext/stock/doctype/delivery_settings/test_delivery_settings.js b/erpnext/stock/doctype/delivery_settings/test_delivery_settings.js
deleted file mode 100644
index 22977c08f75..00000000000
--- a/erpnext/stock/doctype/delivery_settings/test_delivery_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Delivery Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Delivery Settings
- () => frappe.tests.make('Delivery Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/delivery_settings/test_delivery_settings.py b/erpnext/stock/doctype/delivery_settings/test_delivery_settings.py
index 4395d266287..25c9da16aa8 100644
--- a/erpnext/stock/doctype/delivery_settings/test_delivery_settings.py
+++ b/erpnext/stock/doctype/delivery_settings/test_delivery_settings.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestDeliverySettings(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/delivery_stop/delivery_stop.py b/erpnext/stock/doctype/delivery_stop/delivery_stop.py
index 768d1619f65..f94ccb80215 100644
--- a/erpnext/stock/doctype/delivery_stop/delivery_stop.py
+++ b/erpnext/stock/doctype/delivery_stop/delivery_stop.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class DeliveryStop(Document):
pass
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.py b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
index f76bb87efed..fe9818242fe 100644
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.py
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
@@ -10,8 +10,8 @@ import frappe
from frappe import _
from frappe.contacts.doctype.address.address import get_address_display
from frappe.model.document import Document
-from frappe.utils import cint, get_datetime, get_link_to_form
from frappe.model.mapper import get_mapped_doc
+from frappe.utils import cint, get_datetime, get_link_to_form
class DeliveryTrip(Document):
diff --git a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.js b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.js
deleted file mode 100644
index b6d6d1af64f..00000000000
--- a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Delivery Trip", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Delivery Trip
- () => frappe.tests.make('Delivery Trip', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
index 1e716031751..c9081c908f7 100644
--- a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
+++ b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
@@ -5,12 +5,17 @@ from __future__ import unicode_literals
import unittest
-import erpnext
import frappe
-from erpnext.stock.doctype.delivery_trip.delivery_trip import get_contact_and_address, notify_customers, make_expense_claim
-from erpnext.tests.utils import create_test_contact_and_address
from frappe.utils import add_days, flt, now_datetime, nowdate
+import erpnext
+from erpnext.stock.doctype.delivery_trip.delivery_trip import (
+ get_contact_and_address,
+ make_expense_claim,
+ notify_customers,
+)
+from erpnext.tests.utils import create_test_contact_and_address
+
class TestDeliveryTrip(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index cbd0231e66a..e346ea87214 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -17,8 +17,6 @@ frappe.ui.form.on("Item", {
frm.fields_dict["attributes"].grid.set_column_disp("attribute_value", true);
}
- // should never check Private
- frm.fields_dict["website_image"].df.is_private = 0;
if (frm.doc.is_fixed_asset) {
frm.trigger("set_asset_naming_series");
}
@@ -91,6 +89,29 @@ frappe.ui.form.on("Item", {
erpnext.toggle_naming_series();
}
+ if (!frm.doc.published_in_website) {
+ frm.add_custom_button(__("Publish in Website"), function() {
+ frappe.call({
+ method: "erpnext.e_commerce.doctype.website_item.website_item.make_website_item",
+ args: {doc: frm.doc},
+ freeze: true,
+ freeze_message: __("Publishing Item ..."),
+ callback: function(result) {
+ frappe.msgprint({
+ message: __("Website Item {0} has been created.",
+ [repl('
%(item)s ', {
+ item_encoded: encodeURIComponent(result.message[0]),
+ item: result.message[1]
+ })]
+ ),
+ title: __("Published"),
+ indicator: "green"
+ });
+ }
+ });
+ }, __('Actions'));
+ }
+
erpnext.item.edit_prices_button(frm);
erpnext.item.toggle_attributes(frm);
@@ -141,9 +162,8 @@ frappe.ui.form.on("Item", {
is_fixed_asset: function(frm) {
// set serial no to false & toggles its visibility
frm.set_value('has_serial_no', 0);
+ frm.set_value('has_batch_no', 0);
frm.toggle_enable(['has_serial_no', 'serial_no_series'], !frm.doc.is_fixed_asset);
- frm.toggle_reqd(['asset_category'], frm.doc.is_fixed_asset);
- frm.toggle_display(['has_serial_no', 'serial_no_series'], !frm.doc.is_fixed_asset);
frm.call({
method: "set_asset_naming_series",
@@ -183,25 +203,8 @@ frappe.ui.form.on("Item", {
}
},
- copy_from_item_group: function(frm) {
- return frm.call({
- doc: frm.doc,
- method: "copy_specification_from_item_group"
- });
- },
-
has_variants: function(frm) {
erpnext.item.toggle_attributes(frm);
- },
-
- show_in_website: function(frm) {
- if (frm.doc.default_warehouse && !frm.doc.website_warehouse){
- frm.set_value("website_warehouse", frm.doc.default_warehouse);
- }
- },
-
- set_meta_tags(frm) {
- frappe.utils.set_meta_tag(frm.doc.route);
}
});
@@ -394,13 +397,15 @@ $.extend(erpnext.item, {
edit_prices_button: function(frm) {
frm.add_custom_button(__("Add / Edit Prices"), function() {
frappe.set_route("List", "Item Price", {"item_code": frm.doc.name});
- }, __("View"));
+ }, __("Actions"));
},
- weight_to_validate: function(frm){
- if((frm.doc.nett_weight || frm.doc.gross_weight) && !frm.doc.weight_uom) {
- frappe.msgprint(__('Weight is mentioned,\nPlease mention "Weight UOM" too'));
- frappe.validated = 0;
+ weight_to_validate: function(frm) {
+ if (frm.doc.weight_per_unit && !frm.doc.weight_uom) {
+ frappe.msgprint({
+ message: __("Please mention 'Weight UOM' along with Weight."),
+ title: __("Note")
+ });
}
},
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index f662bbd1c79..e360cca124e 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -116,30 +116,14 @@
"customer_code",
"default_item_manufacturer",
"default_manufacturer_part_no",
- "website_section",
- "show_in_website",
- "show_variant_in_website",
- "route",
- "weightage",
- "slideshow",
- "website_image",
- "website_image_alt",
- "thumbnail",
- "cb72",
- "website_warehouse",
- "website_item_groups",
- "set_meta_tags",
- "sb72",
- "copy_from_item_group",
- "website_specifications",
- "web_long_description",
- "website_content",
- "total_projected_qty",
"hub_publishing_sb",
"publish_in_hub",
"hub_category_to_publish",
"hub_warehouse",
- "synced_with_hub"
+ "synced_with_hub",
+ "more_information_section",
+ "published_in_website",
+ "total_projected_qty"
],
"fields": [
{
@@ -204,6 +188,7 @@
},
{
"default": "0",
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "is_item_from_hub",
"fieldtype": "Check",
"label": "Is Item from Hub",
@@ -238,6 +223,7 @@
{
"bold": 1,
"default": "1",
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "is_stock_item",
"fieldtype": "Check",
"label": "Maintain Stock",
@@ -246,6 +232,7 @@
},
{
"default": "1",
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "include_item_in_manufacturing",
"fieldtype": "Check",
"label": "Include Item In Manufacturing"
@@ -282,6 +269,7 @@
"fieldname": "asset_category",
"fieldtype": "Link",
"label": "Asset Category",
+ "mandatory_depends_on": "is_fixed_asset",
"options": "Asset Category"
},
{
@@ -434,8 +422,8 @@
},
{
"collapsible": 1,
- "collapsible_depends_on": "eval:doc.has_batch_no || doc.has_serial_no || doc.is_fixed_asset",
- "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
+ "collapsible_depends_on": "eval:doc.has_batch_no || doc.has_serial_no",
+ "depends_on": "eval:doc.is_stock_item",
"fieldname": "serial_nos_and_batches",
"fieldtype": "Section Break",
"label": "Serial Nos and Batches"
@@ -492,7 +480,7 @@
},
{
"default": "0",
- "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
+ "depends_on": "eval:doc.is_stock_item",
"fieldname": "has_serial_no",
"fieldtype": "Check",
"label": "Has Serial No",
@@ -510,6 +498,7 @@
{
"collapsible": 1,
"collapsible_depends_on": "attributes",
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "variants_section",
"fieldtype": "Section Break",
"label": "Variants"
@@ -540,6 +529,7 @@
"options": "Item Variant Attribute"
},
{
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "defaults",
"fieldtype": "Section Break",
"label": "Sales, Purchase, Accounting Defaults"
@@ -621,6 +611,7 @@
},
{
"collapsible": 1,
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "supplier_details",
"fieldtype": "Section Break",
"label": "Supplier Details"
@@ -668,6 +659,7 @@
},
{
"collapsible": 1,
+ "default": "eval:!doc.is_fixed_asset",
"fieldname": "sales_details",
"fieldtype": "Section Break",
"label": "Sales Details",
@@ -761,6 +753,7 @@
},
{
"collapsible": 1,
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "customer_details",
"fieldtype": "Section Break",
"label": "Customer Details"
@@ -791,6 +784,7 @@
},
{
"collapsible": 1,
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "inspection_criteria",
"fieldtype": "Section Break",
"label": "Inspection Criteria",
@@ -859,124 +853,6 @@
"no_copy": 1,
"print_hide": 1
},
- {
- "collapsible": 1,
- "fieldname": "website_section",
- "fieldtype": "Section Break",
- "label": "Website",
- "options": "fa fa-globe"
- },
- {
- "default": "0",
- "depends_on": "eval:!doc.variant_of",
- "fieldname": "show_in_website",
- "fieldtype": "Check",
- "label": "Show in Website",
- "search_index": 1
- },
- {
- "default": "0",
- "depends_on": "variant_of",
- "fieldname": "show_variant_in_website",
- "fieldtype": "Check",
- "label": "Show in Website (Variant)",
- "search_index": 1
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "fieldname": "route",
- "fieldtype": "Small Text",
- "label": "Route",
- "no_copy": 1
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "description": "Items with higher weightage will be shown higher",
- "fieldname": "weightage",
- "fieldtype": "Int",
- "label": "Weightage"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "description": "Show a slideshow at the top of the page",
- "fieldname": "slideshow",
- "fieldtype": "Link",
- "label": "Slideshow",
- "options": "Website Slideshow"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "description": "Item Image (if not slideshow)",
- "fieldname": "website_image",
- "fieldtype": "Attach",
- "label": "Website Image"
- },
- {
- "fieldname": "thumbnail",
- "fieldtype": "Data",
- "label": "Thumbnail",
- "read_only": 1
- },
- {
- "fieldname": "cb72",
- "fieldtype": "Column Break"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "description": "Show \"In Stock\" or \"Not in Stock\" based on stock available in this warehouse.",
- "fieldname": "website_warehouse",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Website Warehouse",
- "options": "Warehouse"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "description": "List this Item in multiple groups on the website.",
- "fieldname": "website_item_groups",
- "fieldtype": "Table",
- "label": "Website Item Groups",
- "options": "Website Item Group"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "fieldname": "set_meta_tags",
- "fieldtype": "Button",
- "label": "Set Meta Tags"
- },
- {
- "collapsible": 1,
- "collapsible_depends_on": "website_specifications",
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "fieldname": "sb72",
- "fieldtype": "Section Break",
- "label": "Website Specifications"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "fieldname": "copy_from_item_group",
- "fieldtype": "Button",
- "label": "Copy From Item Group"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "fieldname": "website_specifications",
- "fieldtype": "Table",
- "label": "Website Specifications",
- "options": "Item Website Specification"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "fieldname": "web_long_description",
- "fieldtype": "Text Editor",
- "label": "Website Description"
- },
- {
- "description": "You can use any valid Bootstrap 4 markup in this field. It will be shown on your Item Page.",
- "fieldname": "website_content",
- "fieldtype": "HTML Editor",
- "label": "Website Content"
- },
{
"fieldname": "total_projected_qty",
"fieldtype": "Float",
@@ -987,7 +863,7 @@
},
{
"collapsible": 1,
- "depends_on": "eval:(!doc.is_item_from_hub)",
+ "depends_on": "eval:(!doc.is_item_from_hub && !doc.is_fixed_asset)",
"fieldname": "hub_publishing_sb",
"fieldtype": "Section Break",
"label": "Hub Publishing Details"
@@ -1021,7 +897,7 @@
"read_only": 1
},
{
- "depends_on": "eval:!doc.__islocal",
+ "depends_on": "eval:!doc.__islocal && !doc.is_fixed_asset",
"fieldname": "over_delivery_receipt_allowance",
"fieldtype": "Float",
"label": "Over Delivery/Receipt Allowance (%)",
@@ -1029,7 +905,7 @@
"oldfieldtype": "Currency"
},
{
- "depends_on": "eval:!doc.__islocal",
+ "depends_on": "eval:!doc.__islocal && !doc.is_fixed_asset",
"fieldname": "over_billing_allowance",
"fieldtype": "Float",
"label": "Over Billing Allowance (%)"
@@ -1054,20 +930,27 @@
"read_only": 1
},
{
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "fieldname": "website_image_alt",
- "fieldtype": "Data",
- "label": "Image Description"
+ "collapsible": 1,
+ "fieldname": "more_information_section",
+ "fieldtype": "Section Break",
+ "label": "More Information"
+ },
+ {
+ "default": "0",
+ "depends_on": "published_in_website",
+ "fieldname": "published_in_website",
+ "fieldtype": "Check",
+ "label": "Published in Website",
+ "read_only": 1
}
],
- "has_web_view": 1,
"icon": "fa fa-tag",
"idx": 2,
"image_field": "image",
"index_web_pages_for_search": 1,
"links": [],
"max_attachments": 1,
- "modified": "2021-07-13 01:29:06.071827",
+ "modified": "2021-09-10 12:23:07.277077",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index ca587bfe82c..50f68665a3a 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -1,23 +1,34 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-import itertools
-import json
-import erpnext
-import frappe
import copy
-from erpnext.controllers.item_variant import (ItemVariantExistsError,
- copy_attributes_to_variant, get_variant, make_variant_item_code, validate_item_variant_attributes)
-from erpnext.setup.doctype.item_group.item_group import (get_parent_item_groups, invalidate_cache_for)
-from frappe import _, msgprint
-from frappe.utils import (cint, cstr, flt, formatdate, getdate,
- now_datetime, random_string, strip, get_link_to_form, nowtime)
-from frappe.utils.html_utils import clean_html
-from frappe.website.doctype.website_slideshow.website_slideshow import \
- get_slideshow
+import json
-from frappe.website.render import clear_cache
-from frappe.website.website_generator import WebsiteGenerator
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from frappe.utils import (
+ cint,
+ cstr,
+ flt,
+ formatdate,
+ get_link_to_form,
+ getdate,
+ now_datetime,
+ nowtime,
+ strip,
+)
+from frappe.utils.html_utils import clean_html
+
+import erpnext
+from erpnext.controllers.item_variant import (
+ ItemVariantExistsError,
+ copy_attributes_to_variant,
+ get_variant,
+ make_variant_item_code,
+ validate_item_variant_attributes,
+)
+from erpnext.setup.doctype.item_group.item_group import invalidate_cache_for
class DuplicateReorderRows(frappe.ValidationError):
@@ -31,18 +42,11 @@ class StockExistsForTemplate(frappe.ValidationError):
class InvalidBarcode(frappe.ValidationError):
pass
+class DataValidationError(frappe.ValidationError):
+ pass
-class Item(WebsiteGenerator):
- website = frappe._dict(
- page_title_field="item_name",
- condition_field="show_in_website",
- template="templates/generators/item/item.html",
- no_cache=1
- )
-
+class Item(Document):
def onload(self):
- super(Item, self).onload()
-
self.set_onload('stock_exists', self.stock_ledger_created())
self.set_asset_naming_series()
@@ -83,8 +87,6 @@ class Item(WebsiteGenerator):
self.set_opening_stock()
def validate(self):
- super(Item, self).validate()
-
if not self.item_name:
self.item_name = self.item_code
@@ -111,8 +113,6 @@ class Item(WebsiteGenerator):
self.validate_attributes()
self.validate_variant_attributes()
self.validate_variant_based_on_change()
- self.validate_website_image()
- self.make_thumbnail()
self.validate_fixed_asset()
self.validate_retain_sample()
self.validate_uom_conversion_factor()
@@ -121,22 +121,18 @@ class Item(WebsiteGenerator):
self.update_defaults_from_item_group()
self.validate_auto_reorder_enabled_in_stock_settings()
self.cant_change()
- self.update_show_in_website()
self.validate_item_tax_net_rate_range()
set_item_tax_from_hsn_code(self)
if not self.is_new():
self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group")
- self.old_website_item_groups = frappe.db.sql_list("""select item_group
- from `tabWebsite Item Group`
- where parentfield='website_item_groups' and parenttype='Item' and parent=%s""", self.name)
def on_update(self):
invalidate_cache_for_item(self)
self.validate_name_with_item_group()
self.update_variants()
self.update_item_price()
- self.update_template_item()
+ self.update_website_item()
def validate_description(self):
'''Clean HTML description if set'''
@@ -196,95 +192,6 @@ class Item(WebsiteGenerator):
stock_entry.add_comment("Comment", _("Opening Stock"))
- def make_route(self):
- if not self.route:
- return cstr(frappe.db.get_value('Item Group', self.item_group,
- 'route')) + '/' + self.scrub((self.item_name or self.item_code) + '-' + random_string(5))
-
- def validate_website_image(self):
- if frappe.flags.in_import:
- return
-
- """Validate if the website image is a public file"""
- auto_set_website_image = False
- if not self.website_image and self.image:
- auto_set_website_image = True
- self.website_image = self.image
-
- if not self.website_image:
- return
-
- # find if website image url exists as public
- file_doc = frappe.get_all("File", filters={
- "file_url": self.website_image
- }, fields=["name", "is_private"], order_by="is_private asc", limit_page_length=1)
-
- if file_doc:
- file_doc = file_doc[0]
-
- if not file_doc:
- if not auto_set_website_image:
- frappe.msgprint(_("Website Image {0} attached to Item {1} cannot be found").format(self.website_image, self.name))
-
- self.website_image = None
-
- elif file_doc.is_private:
- if not auto_set_website_image:
- frappe.msgprint(_("Website Image should be a public file or website URL"))
-
- self.website_image = None
-
- def make_thumbnail(self):
- if frappe.flags.in_import:
- return
-
- """Make a thumbnail of `website_image`"""
- import requests.exceptions
-
- if not self.is_new() and self.website_image != frappe.db.get_value(self.doctype, self.name, "website_image"):
- self.thumbnail = None
-
- if self.website_image and not self.thumbnail:
- file_doc = None
-
- try:
- file_doc = frappe.get_doc("File", {
- "file_url": self.website_image,
- "attached_to_doctype": "Item",
- "attached_to_name": self.name
- })
- except frappe.DoesNotExistError:
- # cleanup
- frappe.local.message_log.pop()
-
- except requests.exceptions.HTTPError:
- frappe.msgprint(_("Warning: Invalid attachment {0}").format(self.website_image))
- self.website_image = None
-
- except requests.exceptions.SSLError:
- frappe.msgprint(
- _("Warning: Invalid SSL certificate on attachment {0}").format(self.website_image))
- self.website_image = None
-
- # for CSV import
- if self.website_image and not file_doc:
- try:
- file_doc = frappe.get_doc({
- "doctype": "File",
- "file_url": self.website_image,
- "attached_to_doctype": "Item",
- "attached_to_name": self.name
- }).save()
-
- except IOError:
- self.website_image = None
-
- if file_doc:
- if not file_doc.thumbnail_url:
- file_doc.make_thumbnail()
-
- self.thumbnail = file_doc.thumbnail_url
-
def validate_fixed_asset(self):
if self.is_fixed_asset:
if self.is_stock_item:
@@ -308,167 +215,6 @@ class Item(WebsiteGenerator):
frappe.throw(_("{0} Retain Sample is based on batch, please check Has Batch No to retain sample of item").format(
self.item_code))
- def get_context(self, context):
- context.show_search = True
- context.search_link = '/product_search'
-
- context.parents = get_parent_item_groups(self.item_group)
- context.body_class = "product-page"
-
- self.set_variant_context(context)
- self.set_attribute_context(context)
- self.set_disabled_attributes(context)
- self.set_metatags(context)
- self.set_shopping_cart_data(context)
-
- return context
-
- def set_variant_context(self, context):
- if self.has_variants:
- context.no_cache = True
-
- # load variants
- # also used in set_attribute_context
- context.variants = frappe.get_all("Item",
- filters={"variant_of": self.name, "show_variant_in_website": 1},
- order_by="name asc")
-
- variant = frappe.form_dict.variant
- if not variant and context.variants:
- # the case when the item is opened for the first time from its list
- variant = context.variants[0]
-
- if variant:
- context.variant = frappe.get_doc("Item", variant)
-
- for fieldname in ("website_image", "website_image_alt", "web_long_description", "description",
- "website_specifications"):
- if context.variant.get(fieldname):
- value = context.variant.get(fieldname)
- if isinstance(value, list):
- value = [d.as_dict() for d in value]
-
- context[fieldname] = value
-
- if self.slideshow:
- if context.variant and context.variant.slideshow:
- context.update(get_slideshow(context.variant))
- else:
- context.update(get_slideshow(self))
-
- def set_attribute_context(self, context):
- if not self.has_variants:
- return
-
- attribute_values_available = {}
- context.attribute_values = {}
- context.selected_attributes = {}
-
- # load attributes
- for v in context.variants:
- v.attributes = frappe.get_all("Item Variant Attribute",
- fields=["attribute", "attribute_value"],
- filters={"parent": v.name})
- # make a map for easier access in templates
- v.attribute_map = frappe._dict({})
- for attr in v.attributes:
- v.attribute_map[attr.attribute] = attr.attribute_value
-
- for attr in v.attributes:
- values = attribute_values_available.setdefault(attr.attribute, [])
- if attr.attribute_value not in values:
- values.append(attr.attribute_value)
-
- if v.name == context.variant.name:
- context.selected_attributes[attr.attribute] = attr.attribute_value
-
- # filter attributes, order based on attribute table
- for attr in self.attributes:
- values = context.attribute_values.setdefault(attr.attribute, [])
-
- if cint(frappe.db.get_value("Item Attribute", attr.attribute, "numeric_values")):
- for val in sorted(attribute_values_available.get(attr.attribute, []), key=flt):
- values.append(val)
-
- else:
- # get list of values defined (for sequence)
- for attr_value in frappe.db.get_all("Item Attribute Value",
- fields=["attribute_value"],
- filters={"parent": attr.attribute}, order_by="idx asc"):
-
- if attr_value.attribute_value in attribute_values_available.get(attr.attribute, []):
- values.append(attr_value.attribute_value)
-
- context.variant_info = json.dumps(context.variants)
-
- def set_disabled_attributes(self, context):
- """Disable selection options of attribute combinations that do not result in a variant"""
- if not self.attributes or not self.has_variants:
- return
-
- context.disabled_attributes = {}
- attributes = [attr.attribute for attr in self.attributes]
-
- def find_variant(combination):
- for variant in context.variants:
- if len(variant.attributes) < len(attributes):
- continue
-
- if "combination" not in variant:
- ref_combination = []
-
- for attr in variant.attributes:
- idx = attributes.index(attr.attribute)
- ref_combination.insert(idx, attr.attribute_value)
-
- variant["combination"] = ref_combination
-
- if not (set(combination) - set(variant["combination"])):
- # check if the combination is a subset of a variant combination
- # eg. [Blue, 0.5] is a possible combination if exists [Blue, Large, 0.5]
- return True
-
- for i, attr in enumerate(self.attributes):
- if i == 0:
- continue
-
- combination_source = []
-
- # loop through previous attributes
- for prev_attr in self.attributes[:i]:
- combination_source.append([context.selected_attributes.get(prev_attr.attribute)])
-
- combination_source.append(context.attribute_values[attr.attribute])
-
- for combination in itertools.product(*combination_source):
- if not find_variant(combination):
- context.disabled_attributes.setdefault(attr.attribute, []).append(combination[-1])
-
- def set_metatags(self, context):
- context.metatags = frappe._dict({})
-
- safe_description = frappe.utils.to_markdown(self.description)
-
- context.metatags.url = frappe.utils.get_url() + '/' + context.route
-
- if context.website_image:
- if context.website_image.startswith('http'):
- url = context.website_image
- else:
- url = frappe.utils.get_url() + context.website_image
- context.metatags.image = url
-
- context.metatags.description = safe_description[:300]
-
- context.metatags.title = self.item_name or self.item_code
-
- context.metatags['og:type'] = 'product'
- context.metatags['og:site_name'] = 'ERPNext'
-
- def set_shopping_cart_data(self, context):
- from erpnext.shopping_cart.product_info import get_product_info_for_website
- context.shopping_cart = get_product_info_for_website(self.name, skip_quotation_creation=True)
-
def add_default_uom_in_conversion_factor_table(self):
uom_conv_list = [d.uom for d in self.get("uoms")]
if self.stock_uom not in uom_conv_list:
@@ -483,9 +229,29 @@ class Item(WebsiteGenerator):
[self.remove(d) for d in to_remove]
- def update_show_in_website(self):
- if self.disabled:
- self.show_in_website = False
+ def update_website_item(self):
+ """Update Website Item if change in Item impacts it."""
+ web_item = frappe.db.exists("Website Item", {"item_code": self.item_code})
+
+ if web_item:
+ changed = {}
+ editable_fields = ["item_name", "item_group", "stock_uom", "brand", "description",
+ "disabled"]
+ doc_before_save = self.get_doc_before_save()
+
+ for field in editable_fields:
+ if doc_before_save.get(field) != self.get(field):
+ if field == "disabled":
+ changed["published"] = not self.get(field)
+ else:
+ changed[field] = self.get(field)
+
+ if not changed:
+ return
+
+ web_item_doc = frappe.get_doc("Website Item", web_item)
+ web_item_doc.update(changed)
+ web_item_doc.save()
def validate_item_tax_net_rate_range(self):
for tax in self.get('taxes'):
@@ -615,7 +381,6 @@ class Item(WebsiteGenerator):
(self.item_name, self.description, self.brand, self.name))
def on_trash(self):
- super(Item, self).on_trash()
frappe.db.sql("""delete from tabBin where item_code=%s""", self.name)
frappe.db.sql("delete from `tabItem Price` where item_code=%s", self.name)
for variant_of in frappe.get_all("Item", filters={"variant_of": self.name}):
@@ -626,23 +391,15 @@ class Item(WebsiteGenerator):
frappe.db.set_value("Item", old_name, "item_name", new_name)
if merge:
- # Validate properties before merging
- if not frappe.db.exists("Item", new_name):
- frappe.throw(_("Item {0} does not exist").format(new_name))
-
- field_list = ["stock_uom", "is_stock_item", "has_serial_no", "has_batch_no"]
- new_properties = [cstr(d) for d in frappe.db.get_value("Item", new_name, field_list)]
- if new_properties != [cstr(self.get(fld)) for fld in field_list]:
- frappe.throw(_("To merge, following properties must be same for both items")
- + ": \n" + ", ".join([self.meta.get_label(fld) for fld in field_list]))
+ self.validate_properties_before_merge(new_name)
+ self.validate_duplicate_website_item_before_merge(old_name, new_name)
def after_rename(self, old_name, new_name, merge):
if merge:
self.validate_duplicate_item_in_stock_reconciliation(old_name, new_name)
- if self.route:
+ if self.published_in_website:
invalidate_cache_for_item(self)
- clear_cache(self.route)
frappe.db.set_value("Item", new_name, "item_code", new_name)
@@ -682,7 +439,41 @@ class Item(WebsiteGenerator):
msg += _("Note: To merge the items, create a separate Stock Reconciliation for the old item {0}").format(
frappe.bold(old_name))
- frappe.throw(_(msg), title=_("Merge not allowed"))
+ frappe.throw(_(msg), title=_("Cannot Merge"), exc=DataValidationError)
+
+ def validate_properties_before_merge(self, new_name):
+ # Validate properties before merging
+ if not frappe.db.exists("Item", new_name):
+ frappe.throw(_("Item {0} does not exist").format(new_name))
+
+ field_list = ["stock_uom", "is_stock_item", "has_serial_no", "has_batch_no"]
+ new_properties = [cstr(d) for d in frappe.db.get_value("Item", new_name, field_list)]
+
+ if new_properties != [cstr(self.get(field)) for field in field_list]:
+ msg = _("To merge, following properties must be same for both items")
+ msg += ": \n" + ", ".join([self.meta.get_label(fld) for fld in field_list])
+ frappe.throw(msg, title=_("Cannot Merge"), exc=DataValidationError)
+
+ def validate_duplicate_website_item_before_merge(self, old_name, new_name):
+ """
+ Block merge if both old and new items have website items against them.
+ This is to avoid duplicate website items after merging.
+ """
+ web_items = frappe.get_all(
+ "Website Item",
+ filters={
+ "item_code": ["in", [old_name, new_name]]
+ },
+ fields=["item_code", "name"])
+
+ if len(web_items) <= 1:
+ return
+
+ old_web_item = [d.get("name") for d in web_items if d.get("item_code") == old_name][0]
+ web_item_link = get_link_to_form("Website Item", old_web_item)
+
+ msg = f"Please delete linked Website Item {frappe.bold(web_item_link)} before merging {old_name} and {new_name}"
+ frappe.throw(_(msg), title=_("Cannot Merge"), exc=DataValidationError)
def set_last_purchase_rate(self, new_name):
last_purchase_rate = get_last_purchase_details(new_name).get("base_net_rate", 0)
@@ -706,16 +497,6 @@ class Item(WebsiteGenerator):
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock)
frappe.db.auto_commit_on_many_writes = 0
- @frappe.whitelist()
- def copy_specification_from_item_group(self):
- self.set("website_specifications", [])
- if self.item_group:
- for label, desc in frappe.db.get_values("Item Website Specification",
- {"parent": self.item_group}, ["label", "description"]):
- row = self.append("website_specifications")
- row.label = label
- row.description = desc
-
def update_bom_item_desc(self):
if self.is_new():
return
@@ -739,25 +520,6 @@ class Item(WebsiteGenerator):
where item_code = %s and docstatus < 2
""", (self.description, self.name))
- def update_template_item(self):
- """Set Show in Website for Template Item if True for its Variant"""
- if not self.variant_of:
- return
-
- if self.show_in_website:
- self.show_variant_in_website = 1
- self.show_in_website = 0
-
- if self.show_variant_in_website:
- # show template
- template_item = frappe.get_doc("Item", self.variant_of)
-
- if not template_item.show_in_website:
- template_item.show_in_website = 1
- template_item.flags.dont_update_variants = True
- template_item.flags.ignore_permissions = True
- template_item.save()
-
def validate_item_defaults(self):
companies = {row.company for row in self.item_defaults}
@@ -1004,47 +766,6 @@ class Item(WebsiteGenerator):
if not enabled:
frappe.msgprint(msg=_("You have to enable auto re-order in Stock Settings to maintain re-order levels."), title=_("Enable Auto Re-Order"), indicator="orange")
- def create_onboarding_docs(self, args):
- company = frappe.defaults.get_defaults().get('company') or \
- frappe.db.get_single_value('Global Defaults', 'default_company')
-
- for i in range(1, args.get('max_count')):
- item = args.get('item_' + str(i))
- if item:
- default_warehouse = ''
- default_warehouse = frappe.db.get_value('Warehouse', filters={
- 'warehouse_name': _('Finished Goods'),
- 'company': company
- })
-
- try:
- frappe.get_doc({
- 'doctype': self.doctype,
- 'item_code': item,
- 'item_name': item,
- 'description': item,
- 'show_in_website': 1,
- 'is_sales_item': 1,
- 'is_purchase_item': 1,
- 'is_stock_item': 1,
- 'item_group': _('Products'),
- 'stock_uom': _(args.get('item_uom_' + str(i))),
- 'item_defaults': [{
- 'default_warehouse': default_warehouse,
- 'company': company
- }]
- }).insert()
-
- except frappe.NameError:
- pass
- else:
- if args.get('item_price_' + str(i)):
- item_price = flt(args.get('item_price_' + str(i)))
-
- price_list_name = frappe.db.get_value('Price List', {'selling': 1})
- make_item_price(item, price_list_name, item_price)
- price_list_name = frappe.db.get_value('Price List', {'buying': 1})
- make_item_price(item, price_list_name, item_price)
def make_item_price(item, price_list_name, item_price):
frappe.get_doc({
@@ -1159,14 +880,9 @@ def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0):
def invalidate_cache_for_item(doc):
+ """Invalidate Item Group cache and rebuild ItemVariantsCacheManager."""
invalidate_cache_for(doc, doc.item_group)
- website_item_groups = list(set((doc.get("old_website_item_groups") or [])
- + [d.item_group for d in doc.get({"doctype": "Website Item Group"}) if d.item_group]))
-
- for item_group in website_item_groups:
- invalidate_cache_for(doc, item_group)
-
if doc.get("old_item_group") and doc.get("old_item_group") != doc.item_group:
invalidate_cache_for(doc, doc.old_item_group)
@@ -1174,12 +890,14 @@ def invalidate_cache_for_item(doc):
def invalidate_item_variants_cache_for_website(doc):
- from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager
+ """Rebuild ItemVariantsCacheManager via Item or Website Item."""
+ from erpnext.e_commerce.variant_selector.item_variants_cache import ItemVariantsCacheManager
item_code = None
- if doc.has_variants and doc.show_in_website:
- item_code = doc.name
- elif doc.variant_of and frappe.db.get_value('Item', doc.variant_of, 'show_in_website'):
+ is_web_item = doc.get("published_in_website") or doc.get("published")
+ if doc.has_variants and is_web_item:
+ item_code = doc.item_code
+ elif doc.variant_of and frappe.db.get_value('Item', doc.variant_of, 'published_in_website'):
item_code = doc.variant_of
if item_code:
@@ -1303,10 +1021,6 @@ def update_variants(variants, template, publish_progress=True):
if publish_progress:
frappe.publish_progress(count / total * 100, title=_("Updating Variants..."))
-def on_doctype_update():
- # since route is a Text column, it needs a length for indexing
- frappe.db.add_index("Item", ["route(500)"])
-
@erpnext.allow_regional
def set_item_tax_from_hsn_code(item):
pass
diff --git a/erpnext/stock/doctype/item/item_dashboard.py b/erpnext/stock/doctype/item/item_dashboard.py
index b3e4796354b..e80ed6fcda9 100644
--- a/erpnext/stock/doctype/item/item_dashboard.py
+++ b/erpnext/stock/doctype/item/item_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'heatmap': True,
diff --git a/erpnext/stock/doctype/item/test_item.js b/erpnext/stock/doctype/item/test_item.js
deleted file mode 100644
index af44278a59a..00000000000
--- a/erpnext/stock/doctype/item/test_item.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Item", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Item
- () => frappe.tests.make('Item', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 9ec44d2e2e4..9eeb5ab1ba9 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -2,21 +2,31 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import unittest
-import frappe
-import json
+import json
+import unittest
+
+import frappe
from frappe.test_runner import make_test_objects
-from erpnext.controllers.item_variant import (create_variant, ItemVariantExistsError,
- InvalidItemAttributeValueError, get_variant)
-from erpnext.stock.doctype.item.item import StockExistsForTemplate, InvalidBarcode
-from erpnext.stock.doctype.item.item import (get_uom_conv_factor, get_item_attribute,
- validate_is_stock_item, get_timeline_data)
+
+from erpnext.controllers.item_variant import (
+ InvalidItemAttributeValueError,
+ ItemVariantExistsError,
+ create_variant,
+ get_variant,
+)
+from erpnext.stock.doctype.item.item import (
+ InvalidBarcode,
+ StockExistsForTemplate,
+ get_item_attribute,
+ get_timeline_data,
+ get_uom_conv_factor,
+ validate_is_stock_item,
+)
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.stock.get_item_details import get_item_details
from erpnext.tests.utils import change_settings
-
test_ignore = ["BOM"]
test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand", "Item Attribute"]
@@ -506,19 +516,6 @@ class TestItem(unittest.TestCase):
self.assertIsInstance(count, int)
self.assertTrue(count >= 0)
- def test_index_creation(self):
- "check if index is getting created in db"
- from erpnext.stock.doctype.item.item import on_doctype_update
- on_doctype_update()
-
- indices = frappe.db.sql("show index from tabItem", as_dict=1)
- expected_columns = {"item_code", "item_name", "item_group", "route"}
- for index in indices:
- expected_columns.discard(index.get("Column_name"))
-
- if expected_columns:
- self.fail(f"Expected db index on these columns: {', '.join(expected_columns)}")
-
def test_attribute_completions(self):
expected_attrs = {"Small", "Extra Small", "Extra Large", "Large", "2XL", "Medium"}
@@ -590,8 +587,8 @@ def make_item_variant():
test_records = frappe.get_test_records('Item')
def create_item(item_code, is_stock_item=1, valuation_rate=0, warehouse="_Test Warehouse - _TC",
- is_customer_provided_item=None, customer=None, is_purchase_item=None, opening_stock=0,
- company="_Test Company"):
+ is_customer_provided_item=None, customer=None, is_purchase_item=None, opening_stock=0, is_fixed_asset=0,
+ asset_category=None, company="_Test Company"):
if not frappe.db.exists("Item", item_code):
item = frappe.new_doc("Item")
item.item_code = item_code
@@ -599,6 +596,8 @@ def create_item(item_code, is_stock_item=1, valuation_rate=0, warehouse="_Test W
item.description = item_code
item.item_group = "All Item Groups"
item.is_stock_item = is_stock_item
+ item.is_fixed_asset = is_fixed_asset
+ item.asset_category = asset_category
item.opening_stock = opening_stock
item.valuation_rate = valuation_rate
item.is_purchase_item = is_purchase_item
diff --git a/erpnext/stock/doctype/item/test_records.json b/erpnext/stock/doctype/item/test_records.json
index 6cec85288fe..91c77d51529 100644
--- a/erpnext/stock/doctype/item/test_records.json
+++ b/erpnext/stock/doctype/item/test_records.json
@@ -40,9 +40,7 @@
"conversion_factor": 10.0
}
],
- "stock_uom": "_Test UOM",
- "show_in_website": 1,
- "website_warehouse": "_Test Warehouse - _TC"
+ "stock_uom": "_Test UOM"
},
{
"description": "_Test Item 2",
@@ -56,8 +54,6 @@
"item_group": "_Test Item Group",
"item_name": "_Test Item 2",
"stock_uom": "_Test UOM",
- "show_in_website": 1,
- "website_warehouse": "_Test Warehouse - _TC",
"gst_hsn_code": "999800",
"opening_stock": 10,
"valuation_rate": 100,
@@ -311,8 +307,7 @@
"warehouse_reorder_level": 20,
"warehouse_reorder_qty": 20
}
- ],
- "show_in_website": 1
+ ]
},
{
"description": "_Test Item 1",
@@ -344,9 +339,7 @@
"warehouse_reorder_qty": 20
}
],
- "stock_uom": "_Test UOM",
- "show_in_website": 1,
- "website_warehouse": "_Test Warehouse Group-C1 - _TC"
+ "stock_uom": "_Test UOM"
},
{
"description": "_Test Item With Item Tax Template",
diff --git a/erpnext/stock/doctype/item_alternative/item_alternative.py b/erpnext/stock/doctype/item_alternative/item_alternative.py
index 190cb62e997..6080fb4a5fa 100644
--- a/erpnext/stock/doctype/item_alternative/item_alternative.py
+++ b/erpnext/stock/doctype/item_alternative/item_alternative.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
class ItemAlternative(Document):
def validate(self):
self.has_alternative_item()
diff --git a/erpnext/stock/doctype/item_alternative/test_item_alternative.js b/erpnext/stock/doctype/item_alternative/test_item_alternative.js
deleted file mode 100644
index 87318499fe4..00000000000
--- a/erpnext/stock/doctype/item_alternative/test_item_alternative.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Item Alternative", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Item Alternative
- () => frappe.tests.make('Item Alternative', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/item_alternative/test_item_alternative.py b/erpnext/stock/doctype/item_alternative/test_item_alternative.py
index 8f76844bde0..2be8ef740a4 100644
--- a/erpnext/stock/doctype/item_alternative/test_item_alternative.py
+++ b/erpnext/stock/doctype/item_alternative/test_item_alternative.py
@@ -2,17 +2,27 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
-import frappe, json
-from frappe.utils import flt
-from erpnext.stock.doctype.item.test_item import create_item
-from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
-from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
-from erpnext.manufacturing.doctype.work_order.work_order import make_stock_entry
-from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
-from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
-from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt, make_rm_stock_entry
+
+import json
import unittest
+import frappe
+from frappe.utils import flt
+
+from erpnext.buying.doctype.purchase_order.purchase_order import (
+ make_purchase_receipt,
+ make_rm_stock_entry,
+)
+from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
+from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
+from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
+from erpnext.manufacturing.doctype.work_order.work_order import make_stock_entry
+from erpnext.stock.doctype.item.test_item import create_item
+from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
+ create_stock_reconciliation,
+)
+
+
class TestItemAlternative(unittest.TestCase):
def setUp(self):
make_items()
diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.py b/erpnext/stock/doctype/item_attribute/item_attribute.py
index 3764738e838..9894788b8c2 100644
--- a/erpnext/stock/doctype/item_attribute/item_attribute.py
+++ b/erpnext/stock/doctype/item_attribute/item_attribute.py
@@ -2,13 +2,17 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
from frappe import _
+from frappe.model.document import Document
from frappe.utils import flt
-from erpnext.controllers.item_variant import (validate_is_incremental,
- validate_item_attribute_value, InvalidItemAttributeValueError)
+from erpnext.controllers.item_variant import (
+ InvalidItemAttributeValueError,
+ validate_is_incremental,
+ validate_item_attribute_value,
+)
class ItemAttributeIncrementError(frappe.ValidationError): pass
diff --git a/erpnext/stock/doctype/item_attribute/test_item_attribute.py b/erpnext/stock/doctype/item_attribute/test_item_attribute.py
index 07af176a944..fc809f443e6 100644
--- a/erpnext/stock/doctype/item_attribute/test_item_attribute.py
+++ b/erpnext/stock/doctype/item_attribute/test_item_attribute.py
@@ -2,13 +2,16 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
+
import unittest
+import frappe
+
test_records = frappe.get_test_records('Item Attribute')
from erpnext.stock.doctype.item_attribute.item_attribute import ItemAttributeIncrementError
+
class TestItemAttribute(unittest.TestCase):
def setUp(self):
if frappe.db.exists("Item Attribute", "_Test_Length"):
diff --git a/erpnext/stock/doctype/item_attribute_value/item_attribute_value.py b/erpnext/stock/doctype/item_attribute_value/item_attribute_value.py
index edbab002da0..ceffb4972a9 100644
--- a/erpnext/stock/doctype/item_attribute_value/item_attribute_value.py
+++ b/erpnext/stock/doctype/item_attribute_value/item_attribute_value.py
@@ -2,8 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ItemAttributeValue(Document):
pass
diff --git a/erpnext/stock/doctype/item_customer_detail/item_customer_detail.py b/erpnext/stock/doctype/item_customer_detail/item_customer_detail.py
index 3e4e8500467..55fd0ec3436 100644
--- a/erpnext/stock/doctype/item_customer_detail/item_customer_detail.py
+++ b/erpnext/stock/doctype/item_customer_detail/item_customer_detail.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class ItemCustomerDetail(Document):
pass
diff --git a/erpnext/stock/doctype/item_default/item_default.py b/erpnext/stock/doctype/item_default/item_default.py
index 935f0ffb0ff..6239c540434 100644
--- a/erpnext/stock/doctype/item_default/item_default.py
+++ b/erpnext/stock/doctype/item_default/item_default.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class ItemDefault(Document):
pass
diff --git a/erpnext/stock/doctype/item_manufacturer/item_manufacturer.py b/erpnext/stock/doctype/item_manufacturer/item_manufacturer.py
index 939abf8d324..044ac7c2350 100644
--- a/erpnext/stock/doctype/item_manufacturer/item_manufacturer.py
+++ b/erpnext/stock/doctype/item_manufacturer/item_manufacturer.py
@@ -8,6 +8,7 @@ import frappe
from frappe import _
from frappe.model.document import Document
+
class ItemManufacturer(Document):
def validate(self):
self.validate_duplicate_entry()
diff --git a/erpnext/stock/doctype/item_manufacturer/test_item_manufacturer.py b/erpnext/stock/doctype/item_manufacturer/test_item_manufacturer.py
index 1cef20c4171..5a4ca6a44ad 100644
--- a/erpnext/stock/doctype/item_manufacturer/test_item_manufacturer.py
+++ b/erpnext/stock/doctype/item_manufacturer/test_item_manufacturer.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestItemManufacturer(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/item_price/item_price.py b/erpnext/stock/doctype/item_price/item_price.py
index e82a19b0dc0..3f0fc4136b0 100644
--- a/erpnext/stock/doctype/item_price/item_price.py
+++ b/erpnext/stock/doctype/item_price/item_price.py
@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
diff --git a/erpnext/stock/doctype/item_price/test_item_price.py b/erpnext/stock/doctype/item_price/test_item_price.py
index f3d406eeca6..5ed80921660 100644
--- a/erpnext/stock/doctype/item_price/test_item_price.py
+++ b/erpnext/stock/doctype/item_price/test_item_price.py
@@ -2,11 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import unittest
+
import frappe
from frappe.test_runner import make_test_records_for_doctype
-from erpnext.stock.get_item_details import get_price_list_rate_for, process_args
+
from erpnext.stock.doctype.item_price.item_price import ItemPriceDuplicateItem
+from erpnext.stock.get_item_details import get_price_list_rate_for, process_args
class TestItemPrice(unittest.TestCase):
diff --git a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.py b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.py
index 785737b267f..0dd7e431054 100644
--- a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.py
+++ b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class ItemQualityInspectionParameter(Document):
pass
diff --git a/erpnext/stock/doctype/item_reorder/item_reorder.py b/erpnext/stock/doctype/item_reorder/item_reorder.py
index 5cdaa229565..598339deee8 100644
--- a/erpnext/stock/doctype/item_reorder/item_reorder.py
+++ b/erpnext/stock/doctype/item_reorder/item_reorder.py
@@ -4,9 +4,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class ItemReorder(Document):
pass
diff --git a/erpnext/stock/doctype/item_supplier/item_supplier.py b/erpnext/stock/doctype/item_supplier/item_supplier.py
index 5dda535f810..9b5da55f600 100644
--- a/erpnext/stock/doctype/item_supplier/item_supplier.py
+++ b/erpnext/stock/doctype/item_supplier/item_supplier.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class ItemSupplier(Document):
pass
diff --git a/erpnext/stock/doctype/item_tax/item_tax.py b/erpnext/stock/doctype/item_tax/item_tax.py
index 7c9e8115758..33c1e49f409 100644
--- a/erpnext/stock/doctype/item_tax/item_tax.py
+++ b/erpnext/stock/doctype/item_tax/item_tax.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class ItemTax(Document):
pass
diff --git a/erpnext/stock/doctype/item_variant/item_variant.py b/erpnext/stock/doctype/item_variant/item_variant.py
index 5d5a022648a..47ab07fe98d 100644
--- a/erpnext/stock/doctype/item_variant/item_variant.py
+++ b/erpnext/stock/doctype/item_variant/item_variant.py
@@ -2,8 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ItemVariant(Document):
pass
diff --git a/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.py b/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.py
index d1a1eb54a5d..78dda6535fc 100644
--- a/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.py
+++ b/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ItemVariantAttribute(Document):
pass
diff --git a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js
index e8fb34732fc..cb9abc08e25 100644
--- a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js
+++ b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js
@@ -4,8 +4,8 @@
frappe.ui.form.on('Item Variant Settings', {
setup: function(frm) {
const allow_fields = [];
- const exclude_fields = ["naming_series", "item_code", "item_name", "show_in_website",
- "show_variant_in_website", "opening_stock", "variant_of", "valuation_rate"];
+ const exclude_fields = ["naming_series", "item_code", "item_name", "published_in_website",
+ "opening_stock", "variant_of", "valuation_rate"];
frappe.model.with_doctype('Item', () => {
frappe.get_meta('Item').fields.forEach(d => {
diff --git a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.py b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.py
index 78f1131b769..97db049f146 100644
--- a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.py
+++ b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.document import Document
from frappe import _
+from frappe.model.document import Document
+
class ItemVariantSettings(Document):
invalid_fields_for_copy_fields_in_variants = ['barcodes']
@@ -13,10 +15,9 @@ class ItemVariantSettings(Document):
def set_default_fields(self):
self.fields = []
fields = frappe.get_meta('Item').fields
- exclude_fields = {"naming_series", "item_code", "item_name", "show_in_website",
- "show_variant_in_website", "standard_rate", "opening_stock", "image", "description",
+ exclude_fields = {"naming_series", "item_code", "item_name", "published_in_website",
+ "standard_rate", "opening_stock", "image", "description",
"variant_of", "valuation_rate", "description", "barcodes",
- "website_image", "thumbnail", "website_specifiations", "web_long_description",
"has_variants", "attributes"}
for d in fields:
diff --git a/erpnext/stock/doctype/item_variant_settings/test_item_variant_settings.js b/erpnext/stock/doctype/item_variant_settings/test_item_variant_settings.js
deleted file mode 100644
index 3b3bf94f375..00000000000
--- a/erpnext/stock/doctype/item_variant_settings/test_item_variant_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Item Variant Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Item Variant Settings
- () => frappe.tests.make('Item Variant Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/item_variant_settings/test_item_variant_settings.py b/erpnext/stock/doctype/item_variant_settings/test_item_variant_settings.py
index 9a800c07fcb..040382a66f7 100644
--- a/erpnext/stock/doctype/item_variant_settings/test_item_variant_settings.py
+++ b/erpnext/stock/doctype/item_variant_settings/test_item_variant_settings.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestItemVariantSettings(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/item_website_specification/item_website_specification.py b/erpnext/stock/doctype/item_website_specification/item_website_specification.py
index e3041cf3eef..85491b73921 100644
--- a/erpnext/stock/doctype/item_website_specification/item_website_specification.py
+++ b/erpnext/stock/doctype/item_website_specification/item_website_specification.py
@@ -4,9 +4,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class ItemWebsiteSpecification(Document):
pass
diff --git a/erpnext/stock/doctype/landed_cost_item/landed_cost_item.py b/erpnext/stock/doctype/landed_cost_item/landed_cost_item.py
index 493e8b239a4..7dd3aa5c346 100644
--- a/erpnext/stock/doctype/landed_cost_item/landed_cost_item.py
+++ b/erpnext/stock/doctype/landed_cost_item/landed_cost_item.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class LandedCostItem(Document):
pass
diff --git a/erpnext/stock/doctype/landed_cost_purchase_receipt/landed_cost_purchase_receipt.py b/erpnext/stock/doctype/landed_cost_purchase_receipt/landed_cost_purchase_receipt.py
index 38f4eafc3aa..3d81d964111 100644
--- a/erpnext/stock/doctype/landed_cost_purchase_receipt/landed_cost_purchase_receipt.py
+++ b/erpnext/stock/doctype/landed_cost_purchase_receipt/landed_cost_purchase_receipt.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class LandedCostPurchaseReceipt(Document):
pass
diff --git a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.py b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.py
index 0dc396aefac..e649e4d0797 100644
--- a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.py
+++ b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.py
@@ -2,8 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class LandedCostTaxesandCharges(Document):
pass
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
index bf969f99f8e..51ccea982d9 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
@@ -2,14 +2,17 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+
+import frappe
from frappe import _
-from frappe.utils import flt
-from frappe.model.meta import get_field_precision
from frappe.model.document import Document
-from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
-from erpnext.accounts.doctype.account.account import get_account_currency
+from frappe.model.meta import get_field_precision
+from frappe.utils import flt
+
+import erpnext
from erpnext.controllers.taxes_and_totals import init_landed_taxes_and_totals
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+
class LandedCostVoucher(Document):
@frappe.whitelist()
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index cb09d933801..58a72f72dd1 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -3,15 +3,20 @@
from __future__ import unicode_literals
+
import unittest
+
import frappe
from frappe.utils import flt
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \
- import get_gl_entries, test_records as pr_test_records, make_purchase_receipt
+
+from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
-from erpnext.accounts.doctype.account.test_account import get_inventory_account
-from erpnext.accounts.doctype.account.test_account import create_account
from erpnext.assets.doctype.asset.test_asset import create_asset_category, create_fixed_asset_item
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import (
+ get_gl_entries,
+ make_purchase_receipt,
+)
+
class TestLandedCostVoucher(unittest.TestCase):
def test_landed_cost_voucher(self):
@@ -208,7 +213,10 @@ class TestLandedCostVoucher(unittest.TestCase):
self.assertEqual(pr.items[1].landed_cost_voucher_amount, 100)
def test_multi_currency_lcv(self):
- from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records, save_new_records
+ from erpnext.setup.doctype.currency_exchange.test_currency_exchange import (
+ save_new_records,
+ test_records,
+ )
save_new_records(test_records)
diff --git a/erpnext/stock/doctype/manufacturer/manufacturer.py b/erpnext/stock/doctype/manufacturer/manufacturer.py
index b624f73b773..314a2808045 100644
--- a/erpnext/stock/doctype/manufacturer/manufacturer.py
+++ b/erpnext/stock/doctype/manufacturer/manufacturer.py
@@ -3,10 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
+
+from frappe.contacts.address_and_contact import load_address_and_contact
from frappe.model.document import Document
+
class Manufacturer(Document):
def onload(self):
"""Load address and contacts in `__onload`"""
diff --git a/erpnext/stock/doctype/manufacturer/test_manufacturer.js b/erpnext/stock/doctype/manufacturer/test_manufacturer.js
deleted file mode 100644
index 0254a367ccb..00000000000
--- a/erpnext/stock/doctype/manufacturer/test_manufacturer.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Manufacturer", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially('Manufacturer', [
- // insert a new Manufacturer
- () => frappe.tests.make([
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/manufacturer/test_manufacturer.py b/erpnext/stock/doctype/manufacturer/test_manufacturer.py
index 996f6b27ca0..c0c61b00d0b 100644
--- a/erpnext/stock/doctype/manufacturer/test_manufacturer.py
+++ b/erpnext/stock/doctype/manufacturer/test_manufacturer.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Manufacturer')
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index 026b85e26d2..2569c04251c 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -5,19 +5,20 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
-from frappe.utils import cstr, flt, getdate, new_line_sep, nowdate, add_days, get_link_to_form
-from frappe import msgprint, _
+import frappe
+from frappe import _, msgprint
from frappe.model.mapper import get_mapped_doc
-from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty
+from frappe.utils import cstr, flt, get_link_to_form, getdate, new_line_sep, nowdate
+from six import string_types
+
+from erpnext.buying.utils import check_on_hold_or_closed_status, validate_for_items
from erpnext.controllers.buying_controller import BuyingController
from erpnext.manufacturing.doctype.work_order.work_order import get_item_details
-from erpnext.buying.utils import check_on_hold_or_closed_status, validate_for_items
from erpnext.stock.doctype.item.item import get_item_defaults
-
-from six import string_types
+from erpnext.stock.stock_balance import get_indented_qty, update_bin_qty
form_grid_templates = {
"items": "templates/form_grid/material_request_grid.html"
@@ -271,7 +272,10 @@ def update_status(name, status):
material_request.update_status(status)
@frappe.whitelist()
-def make_purchase_order(source_name, target_doc=None):
+def make_purchase_order(source_name, target_doc=None, args={}):
+
+ if isinstance(args, string_types):
+ args = json.loads(args)
def postprocess(source, target_doc):
if frappe.flags.args and frappe.flags.args.default_supplier:
@@ -286,7 +290,10 @@ def make_purchase_order(source_name, target_doc=None):
set_missing_values(source, target_doc)
def select_item(d):
- return d.ordered_qty < d.stock_qty
+ filtered_items = args.get('filtered_children', [])
+ child_filter = d.name in filtered_items if filtered_items else True
+
+ return d.ordered_qty < d.stock_qty and child_filter
doclist = get_mapped_doc("Material Request", source_name, {
"Material Request": {
diff --git a/erpnext/stock/doctype/material_request/material_request_dashboard.py b/erpnext/stock/doctype/material_request/material_request_dashboard.py
index e1e4faf6825..291cfb53c90 100644
--- a/erpnext/stock/doctype/material_request/material_request_dashboard.py
+++ b/erpnext/stock/doctype/material_request/material_request_dashboard.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
from frappe import _
diff --git a/erpnext/stock/doctype/material_request/test_material_request.js b/erpnext/stock/doctype/material_request/test_material_request.js
deleted file mode 100644
index 793cad0f3b6..00000000000
--- a/erpnext/stock/doctype/material_request/test_material_request.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Material Request", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially('Material Request', [
- // insert a new Material Request
- () => frappe.tests.make([
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py
index b4776ba2492..5c2ac2584f7 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -5,11 +5,20 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, unittest, erpnext
+
+import unittest
+
+import frappe
from frappe.utils import flt, today
-from erpnext.stock.doctype.material_request.material_request \
- import raise_work_orders, make_stock_entry, make_purchase_order, make_supplier_quotation
+
from erpnext.stock.doctype.item.test_item import create_item
+from erpnext.stock.doctype.material_request.material_request import (
+ make_purchase_order,
+ make_stock_entry,
+ make_supplier_quotation,
+ raise_work_orders,
+)
+
class TestMaterialRequest(unittest.TestCase):
def test_make_purchase_order(self):
diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.py b/erpnext/stock/doctype/material_request_item/material_request_item.py
index e0066e65d2c..0c98b97e57e 100644
--- a/erpnext/stock/doctype/material_request_item/material_request_item.py
+++ b/erpnext/stock/doctype/material_request_item/material_request_item.py
@@ -4,10 +4,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
from frappe.model.document import Document
+
class MaterialRequestItem(Document):
pass
diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json
index bb396e806f6..830d5469bf0 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.json
+++ b/erpnext/stock/doctype/packed_item/packed_item.json
@@ -16,6 +16,7 @@
"conversion_factor",
"column_break_9",
"qty",
+ "rate",
"uom",
"section_break_9",
"serial_no",
@@ -215,13 +216,23 @@
"fieldname": "conversion_factor",
"fieldtype": "Float",
"label": "Conversion Factor"
+ },
+ {
+ "fetch_from": "item_code.valuation_rate",
+ "fetch_if_empty": 1,
+ "fieldname": "rate",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Rate",
+ "print_hide": 1,
+ "read_only": 1
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-05-26 07:08:05.111385",
+ "modified": "2021-09-01 15:10:29.646399",
"modified_by": "Administrator",
"module": "Stock",
"name": "Packed Item",
diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py
index 4ab71bdf629..aec094b0cd5 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.py
+++ b/erpnext/stock/doctype/packed_item/packed_item.py
@@ -4,10 +4,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, json
-from frappe.utils import cstr, flt
-from erpnext.stock.get_item_details import get_item_details
+
+import json
+
+import frappe
from frappe.model.document import Document
+from frappe.utils import cstr, flt
+
+from erpnext.stock.get_item_details import get_item_details
+
class PackedItem(Document):
pass
@@ -86,6 +91,9 @@ def make_packing_list(doc):
cleanup_packing_list(doc, parent_items)
+ if frappe.db.get_single_value("Selling Settings", "editable_bundle_item_rates"):
+ update_product_bundle_price(doc, parent_items)
+
def cleanup_packing_list(doc, parent_items):
"""Remove all those child items which are no longer present in main item table"""
delete_list = []
@@ -103,6 +111,40 @@ def cleanup_packing_list(doc, parent_items):
if d not in delete_list:
doc.append("packed_items", d)
+def update_product_bundle_price(doc, parent_items):
+ """Updates the prices of Product Bundles based on the rates of the Items in the bundle."""
+
+ if not doc.get('items'):
+ return
+
+ parent_items_index = 0
+ bundle_price = 0
+
+ for bundle_item in doc.get("packed_items"):
+ if parent_items[parent_items_index][0] == bundle_item.parent_item:
+ bundle_item_rate = bundle_item.rate if bundle_item.rate else 0
+ bundle_price += bundle_item.qty * bundle_item_rate
+ else:
+ update_parent_item_price(doc, parent_items[parent_items_index][0], bundle_price)
+
+ bundle_price = 0
+ parent_items_index += 1
+
+ # for the last product bundle
+ if doc.get("packed_items"):
+ update_parent_item_price(doc, parent_items[parent_items_index][0], bundle_price)
+
+def update_parent_item_price(doc, parent_item_code, bundle_price):
+ parent_item_doc = doc.get('items', {'item_code': parent_item_code})[0]
+
+ current_parent_item_price = parent_item_doc.amount
+ if current_parent_item_price != bundle_price:
+ parent_item_doc.amount = bundle_price
+ update_parent_item_rate(parent_item_doc, bundle_price)
+
+def update_parent_item_rate(parent_item_doc, bundle_price):
+ parent_item_doc.rate = bundle_price/parent_item_doc.qty
+
@frappe.whitelist()
def get_items_from_product_bundle(args):
args = json.loads(args)
diff --git a/erpnext/stock/doctype/packing_slip/test_packing_slip.py b/erpnext/stock/doctype/packing_slip/test_packing_slip.py
index 1f2af02e209..193adfcf1cb 100644
--- a/erpnext/stock/doctype/packing_slip/test_packing_slip.py
+++ b/erpnext/stock/doctype/packing_slip/test_packing_slip.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Packing Slip')
diff --git a/erpnext/stock/doctype/packing_slip_item/packing_slip_item.py b/erpnext/stock/doctype/packing_slip_item/packing_slip_item.py
index b0a855961f9..8363968187b 100644
--- a/erpnext/stock/doctype/packing_slip_item/packing_slip_item.py
+++ b/erpnext/stock/doctype/packing_slip_item/packing_slip_item.py
@@ -4,9 +4,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class PackingSlipItem(Document):
pass
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 516ae43089b..dffbe80fa39 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -3,16 +3,21 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
-from six import iteritems
-from frappe.model.document import Document
-from frappe import _
from collections import OrderedDict
-from frappe.utils import floor, flt, today, cint
-from frappe.model.mapper import get_mapped_doc, map_child_doc
+
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from frappe.model.mapper import map_child_doc
+from frappe.utils import cint, floor, flt, today
+from six import iteritems
+
+from erpnext.selling.doctype.sales_order.sales_order import (
+ make_delivery_note as create_delivery_note_from_sales_order,
+)
from erpnext.stock.get_item_details import get_conversion_factor
-from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note as create_delivery_note_from_sales_order
# TODO: Prioritize SO or WO group warehouse
diff --git a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
index 7c321c450a6..50a767bafa7 100644
--- a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
+++ b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
@@ -1,5 +1,5 @@
from __future__ import unicode_literals
-from frappe import _
+
def get_data():
return {
diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py
index 84566b8d8c7..aa710ad0e97 100644
--- a/erpnext/stock/doctype/pick_list/test_pick_list.py
+++ b/erpnext/stock/doctype/pick_list/test_pick_list.py
@@ -3,15 +3,19 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
+
test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch']
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.pick_list.pick_list import create_delivery_note
-from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation \
- import EmptyStockReconciliationItemsError
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
+from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import (
+ EmptyStockReconciliationItemsError,
+)
+
class TestPickList(unittest.TestCase):
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.py b/erpnext/stock/doctype/pick_list_item/pick_list_item.py
index 8797b8dc219..4cd81f7f85b 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.py
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class PickListItem(Document):
pass
diff --git a/erpnext/stock/doctype/price_list/price_list.py b/erpnext/stock/doctype/price_list/price_list.py
index 002d3d898eb..1a5a7ba23ff 100644
--- a/erpnext/stock/doctype/price_list/price_list.py
+++ b/erpnext/stock/doctype/price_list/price_list.py
@@ -2,11 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _, throw
-from frappe.utils import cint
from frappe.model.document import Document
-import frappe.defaults
+from frappe.utils import cint
+
class PriceList(Document):
def validate(self):
@@ -36,12 +37,14 @@ class PriceList(Document):
(self.currency, cint(self.buying), cint(self.selling), self.name))
def check_impact_on_shopping_cart(self):
- "Check if Price List currency change impacts Shopping Cart."
- from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import validate_cart_settings
+ "Check if Price List currency change impacts E Commerce Cart."
+ from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import (
+ validate_cart_settings,
+ )
doc_before_save = self.get_doc_before_save()
currency_changed = self.currency != doc_before_save.currency
- affects_cart = self.name == frappe.get_cached_value("Shopping Cart Settings", None, "price_list")
+ affects_cart = self.name == frappe.get_cached_value("E Commerce Settings", None, "price_list")
if currency_changed and affects_cart:
validate_cart_settings()
diff --git a/erpnext/stock/doctype/price_list/test_price_list.js b/erpnext/stock/doctype/price_list/test_price_list.js
deleted file mode 100644
index fe4e07b3bdd..00000000000
--- a/erpnext/stock/doctype/price_list/test_price_list.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Price List", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Price List
- () => frappe.tests.make('Price List', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/price_list/test_price_list.py b/erpnext/stock/doctype/price_list/test_price_list.py
index 2c287c9033c..baf6170e850 100644
--- a/erpnext/stock/doctype/price_list/test_price_list.py
+++ b/erpnext/stock/doctype/price_list/test_price_list.py
@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
# test_ignore = ["Item"]
diff --git a/erpnext/stock/doctype/price_list_country/price_list_country.py b/erpnext/stock/doctype/price_list_country/price_list_country.py
index db1a0607e62..a57729fb2e4 100644
--- a/erpnext/stock/doctype/price_list_country/price_list_country.py
+++ b/erpnext/stock/doctype/price_list_country/price_list_country.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class PriceListCountry(Document):
pass
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 4a4514f2497..475ac2f06f0 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -2,21 +2,19 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-
-from frappe.utils import flt, cint, nowdate
-
-from frappe import throw, _
-import frappe.defaults
-from frappe.utils import getdate
-from erpnext.controllers.buying_controller import BuyingController
-from erpnext.accounts.utils import get_account_currency
+from frappe import _, throw
from frappe.desk.notifications import clear_doctype_notifications
from frappe.model.mapper import get_mapped_doc
-from erpnext.buying.utils import check_on_hold_or_closed_status
+from frappe.utils import cint, flt, getdate, nowdate
+from six import iteritems
+
+from erpnext.accounts.utils import get_account_currency
from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_enabled
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
-from six import iteritems
+from erpnext.buying.utils import check_on_hold_or_closed_status
+from erpnext.controllers.buying_controller import BuyingController
from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_transaction
form_grid_templates = {
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py
index 3832c827e27..b60850f2855 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'purchase_receipt_no',
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 0210702250e..c61304098f4 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -2,20 +2,22 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import unittest
+
import json
-import frappe, erpnext
-import frappe.defaults
-from frappe.utils import cint, flt, cstr, today, random_string, add_days
-from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice
-from erpnext.stock.doctype.item.test_item import create_item
-from erpnext.stock.doctype.serial_no.serial_no import SerialNoDuplicateError
-from erpnext.accounts.doctype.account.test_account import get_inventory_account
-from erpnext.stock.doctype.item.test_item import make_item
+import unittest
+
+import frappe
+from frappe.utils import add_days, cint, cstr, flt, today
from six import iteritems
-from erpnext.stock.stock_ledger import SerialNoExistsInFutureTransaction
+
+import erpnext
+from erpnext.accounts.doctype.account.test_account import get_inventory_account
+from erpnext.stock.doctype.item.test_item import create_item, make_item
+from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice
+from erpnext.stock.doctype.serial_no.serial_no import SerialNoDuplicateError, get_serial_nos
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
-from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+from erpnext.stock.stock_ledger import SerialNoExistsInFutureTransaction
+
class TestPurchaseReceipt(unittest.TestCase):
def setUp(self):
@@ -275,11 +277,16 @@ class TestPurchaseReceipt(unittest.TestCase):
receive more than the required qty in the PO.
Expected Result: Error Raised for Over Receipt against PO.
"""
+ from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt
+ from erpnext.buying.doctype.purchase_order.purchase_order import (
+ make_rm_stock_entry as make_subcontract_transfer_entry,
+ )
+ from erpnext.buying.doctype.purchase_order.test_purchase_order import (
+ create_purchase_order,
+ make_subcontracted_item,
+ update_backflush_based_on,
+ )
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
- from erpnext.buying.doctype.purchase_order.test_purchase_order import (update_backflush_based_on,
- make_subcontracted_item, create_purchase_order)
- from erpnext.buying.doctype.purchase_order.purchase_order import (make_purchase_receipt,
- make_rm_stock_entry as make_subcontract_transfer_entry)
update_backflush_based_on("Material Transferred for Subcontract")
item_code = "_Test Subcontracted FG Item 1"
@@ -526,7 +533,9 @@ class TestPurchaseReceipt(unittest.TestCase):
pr.cancel()
def test_closed_purchase_receipt(self):
- from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_purchase_receipt_status
+ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
+ update_purchase_receipt_status,
+ )
pr = make_purchase_receipt(do_not_submit=True)
pr.submit()
@@ -539,9 +548,11 @@ class TestPurchaseReceipt(unittest.TestCase):
def test_pr_billing_status(self):
# PO -> PR1 -> PI and PO -> PI and PO -> PR2
+ from erpnext.buying.doctype.purchase_order.purchase_order import (
+ make_purchase_invoice as make_purchase_invoice_from_po,
+ )
+ from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
- from erpnext.buying.doctype.purchase_order.purchase_order \
- import make_purchase_receipt, make_purchase_invoice as make_purchase_invoice_from_po
po = create_purchase_order()
@@ -748,7 +759,10 @@ class TestPurchaseReceipt(unittest.TestCase):
pr.cancel()
def test_make_purchase_invoice_from_pr_for_returned_qty(self):
- from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order, create_pr_against_po
+ from erpnext.buying.doctype.purchase_order.test_purchase_order import (
+ create_pr_against_po,
+ create_purchase_order,
+ )
po = create_purchase_order()
pr = create_pr_against_po(po.name)
@@ -879,10 +893,15 @@ class TestPurchaseReceipt(unittest.TestCase):
def test_subcontracted_pr_for_multi_transfer_batches(self):
+ from erpnext.buying.doctype.purchase_order.purchase_order import (
+ make_purchase_receipt,
+ make_rm_stock_entry,
+ )
+ from erpnext.buying.doctype.purchase_order.test_purchase_order import (
+ create_purchase_order,
+ update_backflush_based_on,
+ )
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
- from erpnext.buying.doctype.purchase_order.purchase_order import make_rm_stock_entry, make_purchase_receipt
- from erpnext.buying.doctype.purchase_order.test_purchase_order import (update_backflush_based_on,
- create_purchase_order)
update_backflush_based_on("Material Transferred for Subcontract")
item_code = "_Test Subcontracted FG Item 3"
@@ -952,8 +971,7 @@ class TestPurchaseReceipt(unittest.TestCase):
- Create PI from PO and submit
- Create PR from PO and submit
"""
- from erpnext.buying.doctype.purchase_order import test_purchase_order
- from erpnext.buying.doctype.purchase_order import purchase_order
+ from erpnext.buying.doctype.purchase_order import purchase_order, test_purchase_order
po = test_purchase_order.create_purchase_order()
@@ -974,8 +992,7 @@ class TestPurchaseReceipt(unittest.TestCase):
- Create partial PI from PO and submit
- Create PR from PO and submit
"""
- from erpnext.buying.doctype.purchase_order import test_purchase_order
- from erpnext.buying.doctype.purchase_order import purchase_order
+ from erpnext.buying.doctype.purchase_order import purchase_order, test_purchase_order
po = test_purchase_order.create_purchase_order()
@@ -1038,10 +1055,18 @@ class TestPurchaseReceipt(unittest.TestCase):
frappe.db.set_value('Company', company, 'enable_perpetual_inventory_for_non_stock_items', before_test_value)
def test_payment_terms_are_fetched_when_creating_purchase_invoice(self):
- from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
+ from erpnext.accounts.doctype.payment_entry.test_payment_entry import (
+ create_payment_terms_template,
+ )
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
- from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order, make_pr_against_po
- from erpnext.selling.doctype.sales_order.test_sales_order import automatically_fetch_payment_terms, compare_payment_schedules
+ from erpnext.buying.doctype.purchase_order.test_purchase_order import (
+ create_purchase_order,
+ make_pr_against_po,
+ )
+ from erpnext.selling.doctype.sales_order.test_sales_order import (
+ automatically_fetch_payment_terms,
+ compare_payment_schedules,
+ )
automatically_fetch_payment_terms()
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index 82cc98e7f75..3efa66e02ed 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -10,6 +10,7 @@
"barcode",
"section_break_2",
"item_code",
+ "product_bundle",
"supplier_part_no",
"column_break_2",
"item_name",
@@ -956,12 +957,19 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "product_bundle",
+ "fieldtype": "Link",
+ "label": "Product Bundle",
+ "options": "Product Bundle",
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2021-03-29 04:17:00.336298",
+ "modified": "2021-09-01 16:02:40.338597",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py
index b79bb5d0430..2d25140d2b6 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class PurchaseReceiptItem(Document):
pass
diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule.py b/erpnext/stock/doctype/putaway_rule/putaway_rule.py
index 315e723fabc..aa9d8968063 100644
--- a/erpnext/stock/doctype/putaway_rule/putaway_rule.py
+++ b/erpnext/stock/doctype/putaway_rule/putaway_rule.py
@@ -3,16 +3,20 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import copy
import json
from collections import defaultdict
-from six import string_types
+
+import frappe
from frappe import _
-from frappe.utils import flt, floor, nowdate, cint
from frappe.model.document import Document
-from erpnext.stock.utils import get_stock_balance
+from frappe.utils import cint, floor, flt, nowdate
+from six import string_types
+
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+from erpnext.stock.utils import get_stock_balance
+
class PutawayRule(Document):
def validate(self):
diff --git a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
index 0590ae1abeb..0aa7610575e 100644
--- a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
+++ b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
@@ -2,14 +2,18 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
-import frappe
+
import unittest
-from erpnext.stock.doctype.item.test_item import make_item
-from erpnext.stock.get_item_details import get_conversion_factor
-from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
-from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+
+import frappe
+
from erpnext.stock.doctype.batch.test_batch import make_new_batch
+from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
+from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
+from erpnext.stock.get_item_details import get_conversion_factor
+
class TestPutawayRule(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
index 469511af60b..8b2f8da9dfd 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
@@ -2,13 +2,17 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+from frappe import _
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
-from frappe import _
-from frappe.utils import flt, cint
-from erpnext.stock.doctype.quality_inspection_template.quality_inspection_template \
- import get_template_details
+from frappe.utils import cint, flt
+
+from erpnext.stock.doctype.quality_inspection_template.quality_inspection_template import (
+ get_template_details,
+)
+
class QualityInspection(Document):
def validate(self):
diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.js b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.js
deleted file mode 100644
index 327484e6cc3..00000000000
--- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Quality Inspection", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Quality Inspection
- () => frappe.tests.make('Quality Inspection', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.py b/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.py
index 86784221a0c..fa682012e59 100644
--- a/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.py
+++ b/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityInspectionParameter(Document):
pass
diff --git a/erpnext/stock/doctype/quality_inspection_parameter/test_quality_inspection_parameter.py b/erpnext/stock/doctype/quality_inspection_parameter/test_quality_inspection_parameter.py
index cefdc0867b1..f3041aa863d 100644
--- a/erpnext/stock/doctype/quality_inspection_parameter/test_quality_inspection_parameter.py
+++ b/erpnext/stock/doctype/quality_inspection_parameter/test_quality_inspection_parameter.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestQualityInspectionParameter(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.py b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.py
index 1a3b1a04639..b5e28f3ec9d 100644
--- a/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.py
+++ b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityInspectionParameterGroup(Document):
pass
diff --git a/erpnext/stock/doctype/quality_inspection_parameter_group/test_quality_inspection_parameter_group.py b/erpnext/stock/doctype/quality_inspection_parameter_group/test_quality_inspection_parameter_group.py
index 212d4b8c21b..ded47e8ca80 100644
--- a/erpnext/stock/doctype/quality_inspection_parameter_group/test_quality_inspection_parameter_group.py
+++ b/erpnext/stock/doctype/quality_inspection_parameter_group/test_quality_inspection_parameter_group.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestQualityInspectionParameterGroup(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.py b/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.py
index b10fa310d66..7b56603321a 100644
--- a/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.py
+++ b/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class QualityInspectionReading(Document):
pass
diff --git a/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py
index 971b3c29825..50e28a6361f 100644
--- a/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py
+++ b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class QualityInspectionTemplate(Document):
pass
diff --git a/erpnext/stock/doctype/quality_inspection_template/test_quality_inspection_template.js b/erpnext/stock/doctype/quality_inspection_template/test_quality_inspection_template.js
deleted file mode 100644
index 879c262ed2a..00000000000
--- a/erpnext/stock/doctype/quality_inspection_template/test_quality_inspection_template.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Quality Inspection Template", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Quality Inspection Template
- () => frappe.tests.make('Quality Inspection Template', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/quality_inspection_template/test_quality_inspection_template.py b/erpnext/stock/doctype/quality_inspection_template/test_quality_inspection_template.py
index b16efa839db..6286523c861 100644
--- a/erpnext/stock/doctype/quality_inspection_template/test_quality_inspection_template.py
+++ b/erpnext/stock/doctype/quality_inspection_template/test_quality_inspection_template.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestQualityInspectionTemplate(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/quick_stock_balance/quick_stock_balance.py b/erpnext/stock/doctype/quick_stock_balance/quick_stock_balance.py
index efa951940ea..8ca5521de02 100644
--- a/erpnext/stock/doctype/quick_stock_balance/quick_stock_balance.py
+++ b/erpnext/stock/doctype/quick_stock_balance/quick_stock_balance.py
@@ -3,11 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.model.document import Document
+
from erpnext.stock.utils import get_stock_balance, get_stock_value_on
+
class QuickStockBalance(Document):
pass
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index 2e454a51596..5f97798974c 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -3,14 +3,22 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-from rq.timeouts import JobTimeoutException
-from frappe.model.document import Document
-from frappe.utils import cint, get_link_to_form, add_to_date, now, today, time_diff_in_hours
-from erpnext.stock.stock_ledger import repost_future_sle
-from erpnext.accounts.utils import update_gl_entries_after, check_if_stock_and_account_balance_synced
-from frappe.utils.user import get_users_with_role
+
+import frappe
from frappe import _
+from frappe.model.document import Document
+from frappe.utils import cint, get_link_to_form, now, today
+from frappe.utils.user import get_users_with_role
+from rq.timeouts import JobTimeoutException
+
+import erpnext
+from erpnext.accounts.utils import (
+ check_if_stock_and_account_balance_synced,
+ update_gl_entries_after,
+)
+from erpnext.stock.stock_ledger import repost_future_sle
+
+
class RepostItemValuation(Document):
def validate(self):
self.set_status()
diff --git a/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
index 13ceb68669c..c70a9ec7a8b 100644
--- a/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestRepostItemValuation(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index 70312bc543b..82d8aaed5b3 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -2,19 +2,20 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import json
+import frappe
+from frappe import ValidationError, _
from frappe.model.naming import make_autoname
-from frappe.utils import cint, cstr, flt, add_days, nowdate, getdate, get_link_to_form
-from erpnext.stock.get_item_details import get_reserved_qty_for_so
-
-from frappe import _, ValidationError
-
-from erpnext.controllers.stock_controller import StockController
+from frappe.utils import add_days, cint, cstr, flt, get_link_to_form, getdate, nowdate
from six import string_types
from six.moves import map
+from erpnext.controllers.stock_controller import StockController
+from erpnext.stock.get_item_details import get_reserved_qty_for_so
+
+
class SerialNoCannotCreateDirectError(ValidationError): pass
class SerialNoCannotCannotChangeError(ValidationError): pass
class SerialNoNotRequiredError(ValidationError): pass
@@ -573,7 +574,7 @@ def auto_fetch_serial_number(qty, item_code, warehouse, posting_date=None, batch
if batch_nos:
try:
filters["batch_no"] = json.loads(batch_nos) if (type(json.loads(batch_nos)) == list) else [json.loads(batch_nos)]
- except:
+ except Exception:
filters["batch_no"] = [batch_nos]
if posting_date:
diff --git a/erpnext/stock/doctype/serial_no/test_serial_no.js b/erpnext/stock/doctype/serial_no/test_serial_no.js
deleted file mode 100644
index bf8293257c3..00000000000
--- a/erpnext/stock/doctype/serial_no/test_serial_no.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Serial No", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Serial No
- () => frappe.tests.make('Serial No', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/serial_no/test_serial_no.py b/erpnext/stock/doctype/serial_no/test_serial_no.py
index 0eccce3a58e..818c163c681 100644
--- a/erpnext/stock/doctype/serial_no/test_serial_no.py
+++ b/erpnext/stock/doctype/serial_no/test_serial_no.py
@@ -5,12 +5,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, unittest
-from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
+import unittest
+
+import frappe
+
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
test_dependencies = ["Item"]
@@ -18,6 +21,7 @@ test_records = frappe.get_test_records('Serial No')
from erpnext.stock.doctype.serial_no.serial_no import *
+
class TestSerialNo(unittest.TestCase):
def test_cannot_create_direct(self):
frappe.delete_doc_if_exists("Serial No", "_TCSER0001")
diff --git a/erpnext/stock/doctype/shipment/shipment.py b/erpnext/stock/doctype/shipment/shipment.py
index 01fcee4cac2..2cacd0dfab4 100644
--- a/erpnext/stock/doctype/shipment/shipment.py
+++ b/erpnext/stock/doctype/shipment/shipment.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt, get_time
-from frappe.model.document import Document
-from erpnext.accounts.party import get_party_shipping_address
from frappe.contacts.doctype.contact.contact import get_default_contact
+from frappe.model.document import Document
+from frappe.utils import flt, get_time
+
+from erpnext.accounts.party import get_party_shipping_address
+
class Shipment(Document):
def validate(self):
diff --git a/erpnext/stock/doctype/shipment/test_shipment.py b/erpnext/stock/doctype/shipment/test_shipment.py
index db2f1161743..9914cf80158 100644
--- a/erpnext/stock/doctype/shipment/test_shipment.py
+++ b/erpnext/stock/doctype/shipment/test_shipment.py
@@ -2,12 +2,15 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
+
+import unittest
from datetime import date, timedelta
import frappe
-import unittest
+
from erpnext.stock.doctype.delivery_note.delivery_note import make_shipment
+
class TestShipment(unittest.TestCase):
def test_shipment_from_delivery_note(self):
delivery_note = create_test_delivery_note()
diff --git a/erpnext/stock/doctype/shipment_delivery_note/shipment_delivery_note.py b/erpnext/stock/doctype/shipment_delivery_note/shipment_delivery_note.py
index 43421516057..795c952bcdd 100644
--- a/erpnext/stock/doctype/shipment_delivery_note/shipment_delivery_note.py
+++ b/erpnext/stock/doctype/shipment_delivery_note/shipment_delivery_note.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ShipmentDeliveryNote(Document):
pass
diff --git a/erpnext/stock/doctype/shipment_parcel/shipment_parcel.py b/erpnext/stock/doctype/shipment_parcel/shipment_parcel.py
index 53e6ed55dd3..69fecb6e5ce 100644
--- a/erpnext/stock/doctype/shipment_parcel/shipment_parcel.py
+++ b/erpnext/stock/doctype/shipment_parcel/shipment_parcel.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ShipmentParcel(Document):
pass
diff --git a/erpnext/stock/doctype/shipment_parcel_template/shipment_parcel_template.py b/erpnext/stock/doctype/shipment_parcel_template/shipment_parcel_template.py
index 2a8d58d8305..0eaa2d3d5b8 100644
--- a/erpnext/stock/doctype/shipment_parcel_template/shipment_parcel_template.py
+++ b/erpnext/stock/doctype/shipment_parcel_template/shipment_parcel_template.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ShipmentParcelTemplate(Document):
pass
diff --git a/erpnext/stock/doctype/shipment_parcel_template/test_shipment_parcel_template.py b/erpnext/stock/doctype/shipment_parcel_template/test_shipment_parcel_template.py
index 6e2caa768bf..5f2a3993353 100644
--- a/erpnext/stock/doctype/shipment_parcel_template/test_shipment_parcel_template.py
+++ b/erpnext/stock/doctype/shipment_parcel_template/test_shipment_parcel_template.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestShipmentParcelTemplate(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index efbc12ce841..350af2b6004 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -278,7 +278,7 @@ frappe.ui.form.on('Stock Entry', {
get_query_filters: {
docstatus: 1,
material_request_type: ["in", allowed_request_types],
- status: ["not in", ["Transferred", "Issued"]]
+ status: ["not in", ["Transferred", "Issued", "Cancelled", "Stopped"]]
}
})
}, __("Get Items From"));
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index ba7c6d11337..2b9bb712171 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -2,27 +2,40 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-import frappe.defaults
+
+import json
+from collections import defaultdict
+
+import frappe
from frappe import _
-from frappe.utils import cstr, cint, flt, comma_or, getdate, nowdate, formatdate, format_time
-from erpnext.stock.utils import get_incoming_rate
-from erpnext.stock.stock_ledger import get_previous_sle, NegativeStockError, get_valuation_rate
-from erpnext.stock.get_item_details import get_bin_details, get_default_cost_center, get_conversion_factor, get_reserved_qty_for_so
-from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
-from erpnext.setup.doctype.brand.brand import get_brand_defaults
-from erpnext.stock.doctype.batch.batch import get_batch_no, set_batch_nos, get_batch_qty
-from erpnext.stock.doctype.item.item import get_item_defaults
-from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, add_additional_cost
-from erpnext.stock.utils import get_bin
from frappe.model.mapper import get_mapped_doc
-from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit, get_serial_nos
-from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import OpeningEntryAccountError
+from frappe.utils import cint, comma_or, cstr, flt, format_time, formatdate, getdate, nowdate
+from six import iteritems, itervalues, string_types
+
+import erpnext
from erpnext.accounts.general_ledger import process_gl_map
from erpnext.controllers.taxes_and_totals import init_landed_taxes_and_totals
-import json
+from erpnext.manufacturing.doctype.bom.bom import add_additional_cost, validate_bom_no
+from erpnext.setup.doctype.brand.brand import get_brand_defaults
+from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
+from erpnext.stock.doctype.batch.batch import get_batch_no, get_batch_qty, set_batch_nos
+from erpnext.stock.doctype.item.item import get_item_defaults
+from erpnext.stock.doctype.serial_no.serial_no import (
+ get_serial_nos,
+ update_serial_nos_after_submit,
+)
+from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import (
+ OpeningEntryAccountError,
+)
+from erpnext.stock.get_item_details import (
+ get_bin_details,
+ get_conversion_factor,
+ get_default_cost_center,
+ get_reserved_qty_for_so,
+)
+from erpnext.stock.stock_ledger import NegativeStockError, get_previous_sle, get_valuation_rate
+from erpnext.stock.utils import get_bin, get_incoming_rate
-from six import string_types, itervalues, iteritems
class IncorrectValuationRateError(frappe.ValidationError): pass
class DuplicateEntryForWorkOrderError(frappe.ValidationError): pass
@@ -672,7 +685,7 @@ class StockEntry(StockController):
def validate_bom(self):
for d in self.get('items'):
- if d.bom_no and (d.t_warehouse != getattr(self, "pro_doc", frappe._dict()).scrap_warehouse):
+ if d.bom_no and d.is_finished_item:
item_code = d.original_item or d.item_code
validate_bom_no(item_code, d.bom_no)
@@ -1179,13 +1192,88 @@ class StockEntry(StockController):
# item dict = { item_code: {qty, description, stock_uom} }
item_dict = get_bom_items_as_dict(self.bom_no, self.company, qty=qty,
- fetch_exploded = 0, fetch_scrap_items = 1)
+ fetch_exploded = 0, fetch_scrap_items = 1) or {}
for item in itervalues(item_dict):
item.from_warehouse = ""
item.is_scrap_item = 1
+
+ for row in self.get_scrap_items_from_job_card():
+ if row.stock_qty <= 0:
+ continue
+
+ item_row = item_dict.get(row.item_code)
+ if not item_row:
+ item_row = frappe._dict({})
+
+ item_row.update({
+ 'uom': row.stock_uom,
+ 'from_warehouse': '',
+ 'qty': row.stock_qty + flt(item_row.stock_qty),
+ 'converison_factor': 1,
+ 'is_scrap_item': 1,
+ 'item_name': row.item_name,
+ 'description': row.description,
+ 'allow_zero_valuation_rate': 1
+ })
+
+ item_dict[row.item_code] = item_row
+
return item_dict
+ def get_scrap_items_from_job_card(self):
+ if not self.pro_doc:
+ self.set_work_order_details()
+
+ scrap_items = frappe.db.sql('''
+ SELECT
+ JCSI.item_code, JCSI.item_name, SUM(JCSI.stock_qty) as stock_qty, JCSI.stock_uom, JCSI.description
+ FROM
+ `tabJob Card` JC, `tabJob Card Scrap Item` JCSI
+ WHERE
+ JCSI.parent = JC.name AND JC.docstatus = 1
+ AND JCSI.item_code IS NOT NULL AND JC.work_order = %s
+ GROUP BY
+ JCSI.item_code
+ ''', self.work_order, as_dict=1)
+
+ pending_qty = flt(self.pro_doc.qty) - flt(self.pro_doc.produced_qty)
+ if pending_qty <=0:
+ return []
+
+ used_scrap_items = self.get_used_scrap_items()
+ for row in scrap_items:
+ row.stock_qty -= flt(used_scrap_items.get(row.item_code))
+ row.stock_qty = (row.stock_qty) * flt(self.fg_completed_qty) / flt(pending_qty)
+
+ if used_scrap_items.get(row.item_code):
+ used_scrap_items[row.item_code] -= row.stock_qty
+
+ if cint(frappe.get_cached_value('UOM', row.stock_uom, 'must_be_whole_number')):
+ row.stock_qty = frappe.utils.ceil(row.stock_qty)
+
+ return scrap_items
+
+ def get_used_scrap_items(self):
+ used_scrap_items = defaultdict(float)
+ data = frappe.get_all(
+ 'Stock Entry',
+ fields = [
+ '`tabStock Entry Detail`.`item_code`', '`tabStock Entry Detail`.`qty`'
+ ],
+ filters = [
+ ['Stock Entry', 'work_order', '=', self.work_order],
+ ['Stock Entry Detail', 'is_scrap_item', '=', 1],
+ ['Stock Entry', 'docstatus', '=', 1],
+ ['Stock Entry', 'purpose', 'in', ['Repack', 'Manufacture']]
+ ]
+ )
+
+ for row in data:
+ used_scrap_items[row.item_code] += row.qty
+
+ return used_scrap_items
+
def get_unconsumed_raw_materials(self):
wo = frappe.get_doc("Work Order", self.work_order)
wo_items = frappe.get_all('Work Order Item',
@@ -1200,10 +1288,10 @@ class StockEntry(StockController):
wo_item_qty = item.transferred_qty or item.required_qty
- req_qty_each = (
- (flt(wo_item_qty) - flt(item.consumed_qty)) /
- (flt(work_order_qty) - flt(wo.produced_qty))
- )
+ wo_qty_consumed = flt(wo_item_qty) - flt(item.consumed_qty)
+ wo_qty_to_produce = flt(work_order_qty) - flt(wo.produced_qty)
+
+ req_qty_each = (wo_qty_consumed) / (wo_qty_to_produce or 1)
qty = req_qty_each * flt(self.fg_completed_qty)
@@ -1252,9 +1340,9 @@ class StockEntry(StockController):
po_qty = frappe.db.sql("""select qty, produced_qty, material_transferred_for_manufacturing from
`tabWork Order` where name=%s""", self.work_order, as_dict=1)[0]
- manufacturing_qty = flt(po_qty.qty)
+ manufacturing_qty = flt(po_qty.qty) or 1
produced_qty = flt(po_qty.produced_qty)
- trans_qty = flt(po_qty.material_transferred_for_manufacturing)
+ trans_qty = flt(po_qty.material_transferred_for_manufacturing) or 1
for item in transferred_materials:
qty= item.qty
@@ -1405,8 +1493,8 @@ class StockEntry(StockController):
se_child.is_scrap_item = item_dict[d].get("is_scrap_item", 0)
se_child.is_process_loss = item_dict[d].get("is_process_loss", 0)
- for field in ["idx", "po_detail", "original_item",
- "expense_account", "description", "item_name", "serial_no", "batch_no"]:
+ for field in ["idx", "po_detail", "original_item", "expense_account",
+ "description", "item_name", "serial_no", "batch_no", "allow_zero_valuation_rate"]:
if item_dict[d].get(field):
se_child.set(field, item_dict[d].get(field))
@@ -1491,7 +1579,8 @@ class StockEntry(StockController):
qty_to_reserve -= reserved_qty[0][0]
if qty_to_reserve > 0:
for item in self.items:
- if item.item_code == item_code:
+ has_serial_no = frappe.get_cached_value("Item", item.item_code, "has_serial_no")
+ if item.item_code == item_code and has_serial_no:
serial_nos = (item.serial_no).split("\n")
for serial_no in serial_nos:
if qty_to_reserve > 0:
@@ -1582,7 +1671,7 @@ class StockEntry(StockController):
if material_request and material_request not in material_requests:
material_requests.append(material_request)
frappe.db.set_value('Material Request', material_request, 'transfer_status', status)
-
+
def update_items_for_process_loss(self):
process_loss_dict = {}
for d in self.get("items"):
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
index 563fcb03973..f54dc4604ed 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
@@ -2,11 +2,14 @@
# See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-from frappe.utils import cint, flt
+import frappe
+from frappe.utils import cint, flt
from six import string_types
+import erpnext
+
+
@frappe.whitelist()
def make_stock_entry(**args):
'''Helper function to make a Stock Entry
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index a0e70516d4b..46619eb1f35 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -2,21 +2,33 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, unittest
-import frappe.defaults
-from frappe.utils import flt, nowdate, nowtime
-from erpnext.stock.doctype.serial_no.serial_no import *
-from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError
-from erpnext.stock.stock_ledger import get_previous_sle
+
+import unittest
+
+import frappe
from frappe.permissions import add_user_permission, remove_user_permission
-from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
-from erpnext.stock.doctype.item.test_item import set_item_variant_settings, make_item_variant, create_item
-from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
-from erpnext.accounts.doctype.account.test_account import get_inventory_account
-from erpnext.stock.doctype.stock_entry.stock_entry import move_sample_to_retention_warehouse, make_stock_in_entry
-from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import OpeningEntryAccountError
+from frappe.utils import flt, nowdate, nowtime
from six import iteritems
+from erpnext.accounts.doctype.account.test_account import get_inventory_account
+from erpnext.stock.doctype.item.test_item import (
+ create_item,
+ make_item_variant,
+ set_item_variant_settings,
+)
+from erpnext.stock.doctype.serial_no.serial_no import * # noqa
+from erpnext.stock.doctype.stock_entry.stock_entry import move_sample_to_retention_warehouse
+from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError
+from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import (
+ OpeningEntryAccountError,
+)
+from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
+ create_stock_reconciliation,
+)
+from erpnext.stock.stock_ledger import get_previous_sle
+
+
def get_sle(**args):
condition, values = "", []
for key, value in iteritems(args):
@@ -539,8 +551,9 @@ class TestStockEntry(unittest.TestCase):
frappe.db.set_value("Stock Settings", None, "stock_frozen_upto_days", 0)
def test_work_order(self):
- from erpnext.manufacturing.doctype.work_order.work_order \
- import make_stock_entry as _make_stock_entry
+ from erpnext.manufacturing.doctype.work_order.work_order import (
+ make_stock_entry as _make_stock_entry,
+ )
bom_no, bom_operation_cost = frappe.db.get_value("BOM", {"item": "_Test FG Item 2",
"is_default": 1, "docstatus": 1}, ["name", "operating_cost"])
@@ -618,8 +631,8 @@ class TestStockEntry(unittest.TestCase):
s2.cancel()
def test_retain_sample(self):
- from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.doctype.batch.batch import get_batch_qty
+ from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
create_warehouse("Test Warehouse for Sample Retention")
frappe.db.set_value("Stock Settings", None, "sample_retention_warehouse", "Test Warehouse for Sample Retention - _TC")
diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py
index a5623fded23..6c03425a9e2 100644
--- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py
+++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class StockEntryDetail(Document):
pass
diff --git a/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py b/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py
index 1069ec8713e..3d6e26409e1 100644
--- a/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py
+++ b/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class StockEntryType(Document):
def validate(self):
if self.add_to_transit and self.purpose != 'Material Transfer':
diff --git a/erpnext/stock/doctype/stock_entry_type/test_stock_entry_type.py b/erpnext/stock/doctype/stock_entry_type/test_stock_entry_type.py
index 4fa73fd2dca..7eea8f5c35c 100644
--- a/erpnext/stock/doctype/stock_entry_type/test_stock_entry_type.py
+++ b/erpnext/stock/doctype/stock_entry_type/test_stock_entry_type.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestStockEntryType(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index be1f00e37fa..caa1d42b662 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -3,14 +3,18 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
+from datetime import date
+
import frappe
from frappe import _
-from frappe.utils import flt, getdate, add_days, formatdate, get_datetime, cint
-from frappe.model.document import Document
-from datetime import date
-from erpnext.controllers.item_variant import ItemTemplateCannotHaveStock
-from erpnext.accounts.utils import get_fiscal_year
from frappe.core.doctype.role.role import get_users
+from frappe.model.document import Document
+from frappe.utils import add_days, cint, flt, formatdate, get_datetime, getdate
+
+from erpnext.accounts.utils import get_fiscal_year
+from erpnext.controllers.item_variant import ItemTemplateCannotHaveStock
+
class StockFreezeError(frappe.ValidationError): pass
class BackDatedStockTransaction(frappe.ValidationError): pass
@@ -27,7 +31,7 @@ class StockLedgerEntry(Document):
def validate(self):
self.flags.ignore_submit_comment = True
- from erpnext.stock.utils import validate_warehouse_company, validate_disabled_warehouse
+ from erpnext.stock.utils import validate_disabled_warehouse, validate_warehouse_company
self.validate_mandatory()
self.validate_item()
self.validate_batch()
diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
index af2ada8c9a4..61bae49b0bd 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
@@ -3,19 +3,25 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from frappe.utils import today, add_days
-from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
-from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation \
- import create_stock_reconciliation
-from erpnext.stock.doctype.item.test_item import make_item
-from erpnext.stock.stock_ledger import get_previous_sle
-from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
-from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import create_landed_cost_voucher
-from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
-from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import BackDatedStockTransaction
+
+import frappe
from frappe.core.page.permission_manager.permission_manager import reset
+from frappe.utils import add_days, today
+
+from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+from erpnext.stock.doctype.item.test_item import make_item
+from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import (
+ create_landed_cost_voucher,
+)
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
+from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import BackDatedStockTransaction
+from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
+ create_stock_reconciliation,
+)
+from erpnext.stock.stock_ledger import get_previous_sle
+
class TestStockLedgerEntry(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 4531652a13c..f2c1b9a5153 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -2,15 +2,18 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-import frappe.defaults
-from frappe import msgprint, _
-from frappe.utils import cstr, flt, cint
-from erpnext.controllers.stock_controller import StockController
+
+import frappe
+from frappe import _, msgprint
+from frappe.utils import cint, cstr, flt
+
+import erpnext
from erpnext.accounts.utils import get_company_default
-from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
-from erpnext.stock.utils import get_stock_balance, get_incoming_rate, get_available_serial_nos
+from erpnext.controllers.stock_controller import StockController
from erpnext.stock.doctype.batch.batch import get_batch_qty
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+from erpnext.stock.utils import get_stock_balance
+
class OpeningEntryAccountError(frappe.ValidationError): pass
class EmptyStockReconciliationItemsError(frappe.ValidationError): pass
@@ -159,8 +162,11 @@ class StockReconciliation(StockController):
raise frappe.ValidationError(self.validation_messages)
def validate_item(self, item_code, row):
- from erpnext.stock.doctype.item.item import validate_end_of_life, \
- validate_is_stock_item, validate_cancelled_item
+ from erpnext.stock.doctype.item.item import (
+ validate_cancelled_item,
+ validate_end_of_life,
+ validate_is_stock_item,
+ )
# using try except to catch all validation msgs and display together
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index e4381271ed2..8647bee40ec 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -5,16 +5,23 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, unittest
-from frappe.utils import flt, nowdate, nowtime, random_string, add_days
+
+import unittest
+
+import frappe
+from frappe.utils import add_days, flt, nowdate, nowtime, random_string
+
from erpnext.accounts.utils import get_stock_and_account_balance
-from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after
-from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import EmptyStockReconciliationItemsError, get_items
-from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.doctype.item.test_item import create_item
-from erpnext.stock.utils import get_incoming_rate, get_stock_value_on, get_valuation_method
-from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import (
+ EmptyStockReconciliationItemsError,
+ get_items,
+)
+from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
+from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after
+from erpnext.stock.utils import get_incoming_rate, get_stock_value_on, get_valuation_method
from erpnext.tests.utils import change_settings
@@ -322,8 +329,8 @@ class TestStockReconciliation(unittest.TestCase):
SR3 | Reco | 0 | 1 (posting date: today-1) [backdated & blocked]
DN2 | DN | -2 | 8(-1) (posting date: today)
"""
- from erpnext.stock.stock_ledger import NegativeStockError
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+ from erpnext.stock.stock_ledger import NegativeStockError
item_code = "Backdated-Reco-Item"
warehouse = "_Test Warehouse - _TC"
@@ -363,8 +370,8 @@ class TestStockReconciliation(unittest.TestCase):
SR | Reco | 100 | 100 (posting date: today-1) (shouldn't be cancelled after DN)
DN | DN | 100 | 0 (posting date: today)
"""
- from erpnext.stock.stock_ledger import NegativeStockError
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+ from erpnext.stock.stock_ledger import NegativeStockError
frappe.db.commit()
item_code = "Backdated-Reco-Cancellation-Item"
diff --git a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.py b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.py
index cc1e19dcafb..227e72769b5 100644
--- a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.py
+++ b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.py
@@ -2,8 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class StockReconciliationItem(Document):
pass
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py
index 2dd7c6f35b8..2a634b3d16b 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.py
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.py
@@ -4,12 +4,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.model.document import Document
-from frappe.utils.html_utils import clean_html
-from frappe.utils import cint
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
+from frappe.model.document import Document
+from frappe.utils import cint
+from frappe.utils.html_utils import clean_html
+
class StockSettings(Document):
def validate(self):
diff --git a/erpnext/stock/doctype/stock_settings/test_stock_settings.js b/erpnext/stock/doctype/stock_settings/test_stock_settings.js
deleted file mode 100644
index 57d9fc61aab..00000000000
--- a/erpnext/stock/doctype/stock_settings/test_stock_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Stock Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Stock Settings
- () => frappe.tests.make('Stock Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/stock_settings/test_stock_settings.py b/erpnext/stock/doctype/stock_settings/test_stock_settings.py
index 42a78f723d3..7e8090499fb 100644
--- a/erpnext/stock/doctype/stock_settings/test_stock_settings.py
+++ b/erpnext/stock/doctype/stock_settings/test_stock_settings.py
@@ -3,9 +3,11 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
+
class TestStockSettings(unittest.TestCase):
def setUp(self):
frappe.db.set_value("Stock Settings", None, "clean_description_html", 0)
diff --git a/erpnext/stock/doctype/uom_category/test_uom_category.js b/erpnext/stock/doctype/uom_category/test_uom_category.js
deleted file mode 100644
index 4b5972ea716..00000000000
--- a/erpnext/stock/doctype/uom_category/test_uom_category.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: UOM Category", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new UOM Category
- () => frappe.tests.make('UOM Category', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/uom_category/test_uom_category.py b/erpnext/stock/doctype/uom_category/test_uom_category.py
index 33bd408a572..dd5510a3dd3 100644
--- a/erpnext/stock/doctype/uom_category/test_uom_category.py
+++ b/erpnext/stock/doctype/uom_category/test_uom_category.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestUOMCategory(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/uom_category/uom_category.py b/erpnext/stock/doctype/uom_category/uom_category.py
index d5c339e1bf3..282ebb2f4e2 100644
--- a/erpnext/stock/doctype/uom_category/uom_category.py
+++ b/erpnext/stock/doctype/uom_category/uom_category.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class UOMCategory(Document):
pass
diff --git a/erpnext/stock/doctype/uom_conversion_detail/uom_conversion_detail.py b/erpnext/stock/doctype/uom_conversion_detail/uom_conversion_detail.py
index fdead205670..9d9d4c6f25b 100644
--- a/erpnext/stock/doctype/uom_conversion_detail/uom_conversion_detail.py
+++ b/erpnext/stock/doctype/uom_conversion_detail/uom_conversion_detail.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class UOMConversionDetail(Document):
pass
diff --git a/erpnext/stock/doctype/variant_field/test_variant_field.js b/erpnext/stock/doctype/variant_field/test_variant_field.js
deleted file mode 100644
index 2600a10fe0d..00000000000
--- a/erpnext/stock/doctype/variant_field/test_variant_field.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Variant Field", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Variant Field
- () => frappe.tests.make('Variant Field', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/stock/doctype/variant_field/test_variant_field.py b/erpnext/stock/doctype/variant_field/test_variant_field.py
index 53024bdac15..408e33b2f70 100644
--- a/erpnext/stock/doctype/variant_field/test_variant_field.py
+++ b/erpnext/stock/doctype/variant_field/test_variant_field.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestVariantField(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/variant_field/variant_field.py b/erpnext/stock/doctype/variant_field/variant_field.py
index a77301e0e54..abcfdc7030f 100644
--- a/erpnext/stock/doctype/variant_field/variant_field.py
+++ b/erpnext/stock/doctype/variant_field/variant_field.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class VariantField(Document):
pass
diff --git a/erpnext/stock/doctype/warehouse/test_warehouse.py b/erpnext/stock/doctype/warehouse/test_warehouse.py
index 6e429a22552..1ca7181f279 100644
--- a/erpnext/stock/doctype/warehouse/test_warehouse.py
+++ b/erpnext/stock/doctype/warehouse/test_warehouse.py
@@ -5,13 +5,13 @@ from __future__ import unicode_literals
import unittest
import frappe
-from frappe.utils import cint
from frappe.test_runner import make_test_records
+from frappe.utils import cint
import erpnext
-from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
-from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
+from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
from erpnext.stock.doctype.item.test_item import create_item
+from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
test_records = frappe.get_test_records('Warehouse')
diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py
index 3abc13907cf..ecd8707fa69 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.py
+++ b/erpnext/stock/doctype/warehouse/warehouse.py
@@ -2,13 +2,18 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-from frappe.utils import cint, flt
-from frappe import throw, _
+
from collections import defaultdict
-from frappe.utils.nestedset import NestedSet
-from erpnext.stock import get_warehouse_account
+
+import frappe
+from frappe import _, throw
from frappe.contacts.address_and_contact import load_address_and_contact
+from frappe.utils import cint, flt
+from frappe.utils.nestedset import NestedSet
+
+import erpnext
+from erpnext.stock import get_warehouse_account
+
class Warehouse(NestedSet):
nsm_parent_field = 'parent_warehouse'
diff --git a/erpnext/stock/doctype/warehouse_type/test_warehouse_type.py b/erpnext/stock/doctype/warehouse_type/test_warehouse_type.py
index 39f4b2391bd..846e63be30a 100644
--- a/erpnext/stock/doctype/warehouse_type/test_warehouse_type.py
+++ b/erpnext/stock/doctype/warehouse_type/test_warehouse_type.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestWarehouseType(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/warehouse_type/warehouse_type.py b/erpnext/stock/doctype/warehouse_type/warehouse_type.py
index 4b7d8d829f9..fd83d787796 100644
--- a/erpnext/stock/doctype/warehouse_type/warehouse_type.py
+++ b/erpnext/stock/doctype/warehouse_type/warehouse_type.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class WarehouseType(Document):
pass
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index c72073c6143..19597c3d993 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -2,22 +2,27 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
+import json
+
import frappe
from frappe import _, throw
-from frappe.utils import flt, cint, add_days, cstr, add_months, getdate
-import json, copy
-from erpnext.accounts.doctype.pricing_rule.pricing_rule import get_pricing_rule_for_item, set_transaction_type
-from erpnext.setup.utils import get_exchange_rate
from frappe.model.meta import get_field_precision
-from erpnext.stock.doctype.batch.batch import get_batch_no
-from erpnext import get_company_currency
-from erpnext.stock.doctype.item.item import get_item_defaults, get_uom_conv_factor
-from erpnext.stock.doctype.price_list.price_list import get_price_list_details
-from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
-from erpnext.setup.doctype.brand.brand import get_brand_defaults
-from erpnext.stock.doctype.item_manufacturer.item_manufacturer import get_item_manufacturer_part_no
+from frappe.utils import add_days, add_months, cint, cstr, flt, getdate
+from six import iteritems, string_types
-from six import string_types, iteritems
+from erpnext import get_company_currency
+from erpnext.accounts.doctype.pricing_rule.pricing_rule import (
+ get_pricing_rule_for_item,
+ set_transaction_type,
+)
+from erpnext.setup.doctype.brand.brand import get_brand_defaults
+from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
+from erpnext.setup.utils import get_exchange_rate
+from erpnext.stock.doctype.batch.batch import get_batch_no
+from erpnext.stock.doctype.item.item import get_item_defaults, get_uom_conv_factor
+from erpnext.stock.doctype.item_manufacturer.item_manufacturer import get_item_manufacturer_part_no
+from erpnext.stock.doctype.price_list.price_list import get_price_list_details
sales_doctypes = ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice', 'POS Invoice']
purchase_doctypes = ['Material Request', 'Supplier Quotation', 'Purchase Order', 'Purchase Receipt', 'Purchase Invoice']
@@ -316,8 +321,8 @@ def get_basic_details(args, item, overwrite_warehouse=True):
"transaction_date": args.get("transaction_date"),
"against_blanket_order": args.get("against_blanket_order"),
"bom_no": item.get("default_bom"),
- "weight_per_unit": item.get("weight_per_unit"),
- "weight_uom": item.get("weight_uom")
+ "weight_per_unit": args.get("weight_per_unit") or item.get("weight_per_unit"),
+ "weight_uom": args.get("weight_uom") or item.get("weight_uom")
})
if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"):
diff --git a/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json b/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json
deleted file mode 100644
index 5ee316786ca..00000000000
--- a/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "add_more_button": 1,
- "app": "ERPNext",
- "creation": "2019-11-15 14:41:12.007359",
- "docstatus": 0,
- "doctype": "Onboarding Slide",
- "domains": [],
- "help_links": [],
- "idx": 0,
- "image_src": "",
- "is_completed": 0,
- "max_count": 3,
- "modified": "2019-12-09 17:54:09.602885",
- "modified_by": "Administrator",
- "name": "Add A Few Products You Buy Or Sell",
- "owner": "Administrator",
- "ref_doctype": "Item",
- "slide_desc": "",
- "slide_fields": [
- {
- "align": "",
- "fieldname": "item",
- "fieldtype": "Data",
- "label": "Item",
- "placeholder": "Product Name",
- "reqd": 1
- },
- {
- "align": "",
- "fieldname": "item_price",
- "fieldtype": "Currency",
- "label": "Item Price",
- "reqd": 1
- },
- {
- "align": "",
- "fieldtype": "Column Break",
- "reqd": 0
- },
- {
- "align": "",
- "fieldname": "uom",
- "fieldtype": "Link",
- "label": "UOM",
- "options": "UOM",
- "reqd": 1
- }
- ],
- "slide_order": 30,
- "slide_title": "Add A Few Products You Buy Or Sell",
- "slide_type": "Create"
-}
\ No newline at end of file
diff --git a/erpnext/stock/reorder_item.py b/erpnext/stock/reorder_item.py
index 4c721acdc12..3cd4cd27617 100644
--- a/erpnext/stock/reorder_item.py
+++ b/erpnext/stock/reorder_item.py
@@ -2,11 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-import erpnext
+
import json
-from frappe.utils import flt, nowdate, add_days, cint
+
+import frappe
from frappe import _
+from frappe.utils import add_days, cint, flt, nowdate
+
+import erpnext
+
def reorder_item():
""" Reorder item if stock reaches reorder level"""
@@ -166,7 +170,7 @@ def create_material_request(material_requests):
mr.submit()
mr_list.append(mr)
- except:
+ except Exception:
_log_exception()
if mr_list:
diff --git a/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py b/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py
index 29689b1a912..da57baddc8c 100644
--- a/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py
+++ b/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt, cint, getdate
+from frappe.utils import cint, getdate
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/stock/report/bom_search/bom_search.py b/erpnext/stock/report/bom_search/bom_search.py
index e3955c9a37f..8b583f35880 100644
--- a/erpnext/stock/report/bom_search/bom_search.py
+++ b/erpnext/stock/report/bom_search/bom_search.py
@@ -2,10 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, json
+import frappe
from six import iteritems
+
def execute(filters=None):
data = []
parents = {
diff --git a/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.py b/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.py
index da593a40d68..5f6184d6f35 100644
--- a/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.py
+++ b/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.py
@@ -1,8 +1,8 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-from collections import OrderedDict
import datetime
+from collections import OrderedDict
from typing import Dict, List, Tuple, Union
import frappe
@@ -11,7 +11,6 @@ from frappe.utils import date_diff
from erpnext.accounts.report.general_ledger.general_ledger import get_gl_entries
-
Filters = frappe._dict
Row = frappe._dict
Data = List[Row]
@@ -43,13 +42,13 @@ def validate_filters(filters: Filters) -> None:
def get_columns() -> Columns:
return [
{
- 'label': 'Item Group',
+ 'label': _('Item Group'),
'fieldname': 'item_group',
'fieldtype': 'Data',
'width': '200'
},
{
- 'label': 'COGS Debit',
+ 'label': _('COGS Debit'),
'fieldname': 'cogs_debit',
'fieldtype': 'Currency',
'width': '200'
diff --git a/erpnext/stock/report/delayed_item_report/delayed_item_report.py b/erpnext/stock/report/delayed_item_report/delayed_item_report.py
index 61306662c0d..1dd0478b40c 100644
--- a/erpnext/stock/report/delayed_item_report/delayed_item_report.py
+++ b/erpnext/stock/report/delayed_item_report/delayed_item_report.py
@@ -2,10 +2,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import date_diff
+
def execute(filters=None, consolidated = False):
data, columns = DelayedItemReport(filters).run()
diff --git a/erpnext/stock/report/delayed_order_report/delayed_order_report.py b/erpnext/stock/report/delayed_order_report/delayed_order_report.py
index d9151606884..677e30c5a41 100644
--- a/erpnext/stock/report/delayed_order_report/delayed_order_report.py
+++ b/erpnext/stock/report/delayed_order_report/delayed_order_report.py
@@ -2,9 +2,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe import _
+
from erpnext.stock.report.delayed_item_report.delayed_item_report import DelayedItemReport
+
def execute(filters=None):
columns, data = [], []
diff --git a/erpnext/stock/report/delivery_note_trends/delivery_note_trends.py b/erpnext/stock/report/delivery_note_trends/delivery_note_trends.py
index 77fd2ff2447..6d03ec1c050 100644
--- a/erpnext/stock/report/delivery_note_trends/delivery_note_trends.py
+++ b/erpnext/stock/report/delivery_note_trends/delivery_note_trends.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe import _
-from erpnext.controllers.trends import get_columns,get_data
+
+from erpnext.controllers.trends import get_columns, get_data
+
def execute(filters=None):
if not filters: filters ={}
diff --git a/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.py b/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.py
index 00125e71a9a..cf273265599 100644
--- a/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.py
+++ b/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.py
@@ -3,8 +3,9 @@
import frappe
from frappe import _
-from six import iteritems
from frappe.utils import flt
+from six import iteritems
+
def execute(filters=None):
columns, data = [], []
diff --git a/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py
index b3b7594ffd7..5f03c7cbe0a 100644
--- a/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py
+++ b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py
@@ -1,12 +1,15 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-import frappe
import copy
+
+import frappe
from frappe import _
from six import iteritems
+
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+
def execute(filters=None):
columns, data = [], []
columns = get_columns()
diff --git a/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py b/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py
index c8f60a15d64..bc520ae27d9 100644
--- a/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py
+++ b/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py
@@ -2,13 +2,16 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-import erpnext
from frappe import _
+from frappe.utils import add_days, getdate, today
from six import iteritems
-from frappe.utils import add_days, today, getdate
-from erpnext.stock.utils import get_stock_value_on
+
+import erpnext
from erpnext.accounts.utils import get_stock_and_account_balance
+from erpnext.stock.utils import get_stock_value_on
+
def execute(filters=None):
if not erpnext.is_perpetual_inventory_enabled(filters.company):
diff --git a/erpnext/stock/report/item_price_stock/item_price_stock.py b/erpnext/stock/report/item_price_stock/item_price_stock.py
index db7498bb215..6ffb5c8a983 100644
--- a/erpnext/stock/report/item_price_stock/item_price_stock.py
+++ b/erpnext/stock/report/item_price_stock/item_price_stock.py
@@ -1,9 +1,11 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
columns, data = [], []
columns=get_columns()
diff --git a/erpnext/stock/report/item_prices/item_prices.py b/erpnext/stock/report/item_prices/item_prices.py
index 12f32972039..aa5ae0ed3d4 100644
--- a/erpnext/stock/report/item_prices/item_prices.py
+++ b/erpnext/stock/report/item_prices/item_prices.py
@@ -2,10 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import msgprint, _
+from frappe import _
from frappe.utils import flt
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/stock/report/item_shortage_report/item_shortage_report.py b/erpnext/stock/report/item_shortage_report/item_shortage_report.py
index c67eed7e926..1438e6cda02 100644
--- a/erpnext/stock/report/item_shortage_report/item_shortage_report.py
+++ b/erpnext/stock/report/item_shortage_report/item_shortage_report.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
columns = get_columns()
conditions = get_conditions(filters)
diff --git a/erpnext/stock/report/item_variant_details/item_variant_details.py b/erpnext/stock/report/item_variant_details/item_variant_details.py
index d8563d79271..eedda53bed2 100644
--- a/erpnext/stock/report/item_variant_details/item_variant_details.py
+++ b/erpnext/stock/report/item_variant_details/item_variant_details.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
columns = get_columns(filters.item)
data = get_data(filters.item)
diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py
index 2e13aa0b040..08869af44ae 100644
--- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py
+++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py
@@ -4,7 +4,8 @@ from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import getdate, flt
+from frappe.utils import flt, getdate
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/stock/report/process_loss_report/process_loss_report.py b/erpnext/stock/report/process_loss_report/process_loss_report.py
index 7494328ab43..5c6a3bb4566 100644
--- a/erpnext/stock/report/process_loss_report/process_loss_report.py
+++ b/erpnext/stock/report/process_loss_report/process_loss_report.py
@@ -1,9 +1,11 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-import frappe
from typing import Dict, List, Tuple
+import frappe
+from frappe import _
+
Filters = frappe._dict
Row = frappe._dict
Data = List[Row]
@@ -24,57 +26,57 @@ def get_data(filters: Filters) -> Data:
def get_columns() -> Columns:
return [
{
- 'label': 'Work Order',
+ 'label': _('Work Order'),
'fieldname': 'name',
'fieldtype': 'Link',
'options': 'Work Order',
'width': '200'
},
{
- 'label': 'Item',
+ 'label': _('Item'),
'fieldname': 'production_item',
'fieldtype': 'Link',
'options': 'Item',
'width': '100'
},
{
- 'label': 'Status',
+ 'label': _('Status'),
'fieldname': 'status',
'fieldtype': 'Data',
'width': '100'
},
{
- 'label': 'Manufactured Qty',
+ 'label': _('Manufactured Qty'),
'fieldname': 'produced_qty',
'fieldtype': 'Float',
'width': '150'
},
{
- 'label': 'Loss Qty',
+ 'label': _('Loss Qty'),
'fieldname': 'process_loss_qty',
'fieldtype': 'Float',
'width': '150'
},
{
- 'label': 'Actual Manufactured Qty',
+ 'label': _('Actual Manufactured Qty'),
'fieldname': 'actual_produced_qty',
'fieldtype': 'Float',
'width': '150'
},
{
- 'label': 'Loss Value',
+ 'label': _('Loss Value'),
'fieldname': 'total_pl_value',
'fieldtype': 'Float',
'width': '150'
},
{
- 'label': 'FG Value',
+ 'label': _('FG Value'),
'fieldname': 'total_fg_value',
'fieldtype': 'Float',
'width': '150'
},
{
- 'label': 'Raw Material Value',
+ 'label': _('Raw Material Value'),
'fieldname': 'total_rm_value',
'fieldtype': 'Float',
'width': '150'
@@ -91,7 +93,7 @@ def get_query_args(filters: Filters) -> QueryArgs:
def run_query(query_args: QueryArgs) -> Data:
return frappe.db.sql("""
- SELECT
+ SELECT
wo.name, wo.status, wo.production_item, wo.qty,
wo.produced_qty, wo.process_loss_qty,
(wo.produced_qty - wo.process_loss_qty) as actual_produced_qty,
diff --git a/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py b/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py
index 8fffbccab3c..2e298e7da4d 100644
--- a/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py
+++ b/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py
@@ -2,12 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt
-from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition
from six import iteritems
+from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition
+
def execute(filters=None):
if not filters:
diff --git a/erpnext/stock/report/purchase_receipt_trends/purchase_receipt_trends.py b/erpnext/stock/report/purchase_receipt_trends/purchase_receipt_trends.py
index 0d96ea6aa8e..29595323980 100644
--- a/erpnext/stock/report/purchase_receipt_trends/purchase_receipt_trends.py
+++ b/erpnext/stock/report/purchase_receipt_trends/purchase_receipt_trends.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe import _
-from erpnext.controllers.trends import get_columns,get_data
+
+from erpnext.controllers.trends import get_columns, get_data
+
def execute(filters=None):
if not filters: filters ={}
diff --git a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
index cc3aa3522d8..897a130a51a 100644
--- a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
+++ b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe import _
+
from erpnext.stock.stock_ledger import get_stock_ledger_entries
-from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+
def execute(filters=None):
columns = get_columns(filters)
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index 623dc2ffd97..b4eca0ba96a 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -2,17 +2,22 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
+from operator import itemgetter
+
import frappe
from frappe import _
-from frappe.utils import date_diff, flt, cint
+from frappe.utils import cint, date_diff, flt
from six import iteritems
+
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+
def execute(filters=None):
columns = get_columns(filters)
item_details = get_fifo_queue(filters)
to_date = filters["to_date"]
- _func = lambda x: x[1]
+ _func = itemgetter(1)
data = []
for item, item_dict in iteritems(item_details):
@@ -26,7 +31,7 @@ def execute(filters=None):
average_age = get_average_age(fifo_queue, to_date)
earliest_age = date_diff(to_date, fifo_queue[0][1])
latest_age = date_diff(to_date, fifo_queue[-1][1])
- range1, range2, range3, above_range3 = get_range_age(filters, fifo_queue, to_date)
+ range1, range2, range3, above_range3 = get_range_age(filters, fifo_queue, to_date, item_dict)
row = [details.name, details.item_name,
details.description, details.item_group, details.brand]
@@ -58,19 +63,21 @@ def get_average_age(fifo_queue, to_date):
return flt(age_qty / total_qty, 2) if total_qty else 0.0
-def get_range_age(filters, fifo_queue, to_date):
+def get_range_age(filters, fifo_queue, to_date, item_dict):
range1 = range2 = range3 = above_range3 = 0.0
+
for item in fifo_queue:
age = date_diff(to_date, item[1])
+ qty = flt(item[0]) if not item_dict["has_serial_no"] else 1.0
if age <= filters.range1:
- range1 += flt(item[0])
+ range1 += qty
elif age <= filters.range2:
- range2 += flt(item[0])
+ range2 += qty
elif age <= filters.range3:
- range3 += flt(item[0])
+ range3 += qty
else:
- above_range3 += flt(item[0])
+ above_range3 += qty
return range1, range2, range3, above_range3
@@ -197,9 +204,7 @@ def get_fifo_queue(filters, sle=None):
fifo_queue.append([d.actual_qty, d.posting_date])
else:
if serial_no_list:
- for serial_no in fifo_queue:
- if serial_no[0] in serial_no_list:
- fifo_queue.remove(serial_no)
+ fifo_queue[:] = [serial_no for serial_no in fifo_queue if serial_no[0] not in serial_no_list]
else:
qty_to_pop = abs(d.actual_qty)
while qty_to_pop:
@@ -222,14 +227,16 @@ def get_fifo_queue(filters, sle=None):
else:
item_details[key]["total_qty"] += d.actual_qty
+ item_details[key]["has_serial_no"] = d.has_serial_no
+
return item_details
def get_stock_ledger_entries(filters):
return frappe.db.sql("""select
- item.name, item.item_name, item_group, brand, description, item.stock_uom,
+ item.name, item.item_name, item_group, brand, description, item.stock_uom, item.has_serial_no,
actual_qty, posting_date, voucher_type, voucher_no, serial_no, batch_no, qty_after_transaction, warehouse
from `tabStock Ledger Entry` sle,
- (select name, item_name, description, stock_uom, brand, item_group
+ (select name, item_name, description, stock_uom, brand, item_group, has_serial_no
from `tabItem` {item_conditions}) item
where item_code = item.name and
company = %(company)s and
diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.py b/erpnext/stock/report/stock_analytics/stock_analytics.py
index a1e1e7fce7c..ddc831037bf 100644
--- a/erpnext/stock/report/stock_analytics/stock_analytics.py
+++ b/erpnext/stock/report/stock_analytics/stock_analytics.py
@@ -4,13 +4,18 @@ import datetime
import frappe
from frappe import _, scrub
-from frappe.utils import getdate, get_quarter_start, get_first_day_of_week
from frappe.utils import get_first_day as get_first_day_of_month
+from frappe.utils import get_first_day_of_week, get_quarter_start, getdate
-from erpnext.stock.report.stock_balance.stock_balance import (get_items, get_stock_ledger_entries, get_item_details)
from erpnext.accounts.utils import get_fiscal_year
+from erpnext.stock.report.stock_balance.stock_balance import (
+ get_item_details,
+ get_items,
+ get_stock_ledger_entries,
+)
from erpnext.stock.utils import is_reposting_item_valuation_in_progress
+
def execute(filters=None):
is_reposting_item_valuation_in_progress()
filters = frappe._dict(filters or {})
diff --git a/erpnext/stock/report/stock_analytics/test_stock_analytics.py b/erpnext/stock/report/stock_analytics/test_stock_analytics.py
index 00e268b4e0e..21e1205bfcc 100644
--- a/erpnext/stock/report/stock_analytics/test_stock_analytics.py
+++ b/erpnext/stock/report/stock_analytics/test_stock_analytics.py
@@ -2,8 +2,8 @@ import datetime
import unittest
from frappe import _dict
-from erpnext.accounts.utils import get_fiscal_year
+from erpnext.accounts.utils import get_fiscal_year
from erpnext.stock.report.stock_analytics.stock_analytics import get_period_date_ranges
diff --git a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
index 7e0c0e8ab35..f64774a20a8 100644
--- a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
+++ b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
@@ -2,12 +2,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+
+import frappe
from frappe import _
-from erpnext.accounts.utils import get_stock_accounts
-from erpnext.accounts.utils import get_currency_precision
+
+import erpnext
+from erpnext.accounts.utils import get_currency_precision, get_stock_accounts
from erpnext.stock.doctype.warehouse.warehouse import get_warehouses_based_on_account
+
def execute(filters=None):
if not erpnext.is_perpetual_inventory_enabled(filters.company):
frappe.throw(_("Perpetual inventory required for the company {0} to view this report.")
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index fc3d719a780..fc5d5c12da4 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -2,16 +2,20 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-from frappe import _
-from frappe.utils import flt, cint, getdate, now, date_diff
-from erpnext.stock.utils import add_additional_uom_columns
-from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition
-from erpnext.stock.utils import is_reposting_item_valuation_in_progress
-from erpnext.stock.report.stock_ageing.stock_ageing import get_fifo_queue, get_average_age
+from operator import itemgetter
+
+import frappe
+from frappe import _
+from frappe.utils import cint, date_diff, flt, getdate
from six import iteritems
+import erpnext
+from erpnext.stock.report.stock_ageing.stock_ageing import get_average_age, get_fifo_queue
+from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition
+from erpnext.stock.utils import add_additional_uom_columns, is_reposting_item_valuation_in_progress
+
+
def execute(filters=None):
is_reposting_item_valuation_in_progress()
if not filters: filters = {}
@@ -44,7 +48,7 @@ def execute(filters=None):
data = []
conversion_factors = {}
- _func = lambda x: x[1]
+ _func = itemgetter(1)
for (company, item, warehouse) in sorted(iwb_map):
if item_map.get(item):
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index b6923e97c4f..1ea58fed191 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -4,10 +4,15 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import cint, flt
-from erpnext.stock.utils import update_included_uom_in_report, is_reposting_item_valuation_in_progress
from frappe import _
+from frappe.utils import cint, flt
+
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+from erpnext.stock.utils import (
+ is_reposting_item_valuation_in_progress,
+ update_included_uom_in_report,
+)
+
def execute(filters=None):
is_reposting_item_valuation_in_progress()
diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
index 7956f2e8648..16f7c305a3c 100644
--- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
+++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
@@ -2,11 +2,17 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt, today
-from erpnext.stock.utils import update_included_uom_in_report, is_reposting_item_valuation_in_progress
+
from erpnext.accounts.doctype.pos_invoice.pos_invoice import get_pos_reserved_qty
+from erpnext.stock.utils import (
+ is_reposting_item_valuation_in_progress,
+ update_included_uom_in_report,
+)
+
def execute(filters=None):
is_reposting_item_valuation_in_progress()
diff --git a/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py b/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py
index fa19eeba58b..5580636703e 100644
--- a/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py
+++ b/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
validate_warehouse(filters)
columns = get_columns()
diff --git a/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py b/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py
index 4108a575542..f15557b00bf 100644
--- a/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py
+++ b/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py
@@ -2,11 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt
from six import iteritems
+
def execute(filters=None):
columns = get_columns(filters)
consumed_details = get_consumed_details(filters)
diff --git a/erpnext/stock/report/total_stock_summary/total_stock_summary.py b/erpnext/stock/report/total_stock_summary/total_stock_summary.py
index 59c253c425b..779b5aabdbc 100644
--- a/erpnext/stock/report/total_stock_summary/total_stock_summary.py
+++ b/erpnext/stock/report/total_stock_summary/total_stock_summary.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
if not filters: filters = {}
validate_filters(filters)
diff --git a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py
index 04f7d347ba8..6cb37513666 100644
--- a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py
+++ b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py
@@ -5,15 +5,22 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt, cint, getdate
-from erpnext.stock.report.stock_balance.stock_balance import (get_item_details,
- get_item_reorder_details, get_item_warehouse_map, get_items, get_stock_ledger_entries)
-from erpnext.stock.report.stock_ageing.stock_ageing import get_fifo_queue, get_average_age
-from erpnext.stock.utils import is_reposting_item_valuation_in_progress
+from frappe.utils import flt
from six import iteritems
+from erpnext.stock.report.stock_ageing.stock_ageing import get_average_age, get_fifo_queue
+from erpnext.stock.report.stock_balance.stock_balance import (
+ get_item_details,
+ get_item_warehouse_map,
+ get_items,
+ get_stock_ledger_entries,
+)
+from erpnext.stock.utils import is_reposting_item_valuation_in_progress
+
+
def execute(filters=None):
is_reposting_item_valuation_in_progress()
if not filters: filters = {}
diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py
index 8917bfeae4f..1cb0f0d0a49 100644
--- a/erpnext/stock/stock_balance.py
+++ b/erpnext/stock/stock_balance.py
@@ -2,11 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import print_function, unicode_literals
+
import frappe
-from frappe.utils import flt, cstr, nowdate, nowtime
-from erpnext.stock.utils import update_bin
-from erpnext.stock.stock_ledger import update_entries_after
+from frappe.utils import cstr, flt, nowdate, nowtime
+
from erpnext.controllers.stock_controller import create_repost_item_valuation_entry
+from erpnext.stock.utils import update_bin
+
def repost(only_actual=False, allow_negative_stock=False, allow_zero_rate=False, only_bin=False):
"""
@@ -29,7 +31,7 @@ def repost(only_actual=False, allow_negative_stock=False, allow_zero_rate=False,
try:
repost_stock(d[0], d[1], allow_zero_rate, only_actual, only_bin, allow_negative_stock)
frappe.db.commit()
- except:
+ except Exception:
frappe.db.rollback()
if allow_negative_stock:
@@ -247,5 +249,5 @@ def reset_serial_no_status_and_warehouse(serial_nos=None):
sr.via_stock_ledger = True
sr.save()
- except:
+ except Exception:
pass
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index e98df737cb7..8e364a5062e 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -2,17 +2,22 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-import erpnext
import copy
-from frappe import _
-from frappe.utils import cint, flt, cstr, now, get_link_to_form, getdate
-from frappe.model.meta import get_field_precision
-from erpnext.stock.utils import get_valuation_method, get_incoming_outgoing_rate_for_cancel
-from erpnext.stock.utils import get_bin
import json
+
+import frappe
+from frappe import _
+from frappe.model.meta import get_field_precision
+from frappe.utils import cint, cstr, flt, get_link_to_form, getdate, now
from six import iteritems
+import erpnext
+from erpnext.stock.utils import (
+ get_bin,
+ get_incoming_outgoing_rate_for_cancel,
+ get_valuation_method,
+)
+
# future reposting
class NegativeStockError(frappe.ValidationError): pass
@@ -394,7 +399,8 @@ class update_entries_after(object):
return
# Get dynamic incoming/outgoing rate
- self.get_dynamic_incoming_outgoing_rate(sle)
+ if not self.args.get("sle_id"):
+ self.get_dynamic_incoming_outgoing_rate(sle)
if sle.serial_no:
self.get_serialized_values(sle)
@@ -434,7 +440,8 @@ class update_entries_after(object):
sle.doctype="Stock Ledger Entry"
frappe.get_doc(sle).db_update()
- self.update_outgoing_rate_on_transaction(sle)
+ if not self.args.get("sle_id"):
+ self.update_outgoing_rate_on_transaction(sle)
def validate_negative_stock(self, sle):
"""
@@ -470,7 +477,9 @@ class update_entries_after(object):
# Sales and Purchase Return
elif sle.voucher_type in ("Purchase Receipt", "Purchase Invoice", "Delivery Note", "Sales Invoice"):
if frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_return"):
- from erpnext.controllers.sales_and_purchase_return import get_rate_for_return # don't move this import to top
+ from erpnext.controllers.sales_and_purchase_return import (
+ get_rate_for_return, # don't move this import to top
+ )
rate = get_rate_for_return(sle.voucher_type, sle.voucher_no, sle.item_code,
voucher_detail_no=sle.voucher_detail_no, sle = sle)
else:
@@ -666,11 +675,15 @@ class update_entries_after(object):
if self.wh_data.stock_queue[-1][1]==incoming_rate:
self.wh_data.stock_queue[-1][0] += actual_qty
else:
+ # Item has a positive balance qty, add new entry
if self.wh_data.stock_queue[-1][0] > 0:
self.wh_data.stock_queue.append([actual_qty, incoming_rate])
- else:
+ else: # negative balance qty
qty = self.wh_data.stock_queue[-1][0] + actual_qty
- self.wh_data.stock_queue[-1] = [qty, incoming_rate]
+ if qty > 0: # new balance qty is positive
+ self.wh_data.stock_queue[-1] = [qty, incoming_rate]
+ else: # new balance qty is still negative, maintain same rate
+ self.wh_data.stock_queue[-1][0] = qty
else:
qty_to_pop = abs(actual_qty)
while qty_to_pop:
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index 9f6d0a8addd..aeb06e987f8 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -2,13 +2,17 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-from frappe import _
-import json
-from frappe.utils import flt, cstr, nowdate, nowtime, get_link_to_form
+import json
+
+import frappe
+from frappe import _
+from frappe.utils import cstr, flt, get_link_to_form, nowdate, nowtime
from six import string_types
+import erpnext
+
+
class InvalidWarehouseCompany(frappe.ValidationError): pass
def get_stock_value_from_bin(warehouse=None, item_code=None):
diff --git a/erpnext/support/__init__.py b/erpnext/support/__init__.py
index cc26c14433c..bd1b3f88adc 100644
--- a/erpnext/support/__init__.py
+++ b/erpnext/support/__init__.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
install_docs = [
{'doctype':'Role', 'role_name':'Support Team', 'name':'Support Team'},
{'doctype':'Role', 'role_name':'Maintenance User', 'name':'Maintenance User'},
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index 074f1aca0e2..272e3be2648 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -2,17 +2,33 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import json
-from frappe import _
-from frappe import utils
-from frappe.model.document import Document
-from frappe.utils import cint, now_datetime, getdate, get_weekdays, add_to_date, get_time, get_datetime, time_diff_in_seconds
from datetime import datetime, timedelta
-from frappe.model.mapper import get_mapped_doc
-from frappe.utils.user import is_website_user
-from erpnext.support.doctype.service_level_agreement.service_level_agreement import get_active_service_level_agreement_for
+
+import frappe
+from frappe import _
+from frappe.core.utils import get_parent_doc
from frappe.email.inbox import link_communication_to_document
+from frappe.model.document import Document
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import (
+ add_to_date,
+ cint,
+ date_diff,
+ get_datetime,
+ get_time,
+ get_weekdays,
+ getdate,
+ now_datetime,
+ time_diff_in_seconds,
+)
+from frappe.utils.user import is_website_user
+
+from erpnext.support.doctype.service_level_agreement.service_level_agreement import (
+ get_active_service_level_agreement_for,
+)
+
class Issue(Document):
def get_feed(self):
@@ -24,11 +40,9 @@ class Issue(Document):
if not self.raised_by:
self.raised_by = frappe.session.user
-
self.change_service_level_agreement_and_priority()
self.update_status()
self.set_lead_contact(self.raised_by)
-
if not self.service_level_agreement:
self.reset_sla_fields()
@@ -293,10 +307,6 @@ class Issue(Document):
self.agreement_status = "Ongoing"
self.save()
- def reset_issue_metrics(self):
- self.db_set("resolution_time", None)
- self.db_set("user_resolution_time", None)
-
def get_priority(issue):
service_level_agreement = frappe.get_doc("Service Level Agreement", issue.service_level_agreement)
@@ -524,5 +534,120 @@ def get_time_in_timedelta(time):
"""
Converts datetime.time(10, 36, 55, 961454) to datetime.timedelta(seconds=38215)
"""
- import datetime
- return datetime.timedelta(hours=time.hour, minutes=time.minute, seconds=time.second)
+ return timedelta(hours=time.hour, minutes=time.minute, seconds=time.second)
+
+def set_first_response_time(communication, method):
+ if communication.get('reference_doctype') == "Issue":
+ issue = get_parent_doc(communication)
+ if is_first_response(issue):
+ first_response_time = calculate_first_response_time(issue, get_datetime(issue.first_responded_on))
+ issue.db_set("first_response_time", first_response_time)
+
+def is_first_response(issue):
+ responses = frappe.get_all('Communication', filters = {'reference_name': issue.name, 'sent_or_received': 'Sent'})
+ if len(responses) == 1:
+ return True
+ return False
+
+def calculate_first_response_time(issue, first_responded_on):
+ issue_creation_date = issue.creation
+ issue_creation_time = get_time_in_seconds(issue_creation_date)
+ first_responded_on_in_seconds = get_time_in_seconds(first_responded_on)
+ support_hours = frappe.get_cached_doc("Service Level Agreement", issue.service_level_agreement).support_and_resolution
+
+ if issue_creation_date.day == first_responded_on.day:
+ if is_work_day(issue_creation_date, support_hours):
+ start_time, end_time = get_working_hours(issue_creation_date, support_hours)
+
+ # issue creation and response on the same day during working hours
+ if is_during_working_hours(issue_creation_date, support_hours) and is_during_working_hours(first_responded_on, support_hours):
+ return get_elapsed_time(issue_creation_date, first_responded_on)
+
+ # issue creation is during working hours, but first response was after working hours
+ elif is_during_working_hours(issue_creation_date, support_hours):
+ return get_elapsed_time(issue_creation_time, end_time)
+
+ # issue creation was before working hours but first response is during working hours
+ elif is_during_working_hours(first_responded_on, support_hours):
+ return get_elapsed_time(start_time, first_responded_on_in_seconds)
+
+ # both issue creation and first response were after working hours
+ else:
+ return 1.0 # this should ideally be zero, but it gets reset when the next response is sent if the value is zero
+
+ else:
+ return 1.0
+
+ else:
+ # response on the next day
+ if date_diff(first_responded_on, issue_creation_date) == 1:
+ first_response_time = 0
+ else:
+ first_response_time = calculate_initial_frt(issue_creation_date, date_diff(first_responded_on, issue_creation_date)- 1, support_hours)
+
+ # time taken on day of issue creation
+ if is_work_day(issue_creation_date, support_hours):
+ start_time, end_time = get_working_hours(issue_creation_date, support_hours)
+
+ if is_during_working_hours(issue_creation_date, support_hours):
+ first_response_time += get_elapsed_time(issue_creation_time, end_time)
+ elif is_before_working_hours(issue_creation_date, support_hours):
+ first_response_time += get_elapsed_time(start_time, end_time)
+
+ # time taken on day of first response
+ if is_work_day(first_responded_on, support_hours):
+ start_time, end_time = get_working_hours(first_responded_on, support_hours)
+
+ if is_during_working_hours(first_responded_on, support_hours):
+ first_response_time += get_elapsed_time(start_time, first_responded_on_in_seconds)
+ elif not is_before_working_hours(first_responded_on, support_hours):
+ first_response_time += get_elapsed_time(start_time, end_time)
+
+ if first_response_time:
+ return first_response_time
+ else:
+ return 1.0
+
+def get_time_in_seconds(date):
+ return timedelta(hours=date.hour, minutes=date.minute, seconds=date.second)
+
+def get_working_hours(date, support_hours):
+ if is_work_day(date, support_hours):
+ weekday = frappe.utils.get_weekday(date)
+ for day in support_hours:
+ if day.workday == weekday:
+ return day.start_time, day.end_time
+
+def is_work_day(date, support_hours):
+ weekday = frappe.utils.get_weekday(date)
+ for day in support_hours:
+ if day.workday == weekday:
+ return True
+ return False
+
+def is_during_working_hours(date, support_hours):
+ start_time, end_time = get_working_hours(date, support_hours)
+ time = get_time_in_seconds(date)
+ if time >= start_time and time <= end_time:
+ return True
+ return False
+
+def get_elapsed_time(start_time, end_time):
+ return round(time_diff_in_seconds(end_time, start_time), 2)
+
+def calculate_initial_frt(issue_creation_date, days_in_between, support_hours):
+ initial_frt = 0
+ for i in range(days_in_between):
+ date = issue_creation_date + timedelta(days = (i+1))
+ if is_work_day(date, support_hours):
+ start_time, end_time = get_working_hours(date, support_hours)
+ initial_frt += get_elapsed_time(start_time, end_time)
+
+ return initial_frt
+
+def is_before_working_hours(date, support_hours):
+ start_time, end_time = get_working_hours(date, support_hours)
+ time = get_time_in_seconds(date)
+ if time < start_time:
+ return True
+ return False
diff --git a/erpnext/support/doctype/issue/test_issue.py b/erpnext/support/doctype/issue/test_issue.py
index 7da5d7f0ed4..7de5b9abb91 100644
--- a/erpnext/support/doctype/issue/test_issue.py
+++ b/erpnext/support/doctype/issue/test_issue.py
@@ -2,72 +2,77 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from erpnext.support.doctype.service_level_agreement.test_service_level_agreement import create_service_level_agreements_for_issues
-from frappe.utils import now_datetime, get_datetime, flt
-import datetime
-from datetime import timedelta
-class TestIssue(unittest.TestCase):
+import frappe
+from frappe.core.doctype.user_permission.test_user_permission import create_user
+from frappe.utils import flt, get_datetime
+
+from erpnext.support.doctype.service_level_agreement.test_service_level_agreement import (
+ create_service_level_agreements_for_issues,
+)
+
+
+class TestSetUp(unittest.TestCase):
def setUp(self):
frappe.db.sql("delete from `tabService Level Agreement`")
frappe.db.set_value("Support Settings", None, "track_service_level_agreement", 1)
create_service_level_agreements_for_issues()
+class TestIssue(TestSetUp):
def test_response_time_and_resolution_time_based_on_different_sla(self):
- creation = datetime.datetime(2019, 3, 4, 12, 0)
+ creation = get_datetime("2019-03-04 12:00")
# make issue with customer specific SLA
customer = create_customer("_Test Customer", "__Test SLA Customer Group", "__Test SLA Territory")
issue = make_issue(creation, "_Test Customer", 1)
- self.assertEqual(issue.response_by, datetime.datetime(2019, 3, 4, 14, 0))
- self.assertEqual(issue.resolution_by, datetime.datetime(2019, 3, 4, 15, 0))
+ self.assertEqual(issue.response_by, get_datetime("2019-03-04 14:00"))
+ self.assertEqual(issue.resolution_by, get_datetime("2019-03-04 15:00"))
# make issue with customer_group specific SLA
customer = create_customer("__Test Customer", "_Test SLA Customer Group", "__Test SLA Territory")
issue = make_issue(creation, "__Test Customer", 2)
- self.assertEqual(issue.response_by, datetime.datetime(2019, 3, 4, 14, 0))
- self.assertEqual(issue.resolution_by, datetime.datetime(2019, 3, 4, 15, 0))
+ self.assertEqual(issue.response_by, get_datetime("2019-03-04 14:00"))
+ self.assertEqual(issue.resolution_by, get_datetime("2019-03-04 15:00"))
# make issue with territory specific SLA
customer = create_customer("___Test Customer", "__Test SLA Customer Group", "_Test SLA Territory")
issue = make_issue(creation, "___Test Customer", 3)
- self.assertEqual(issue.response_by, datetime.datetime(2019, 3, 4, 14, 0))
- self.assertEqual(issue.resolution_by, datetime.datetime(2019, 3, 4, 15, 0))
+ self.assertEqual(issue.response_by, get_datetime("2019-03-04 14:00"))
+ self.assertEqual(issue.resolution_by, get_datetime("2019-03-04 15:00"))
# make issue with default SLA
issue = make_issue(creation=creation, index=4)
- self.assertEqual(issue.response_by, datetime.datetime(2019, 3, 4, 16, 0))
- self.assertEqual(issue.resolution_by, datetime.datetime(2019, 3, 4, 18, 0))
+ self.assertEqual(issue.response_by, get_datetime("2019-03-04 16:00"))
+ self.assertEqual(issue.resolution_by, get_datetime("2019-03-04 18:00"))
# make issue with default SLA before working hours
- creation = datetime.datetime(2019, 3, 4, 7, 0)
+ creation = get_datetime("2019-03-04 7:00")
issue = make_issue(creation=creation, index=5)
- self.assertEqual(issue.response_by, datetime.datetime(2019, 3, 4, 14, 0))
- self.assertEqual(issue.resolution_by, datetime.datetime(2019, 3, 4, 16, 0))
+ self.assertEqual(issue.response_by, get_datetime("2019-03-04 14:00"))
+ self.assertEqual(issue.resolution_by, get_datetime("2019-03-04 16:00"))
# make issue with default SLA after working hours
- creation = datetime.datetime(2019, 3, 4, 20, 0)
+ creation = get_datetime("2019-03-04 20:00")
issue = make_issue(creation, index=6)
- self.assertEqual(issue.response_by, datetime.datetime(2019, 3, 6, 14, 0))
- self.assertEqual(issue.resolution_by, datetime.datetime(2019, 3, 6, 16, 0))
+ self.assertEqual(issue.response_by, get_datetime("2019-03-06 14:00"))
+ self.assertEqual(issue.resolution_by, get_datetime("2019-03-06 16:00"))
# make issue with default SLA next day
- creation = datetime.datetime(2019, 3, 4, 14, 0)
+ creation = get_datetime("2019-03-04 14:00")
issue = make_issue(creation=creation, index=7)
- self.assertEqual(issue.response_by, datetime.datetime(2019, 3, 4, 18, 0))
- self.assertEqual(issue.resolution_by, datetime.datetime(2019, 3, 6, 12, 0))
+ self.assertEqual(issue.response_by, get_datetime("2019-03-04 18:00"))
+ self.assertEqual(issue.resolution_by, get_datetime("2019-03-06 12:00"))
- frappe.flags.current_time = datetime.datetime(2019, 3, 4, 15, 0)
+ frappe.flags.current_time = get_datetime("2019-03-04 15:00")
issue.status = 'Closed'
issue.save()
@@ -75,21 +80,21 @@ class TestIssue(unittest.TestCase):
self.assertEqual(issue.agreement_status, 'Fulfilled')
def test_issue_metrics(self):
- creation = datetime.datetime(2020, 3, 4, 4, 0)
+ creation = get_datetime("2020-03-04 4:00")
issue = make_issue(creation, index=1)
create_communication(issue.name, "test@example.com", "Received", creation)
- creation = datetime.datetime(2020, 3, 4, 4, 15)
+ creation = get_datetime("2020-03-04 4:15")
create_communication(issue.name, "test@admin.com", "Sent", creation)
- creation = datetime.datetime(2020, 3, 4, 5, 0)
+ creation = get_datetime("2020-03-04 5:00")
create_communication(issue.name, "test@example.com", "Received", creation)
- creation = datetime.datetime(2020, 3, 4, 5, 5)
+ creation = get_datetime("2020-03-04 5:05")
create_communication(issue.name, "test@admin.com", "Sent", creation)
- frappe.flags.current_time = datetime.datetime(2020, 3, 4, 5, 5)
+ frappe.flags.current_time = get_datetime("2020-03-04 5:05")
issue.reload()
issue.status = 'Closed'
issue.save()
@@ -99,33 +104,33 @@ class TestIssue(unittest.TestCase):
self.assertEqual(issue.user_resolution_time, 1200)
def test_hold_time_on_replied(self):
- creation = datetime.datetime(2020, 3, 4, 4, 0)
+ creation = get_datetime("2020-03-04 4:00")
issue = make_issue(creation, index=1)
create_communication(issue.name, "test@example.com", "Received", creation)
- creation = datetime.datetime(2020, 3, 4, 4, 15)
+ creation = get_datetime("2020-03-04 4:15")
create_communication(issue.name, "test@admin.com", "Sent", creation)
- frappe.flags.current_time = datetime.datetime(2020, 3, 4, 4, 15)
+ frappe.flags.current_time = get_datetime("2020-03-04 4:15")
issue.reload()
issue.status = 'Replied'
issue.save()
self.assertEqual(issue.on_hold_since, frappe.flags.current_time)
- creation = datetime.datetime(2020, 3, 4, 5, 0)
- frappe.flags.current_time = datetime.datetime(2020, 3, 4, 5, 0)
+ creation = get_datetime("2020-03-04 5:00")
+ frappe.flags.current_time = get_datetime("2020-03-04 5:00")
create_communication(issue.name, "test@example.com", "Received", creation)
issue.reload()
self.assertEqual(flt(issue.total_hold_time, 2), 2700)
- self.assertEqual(issue.resolution_by, datetime.datetime(2020, 3, 4, 16, 45))
+ self.assertEqual(issue.resolution_by, get_datetime("2020-03-04 16:45"))
- creation = datetime.datetime(2020, 3, 4, 5, 5)
+ creation = get_datetime("2020-03-04 5:05")
create_communication(issue.name, "test@admin.com", "Sent", creation)
- frappe.flags.current_time = datetime.datetime(2020, 3, 4, 5, 5)
+ frappe.flags.current_time = get_datetime("2020-03-04 5:05")
issue.reload()
issue.status = 'Closed'
issue.save()
@@ -133,6 +138,223 @@ class TestIssue(unittest.TestCase):
issue.reload()
self.assertEqual(flt(issue.total_hold_time, 2), 2700)
+class TestFirstResponseTime(TestSetUp):
+ # working hours used in all cases: Mon-Fri, 10am to 6pm
+ # all dates are in the mm-dd-yyyy format
+
+ # issue creation and first response are on the same day
+ def test_first_response_time_case1(self):
+ """
+ Test frt when issue creation and first response are during working hours on the same day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 11:00"), get_datetime("06-28-2021 12:00"))
+ self.assertEqual(issue.first_response_time, 3600.0)
+
+ def test_first_response_time_case2(self):
+ """
+ Test frt when issue creation was during working hours, but first response is sent after working hours on the same day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 12:00"), get_datetime("06-28-2021 20:00"))
+ self.assertEqual(issue.first_response_time, 21600.0)
+
+ def test_first_response_time_case3(self):
+ """
+ Test frt when issue creation was before working hours but first response is sent during working hours on the same day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 6:00"), get_datetime("06-28-2021 12:00"))
+ self.assertEqual(issue.first_response_time, 7200.0)
+
+ def test_first_response_time_case4(self):
+ """
+ Test frt when both issue creation and first response were after working hours on the same day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 19:00"), get_datetime("06-28-2021 20:00"))
+ self.assertEqual(issue.first_response_time, 1.0)
+
+ def test_first_response_time_case5(self):
+ """
+ Test frt when both issue creation and first response are on the same day, but it's not a work day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-27-2021 10:00"), get_datetime("06-27-2021 11:00"))
+ self.assertEqual(issue.first_response_time, 1.0)
+
+ # issue creation and first response are on consecutive days
+ def test_first_response_time_case6(self):
+ """
+ Test frt when the issue was created before working hours and the first response is also sent before working hours, but on the next day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 6:00"), get_datetime("06-29-2021 6:00"))
+ self.assertEqual(issue.first_response_time, 28800.0)
+
+ def test_first_response_time_case7(self):
+ """
+ Test frt when the issue was created before working hours and the first response is sent during working hours, but on the next day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 6:00"), get_datetime("06-29-2021 11:00"))
+ self.assertEqual(issue.first_response_time, 32400.0)
+
+ def test_first_response_time_case8(self):
+ """
+ Test frt when the issue was created before working hours and the first response is sent after working hours, but on the next day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 6:00"), get_datetime("06-29-2021 20:00"))
+ self.assertEqual(issue.first_response_time, 57600.0)
+
+ def test_first_response_time_case9(self):
+ """
+ Test frt when the issue was created before working hours and the first response is sent on the next day, which is not a work day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-25-2021 6:00"), get_datetime("06-26-2021 11:00"))
+ self.assertEqual(issue.first_response_time, 28800.0)
+
+ def test_first_response_time_case10(self):
+ """
+ Test frt when the issue was created during working hours and the first response is sent before working hours, but on the next day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 12:00"), get_datetime("06-29-2021 6:00"))
+ self.assertEqual(issue.first_response_time, 21600.0)
+
+ def test_first_response_time_case11(self):
+ """
+ Test frt when the issue was created during working hours and the first response is also sent during working hours, but on the next day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 12:00"), get_datetime("06-29-2021 11:00"))
+ self.assertEqual(issue.first_response_time, 25200.0)
+
+ def test_first_response_time_case12(self):
+ """
+ Test frt when the issue was created during working hours and the first response is sent after working hours, but on the next day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 12:00"), get_datetime("06-29-2021 20:00"))
+ self.assertEqual(issue.first_response_time, 50400.0)
+
+ def test_first_response_time_case13(self):
+ """
+ Test frt when the issue was created during working hours and the first response is sent on the next day, which is not a work day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-25-2021 12:00"), get_datetime("06-26-2021 11:00"))
+ self.assertEqual(issue.first_response_time, 21600.0)
+
+ def test_first_response_time_case14(self):
+ """
+ Test frt when the issue was created after working hours and the first response is sent before working hours, but on the next day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 20:00"), get_datetime("06-29-2021 6:00"))
+ self.assertEqual(issue.first_response_time, 1.0)
+
+ def test_first_response_time_case15(self):
+ """
+ Test frt when the issue was created after working hours and the first response is sent during working hours, but on the next day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 20:00"), get_datetime("06-29-2021 11:00"))
+ self.assertEqual(issue.first_response_time, 3600.0)
+
+ def test_first_response_time_case16(self):
+ """
+ Test frt when the issue was created after working hours and the first response is also sent after working hours, but on the next day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 20:00"), get_datetime("06-29-2021 20:00"))
+ self.assertEqual(issue.first_response_time, 28800.0)
+
+ def test_first_response_time_case17(self):
+ """
+ Test frt when the issue was created after working hours and the first response is sent on the next day, which is not a work day.
+ """
+ issue = create_issue_and_communication(get_datetime("06-25-2021 20:00"), get_datetime("06-26-2021 11:00"))
+ self.assertEqual(issue.first_response_time, 1.0)
+
+ # issue creation and first response are a few days apart
+ def test_first_response_time_case18(self):
+ """
+ Test frt when the issue was created before working hours and the first response is also sent before working hours, but after a few days.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 6:00"), get_datetime("07-01-2021 6:00"))
+ self.assertEqual(issue.first_response_time, 86400.0)
+
+ def test_first_response_time_case19(self):
+ """
+ Test frt when the issue was created before working hours and the first response is sent during working hours, but after a few days.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 6:00"), get_datetime("07-01-2021 11:00"))
+ self.assertEqual(issue.first_response_time, 90000.0)
+
+ def test_first_response_time_case20(self):
+ """
+ Test frt when the issue was created before working hours and the first response is sent after working hours, but after a few days.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 6:00"), get_datetime("07-01-2021 20:00"))
+ self.assertEqual(issue.first_response_time, 115200.0)
+
+ def test_first_response_time_case21(self):
+ """
+ Test frt when the issue was created before working hours and the first response is sent after a few days, on a holiday.
+ """
+ issue = create_issue_and_communication(get_datetime("06-25-2021 6:00"), get_datetime("06-27-2021 11:00"))
+ self.assertEqual(issue.first_response_time, 28800.0)
+
+ def test_first_response_time_case22(self):
+ """
+ Test frt when the issue was created during working hours and the first response is sent before working hours, but after a few days.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 12:00"), get_datetime("07-01-2021 6:00"))
+ self.assertEqual(issue.first_response_time, 79200.0)
+
+ def test_first_response_time_case23(self):
+ """
+ Test frt when the issue was created during working hours and the first response is also sent during working hours, but after a few days.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 12:00"), get_datetime("07-01-2021 11:00"))
+ self.assertEqual(issue.first_response_time, 82800.0)
+
+ def test_first_response_time_case24(self):
+ """
+ Test frt when the issue was created during working hours and the first response is sent after working hours, but after a few days.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 12:00"), get_datetime("07-01-2021 20:00"))
+ self.assertEqual(issue.first_response_time, 108000.0)
+
+ def test_first_response_time_case25(self):
+ """
+ Test frt when the issue was created during working hours and the first response is sent after a few days, on a holiday.
+ """
+ issue = create_issue_and_communication(get_datetime("06-25-2021 12:00"), get_datetime("06-27-2021 11:00"))
+ self.assertEqual(issue.first_response_time, 21600.0)
+
+ def test_first_response_time_case26(self):
+ """
+ Test frt when the issue was created after working hours and the first response is sent before working hours, but after a few days.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 20:00"), get_datetime("07-01-2021 6:00"))
+ self.assertEqual(issue.first_response_time, 57600.0)
+
+ def test_first_response_time_case27(self):
+ """
+ Test frt when the issue was created after working hours and the first response is sent during working hours, but after a few days.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 20:00"), get_datetime("07-01-2021 11:00"))
+ self.assertEqual(issue.first_response_time, 61200.0)
+
+ def test_first_response_time_case28(self):
+ """
+ Test frt when the issue was created after working hours and the first response is also sent after working hours, but after a few days.
+ """
+ issue = create_issue_and_communication(get_datetime("06-28-2021 20:00"), get_datetime("07-01-2021 20:00"))
+ self.assertEqual(issue.first_response_time, 86400.0)
+
+ def test_first_response_time_case29(self):
+ """
+ Test frt when the issue was created after working hours and the first response is sent after a few days, on a holiday.
+ """
+ issue = create_issue_and_communication(get_datetime("06-25-2021 20:00"), get_datetime("06-27-2021 11:00"))
+ self.assertEqual(issue.first_response_time, 1.0)
+
+def create_issue_and_communication(issue_creation, first_responded_on):
+ issue = make_issue(issue_creation, index=1)
+ sender = create_user("test@admin.com")
+ create_communication(issue.name, sender.email, "Sent", first_responded_on)
+ issue.reload()
+
+ return issue
def make_issue(creation=None, customer=None, index=0, priority=None, issue_type=None):
issue = frappe.get_doc({
@@ -185,7 +407,7 @@ def create_territory(territory):
def create_communication(reference_name, sender, sent_or_received, creation):
- issue = frappe.get_doc({
+ communication = frappe.get_doc({
"doctype": "Communication",
"communication_type": "Communication",
"communication_medium": "Email",
@@ -199,4 +421,4 @@ def create_communication(reference_name, sender, sent_or_received, creation):
"creation": creation,
"reference_name": reference_name
})
- issue.save()
+ communication.save()
\ No newline at end of file
diff --git a/erpnext/support/doctype/issue_priority/issue_priority.py b/erpnext/support/doctype/issue_priority/issue_priority.py
index 514b6cc26ba..1a7daf693d2 100644
--- a/erpnext/support/doctype/issue_priority/issue_priority.py
+++ b/erpnext/support/doctype/issue_priority/issue_priority.py
@@ -3,9 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe import _
+
from frappe.model.document import Document
+
class IssuePriority(Document):
pass
diff --git a/erpnext/support/doctype/issue_priority/test_issue_priority.py b/erpnext/support/doctype/issue_priority/test_issue_priority.py
index 618c93ea9d8..fc9ae687c93 100644
--- a/erpnext/support/doctype/issue_priority/test_issue_priority.py
+++ b/erpnext/support/doctype/issue_priority/test_issue_priority.py
@@ -3,9 +3,11 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
+
class TestIssuePriority(unittest.TestCase):
def test_priorities(self):
diff --git a/erpnext/support/doctype/issue_type/issue_type.py b/erpnext/support/doctype/issue_type/issue_type.py
index f95d09cbf3e..089ae28491a 100644
--- a/erpnext/support/doctype/issue_type/issue_type.py
+++ b/erpnext/support/doctype/issue_type/issue_type.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class IssueType(Document):
pass
diff --git a/erpnext/support/doctype/issue_type/test_issue_type.py b/erpnext/support/doctype/issue_type/test_issue_type.py
index 4e3b66a8a4d..06a2de283b5 100644
--- a/erpnext/support/doctype/issue_type/test_issue_type.py
+++ b/erpnext/support/doctype/issue_type/test_issue_type.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestIssueType(unittest.TestCase):
pass
diff --git a/erpnext/support/doctype/pause_sla_on_status/pause_sla_on_status.py b/erpnext/support/doctype/pause_sla_on_status/pause_sla_on_status.py
index a3b547e4801..37c1f2bff7d 100644
--- a/erpnext/support/doctype/pause_sla_on_status/pause_sla_on_status.py
+++ b/erpnext/support/doctype/pause_sla_on_status/pause_sla_on_status.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class PauseSLAOnStatus(Document):
pass
diff --git a/erpnext/support/doctype/service_day/service_day.py b/erpnext/support/doctype/service_day/service_day.py
index 3805b5aa390..da96cad4172 100644
--- a/erpnext/support/doctype/service_day/service_day.py
+++ b/erpnext/support/doctype/service_day/service_day.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ServiceDay(Document):
pass
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.js b/erpnext/support/doctype/service_level_agreement/service_level_agreement.js
index 00060b95300..62784f450f0 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.js
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.js
@@ -2,7 +2,7 @@
// For license information, please see license.txt
frappe.ui.form.on('Service Level Agreement', {
- setup: function(frm) {
+ refresh: function(frm) {
let allow_statuses = [];
const exclude_statuses = ['Open', 'Closed', 'Resolved'];
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
index 11812426d67..0c292d25830 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -5,11 +5,12 @@
from __future__ import unicode_literals
import frappe
-from frappe.model.document import Document
from frappe import _
-from frappe.utils import getdate, get_weekdays, get_link_to_form, nowdate
+from frappe.model.document import Document
+from frappe.utils import get_link_to_form, get_weekdays, getdate, nowdate
from frappe.utils.safe_exec import get_safe_globals
+
class ServiceLevelAgreement(Document):
def validate(self):
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py
index 7e7a405d6e7..22e2c374e12 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py
@@ -1,5 +1,6 @@
from frappe import _
+
def get_data():
return {
'fieldname': 'service_level_agreement',
diff --git a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
index 07ef368cbe3..824ce051906 100644
--- a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
@@ -3,11 +3,14 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
+
from erpnext.hr.doctype.employee_group.test_employee_group import make_employee_group
from erpnext.support.doctype.issue_priority.test_issue_priority import make_priorities
+
class TestServiceLevelAgreement(unittest.TestCase):
def setUp(self):
frappe.db.sql("delete from `tabService Level Agreement`")
@@ -145,16 +148,6 @@ def create_service_level_agreement(default_service_level_agreement, holiday_list
"workday": "Friday",
"start_time": "10:00:00",
"end_time": "18:00:00",
- },
- {
- "workday": "Saturday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- },
- {
- "workday": "Sunday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
}
]
})
diff --git a/erpnext/support/doctype/service_level_priority/service_level_priority.py b/erpnext/support/doctype/service_level_priority/service_level_priority.py
index 0c0fe4a0669..3b2d124a692 100644
--- a/erpnext/support/doctype/service_level_priority/service_level_priority.py
+++ b/erpnext/support/doctype/service_level_priority/service_level_priority.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class ServiceLevelPriority(Document):
pass
diff --git a/erpnext/support/doctype/support_search_source/support_search_source.py b/erpnext/support/doctype/support_search_source/support_search_source.py
index 93e503a4366..50f4714f731 100644
--- a/erpnext/support/doctype/support_search_source/support_search_source.py
+++ b/erpnext/support/doctype/support_search_source/support_search_source.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class SupportSearchSource(Document):
pass
diff --git a/erpnext/support/doctype/support_settings/support_settings.py b/erpnext/support/doctype/support_settings/support_settings.py
index bb3c53ab6db..73aad9d82fd 100644
--- a/erpnext/support/doctype/support_settings/support_settings.py
+++ b/erpnext/support/doctype/support_settings/support_settings.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class SupportSettings(Document):
pass
diff --git a/erpnext/support/doctype/support_settings/test_support_settings.js b/erpnext/support/doctype/support_settings/test_support_settings.js
deleted file mode 100644
index 0787306c3ea..00000000000
--- a/erpnext/support/doctype/support_settings/test_support_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Support Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Support Settings
- () => frappe.tests.make('Support Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/support/doctype/support_settings/test_support_settings.py b/erpnext/support/doctype/support_settings/test_support_settings.py
index 9c47f968119..e9ec070b3aa 100644
--- a/erpnext/support/doctype/support_settings/test_support_settings.py
+++ b/erpnext/support/doctype/support_settings/test_support_settings.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestSupportSettings(unittest.TestCase):
pass
diff --git a/erpnext/support/doctype/warranty_claim/test_warranty_claim.py b/erpnext/support/doctype/warranty_claim/test_warranty_claim.py
index 909675a0d51..dac8f034c30 100644
--- a/erpnext/support/doctype/warranty_claim/test_warranty_claim.py
+++ b/erpnext/support/doctype/warranty_claim/test_warranty_claim.py
@@ -2,9 +2,10 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
test_records = frappe.get_test_records('Warranty Claim')
class TestWarrantyClaim(unittest.TestCase):
diff --git a/erpnext/support/doctype/warranty_claim/warranty_claim.py b/erpnext/support/doctype/warranty_claim/warranty_claim.py
index a20e7a801b0..5fb11242a9d 100644
--- a/erpnext/support/doctype/warranty_claim/warranty_claim.py
+++ b/erpnext/support/doctype/warranty_claim/warranty_claim.py
@@ -3,14 +3,14 @@
from __future__ import unicode_literals
+
import frappe
-from frappe import session, _
-from frappe.utils import today, now_datetime
-
-
+from frappe import _, session
+from frappe.utils import now_datetime
from erpnext.utilities.transaction_base import TransactionBase
+
class WarrantyClaim(TransactionBase):
def get_feed(self):
return _("{0}: From {1}").format(self.status, self.customer_name)
diff --git a/erpnext/support/report/first_response_time_for_issues/first_response_time_for_issues.py b/erpnext/support/report/first_response_time_for_issues/first_response_time_for_issues.py
index 69bf2730d35..cb7a8a629e5 100644
--- a/erpnext/support/report/first_response_time_for_issues/first_response_time_for_issues.py
+++ b/erpnext/support/report/first_response_time_for_issues/first_response_time_for_issues.py
@@ -2,8 +2,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
+
def execute(filters=None):
columns = [
{
diff --git a/erpnext/support/report/issue_analytics/issue_analytics.py b/erpnext/support/report/issue_analytics/issue_analytics.py
index 54fce0b3592..ac8bce104fa 100644
--- a/erpnext/support/report/issue_analytics/issue_analytics.py
+++ b/erpnext/support/report/issue_analytics/issue_analytics.py
@@ -2,13 +2,17 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
-from six import iteritems
+
+import frappe
from frappe import _, scrub
-from frappe.utils import getdate, flt, add_to_date, add_days
+from frappe.utils import add_days, add_to_date, flt, getdate
+from six import iteritems
+
from erpnext.accounts.utils import get_fiscal_year
+
def execute(filters=None):
return IssueAnalytics(filters).run()
@@ -103,7 +107,7 @@ class IssueAnalytics(object):
return period
def get_period_date_ranges(self):
- from dateutil.relativedelta import relativedelta, MO
+ from dateutil.relativedelta import MO, relativedelta
from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date)
increment = {
diff --git a/erpnext/support/report/issue_analytics/test_issue_analytics.py b/erpnext/support/report/issue_analytics/test_issue_analytics.py
index a9d961a4592..1de03ab28dc 100644
--- a/erpnext/support/report/issue_analytics/test_issue_analytics.py
+++ b/erpnext/support/report/issue_analytics/test_issue_analytics.py
@@ -1,11 +1,16 @@
from __future__ import unicode_literals
+
import unittest
+
import frappe
-from frappe.utils import getdate, add_months
-from erpnext.support.report.issue_analytics.issue_analytics import execute
-from erpnext.support.doctype.issue.test_issue import make_issue, create_customer
-from erpnext.support.doctype.service_level_agreement.test_service_level_agreement import create_service_level_agreements_for_issues
from frappe.desk.form.assign_to import add as add_assignment
+from frappe.utils import add_months, getdate
+
+from erpnext.support.doctype.issue.test_issue import create_customer, make_issue
+from erpnext.support.doctype.service_level_agreement.test_service_level_agreement import (
+ create_service_level_agreements_for_issues,
+)
+from erpnext.support.report.issue_analytics.issue_analytics import execute
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
diff --git a/erpnext/support/report/issue_summary/issue_summary.py b/erpnext/support/report/issue_summary/issue_summary.py
index 7c4af39f104..04819966095 100644
--- a/erpnext/support/report/issue_summary/issue_summary.py
+++ b/erpnext/support/report/issue_summary/issue_summary.py
@@ -2,11 +2,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
-from six import iteritems
+
+import frappe
from frappe import _, scrub
from frappe.utils import flt
+from six import iteritems
+
def execute(filters=None):
return IssueSummary(filters).run()
diff --git a/erpnext/support/report/support_hour_distribution/support_hour_distribution.py b/erpnext/support/report/support_hour_distribution/support_hour_distribution.py
index 08802b4f5ea..c0bec3c9552 100644
--- a/erpnext/support/report/support_hour_distribution/support_hour_distribution.py
+++ b/erpnext/support/report/support_hour_distribution/support_hour_distribution.py
@@ -2,9 +2,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import add_to_date, getdate, get_datetime
+from frappe.utils import add_to_date, get_datetime, getdate
from six import iteritems
time_slots = {
diff --git a/erpnext/support/web_form/issues/issues.py b/erpnext/support/web_form/issues/issues.py
index 2334f8b26d8..f57de916dd1 100644
--- a/erpnext/support/web_form/issues/issues.py
+++ b/erpnext/support/web_form/issues/issues.py
@@ -1,6 +1,5 @@
from __future__ import unicode_literals
-import frappe
def get_context(context):
# do your magic here
diff --git a/erpnext/telephony/doctype/call_log/call_log.py b/erpnext/telephony/doctype/call_log/call_log.py
index 6f8e4116956..0c1ea1657a7 100644
--- a/erpnext/telephony/doctype/call_log/call_log.py
+++ b/erpnext/telephony/doctype/call_log/call_log.py
@@ -3,14 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.model.document import Document
-from erpnext.crm.doctype.utils import get_scheduled_employees_for_popup, strip_number
from frappe.contacts.doctype.contact.contact import get_contact_with_phone_number
from frappe.core.doctype.dynamic_link.dynamic_link import deduplicate_dynamic_links
+from frappe.model.document import Document
from erpnext.crm.doctype.lead.lead import get_lead_with_phone_number
+from erpnext.crm.doctype.utils import get_scheduled_employees_for_popup, strip_number
END_CALL_STATUSES = ['No Answer', 'Completed', 'Busy', 'Failed']
ONGOING_CALL_STATUSES = ['Ringing', 'In Progress']
diff --git a/erpnext/telephony/doctype/call_log/test_call_log.py b/erpnext/telephony/doctype/call_log/test_call_log.py
index faa63041ba3..f8d458d5415 100644
--- a/erpnext/telephony/doctype/call_log/test_call_log.py
+++ b/erpnext/telephony/doctype/call_log/test_call_log.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestCallLog(unittest.TestCase):
pass
diff --git a/erpnext/telephony/doctype/incoming_call_handling_schedule/incoming_call_handling_schedule.py b/erpnext/telephony/doctype/incoming_call_handling_schedule/incoming_call_handling_schedule.py
index fcf29745e2b..f48c808331d 100644
--- a/erpnext/telephony/doctype/incoming_call_handling_schedule/incoming_call_handling_schedule.py
+++ b/erpnext/telephony/doctype/incoming_call_handling_schedule/incoming_call_handling_schedule.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class IncomingCallHandlingSchedule(Document):
pass
diff --git a/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.py b/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.py
index 2b2008a8ab7..faeff9024da 100644
--- a/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.py
+++ b/erpnext/telephony/doctype/incoming_call_settings/incoming_call_settings.py
@@ -3,11 +3,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
+
from datetime import datetime
from typing import Tuple
+
+import frappe
from frappe import _
+from frappe.model.document import Document
+
class IncomingCallSettings(Document):
def validate(self):
diff --git a/erpnext/telephony/doctype/incoming_call_settings/test_incoming_call_settings.py b/erpnext/telephony/doctype/incoming_call_settings/test_incoming_call_settings.py
index c058c117b32..243e3d9aeab 100644
--- a/erpnext/telephony/doctype/incoming_call_settings/test_incoming_call_settings.py
+++ b/erpnext/telephony/doctype/incoming_call_settings/test_incoming_call_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestIncomingCallSettings(unittest.TestCase):
pass
diff --git a/erpnext/telephony/doctype/voice_call_settings/test_voice_call_settings.py b/erpnext/telephony/doctype/voice_call_settings/test_voice_call_settings.py
index 85d6adda093..810b717ae61 100644
--- a/erpnext/telephony/doctype/voice_call_settings/test_voice_call_settings.py
+++ b/erpnext/telephony/doctype/voice_call_settings/test_voice_call_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestVoiceCallSettings(unittest.TestCase):
pass
diff --git a/erpnext/telephony/doctype/voice_call_settings/voice_call_settings.py b/erpnext/telephony/doctype/voice_call_settings/voice_call_settings.py
index ad3bbf1784d..fc0e338c15e 100644
--- a/erpnext/telephony/doctype/voice_call_settings/voice_call_settings.py
+++ b/erpnext/telephony/doctype/voice_call_settings/voice_call_settings.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class VoiceCallSettings(Document):
pass
diff --git a/erpnext/templates/generators/item/item.html b/erpnext/templates/generators/item/item.html
index 663ea79f4ec..89436343c7a 100644
--- a/erpnext/templates/generators/item/item.html
+++ b/erpnext/templates/generators/item/item.html
@@ -1,4 +1,5 @@
{% extends "templates/web.html" %}
+{% from "erpnext/templates/includes/macros.html" import recommended_item_row %}
{% block title %} {{ title }} {% endblock %}
@@ -9,21 +10,65 @@
{% endblock %}
{% block page_content %}
-
+
{% from "erpnext/templates/includes/macros.html" import product_image %}
+
{% include "templates/generators/item/item_image.html" %}
{% include "templates/generators/item/item_details.html" %}
-
- {% include "templates/generators/item/item_specifications.html" %}
-
- {{ doc.website_content or '' }}
+
+
+
+ {% set show_recommended_items = recommended_items and shopping_cart.cart_settings.enable_recommendations %}
+ {% set info_col = 'col-9' if show_recommended_items else 'col-12' %}
+
+ {% set padding_top = 'pt-0' if (show_tabs and tabs) else '' %}
+
+
+
+
+
+ {% if show_tabs and tabs %}
+
+
+ {{ web_block("Section with Tabs", values=tabs, add_container=0,
+ add_top_padding=0, add_bottom_padding=0)
+ }}
+
+ {% elif website_specifications %}
+ {% include "templates/generators/item/item_specifications.html"%}
+ {% endif %}
+
+
+ {{ doc.website_content or '' }}
+
+
+ {% if shopping_cart.cart_settings.enable_reviews and not doc.has_variants %}
+ {% include "templates/generators/item/item_reviews.html"%}
+ {% endif %}
+
+
+
+
+
+ {% if show_recommended_items %}
+
+
+
+ {% for item in recommended_items %}
+ {{ recommended_item_row(item) }}
+ {% endfor %}
+
+
+ {% endif %}
+
+
{% endblock %}
{% block base_scripts %}
diff --git a/erpnext/templates/generators/item/item_add_to_cart.html b/erpnext/templates/generators/item/item_add_to_cart.html
index 167c848eff1..8000a2446be 100644
--- a/erpnext/templates/generators/item/item_add_to_cart.html
+++ b/erpnext/templates/generators/item/item_add_to_cart.html
@@ -5,54 +5,115 @@
+
{% if cart_settings.show_price and product_info.price %}
-
- {{ product_info.price.formatted_price_sales_uom }}
- ({{ product_info.price.formatted_price }} / {{ product_info.uom }})
-
+ {% set price_info = product_info.price %}
+
+
+
+ {{ price_info.formatted_price_sales_uom }}
+
+
+ {% if price_info.formatted_mrp %}
+
+ MRP {{ price_info.formatted_mrp }}
+
+
+ -{{ price_info.get("formatted_discount_percent") or price_info.get("formatted_discount_rate")}}
+
+ {% endif %}
+
+
+
+ ({{ price_info.formatted_price }} / {{ product_info.uom }})
+
+
{% else %}
{{ _("UOM") }} : {{ product_info.uom }}
{% endif %}
{% if cart_settings.show_stock_availability %}
-
- {% if product_info.in_stock == 0 %}
-
- {{ _('Not in stock') }}
-
+
+ {% if product_info.get("on_backorder") %}
+
+ {{ _('Available on backorder') }}
+
+ {% elif product_info.in_stock == 0 %}
+
+ {{ _('Out of stock') }}
+
{% elif product_info.in_stock == 1 %}
-
- {{ _('In stock') }}
- {% if product_info.show_stock_qty and product_info.stock_qty %}
- ({{ product_info.stock_qty[0][0] }})
- {% endif %}
-
+
+ {{ _('In stock') }}
+ {% if product_info.show_stock_qty and product_info.stock_qty %}
+ ({{ product_info.stock_qty[0][0] }})
+ {% endif %}
+
{% endif %}
{% endif %}
-
- {% if product_info.price and (cart_settings.allow_items_not_in_stock or product_info.in_stock) %}
-
- {{ _("View in Cart") }}
-
-
-
-
-
+
+
+ {% if doc.offers %}
+
+
+
+
+
+ Available Offers
+
+
+ {% for offer in doc.offers %}
+
+
+
+
+
+
+
-
- {{ _("Add to Cart") }}
-
- {% endif %}
- {% if cart_settings.show_contact_us_button %}
- {% include "templates/generators/item/item_inquiry.html" %}
- {% endif %}
+
+
+ {{ _(offer.offer_title) }}:
+ {{ _(offer.offer_subtitle) if offer.offer_subtitle else '' }}
+
+ {{ _("More") }}
+
+
+
+ {% endfor %}
+
+ {% endif %}
+
+
+
+
+
+ {% if product_info.price and (cart_settings.allow_items_not_in_stock or product_info.in_stock) %}
+
+ {{ _("View in Cart") if cart_settings.enable_checkout else _("View in Quote") }}
+
+
+
+
+
+
+
+ {{ _("Add to Cart") if cart_settings.enable_checkout else _("Add to Quote") }}
+
+ {% endif %}
+
+
+ {% if cart_settings.show_contact_us_button %}
+ {% include "templates/generators/item/item_inquiry.html" %}
+ {% endif %}
+
@@ -60,10 +121,11 @@
{% endif %}
diff --git a/erpnext/templates/generators/item/item_configure.html b/erpnext/templates/generators/item/item_configure.html
index b61ac73072d..fcab594402b 100644
--- a/erpnext/templates/generators/item/item_configure.html
+++ b/erpnext/templates/generators/item/item_configure.html
@@ -3,11 +3,11 @@
{% if cart_settings.enable_variants | int %}
-
- {{ _('Configure') }}
+ {{ _('Select Variant') }}
{% endif %}
{% if cart_settings.show_contact_us_button %}
diff --git a/erpnext/templates/generators/item/item_configure.js b/erpnext/templates/generators/item/item_configure.js
index 8eadb842899..b5f92989ef4 100644
--- a/erpnext/templates/generators/item/item_configure.js
+++ b/erpnext/templates/generators/item/item_configure.js
@@ -29,7 +29,7 @@ class ItemConfigure {
});
this.dialog = new frappe.ui.Dialog({
- title: __('Configure {0}', [this.item_name]),
+ title: __('Select Variant for {0}', [this.item_name]),
fields,
on_hide: () => {
set_continue_configuration();
@@ -201,7 +201,7 @@ class ItemConfigure {
${frappe.utils.icon('assets', 'md')}
- ${__("Add to Cart")}s
+ ${__("Add to Cart")}
` : '';
@@ -214,7 +214,7 @@ class ItemConfigure {
? `
${one_item}
- ${product_info && product_info.price
+ ${product_info && product_info.price && !$.isEmptyObject()
? '(' + product_info.price.formatted_price_sales_uom + ')'
: ''
}
@@ -247,7 +247,7 @@ class ItemConfigure {
const additional_notes = Object.keys(this.range_values || {}).map(attribute => {
return `${attribute}: ${this.range_values[attribute]}`;
}).join('\n');
- erpnext.shopping_cart.update_cart({
+ erpnext.e_commerce.shopping_cart.update_cart({
item_code,
additional_notes,
qty: 1
@@ -280,14 +280,14 @@ class ItemConfigure {
}
get_next_attribute_and_values(selected_attributes) {
- return this.call('erpnext.portal.product_configurator.utils.get_next_attribute_and_values', {
+ return this.call('erpnext.e_commerce.variant_selector.utils.get_next_attribute_and_values', {
item_code: this.item_code,
selected_attributes
});
}
get_attributes_and_values() {
- return this.call('erpnext.portal.product_configurator.utils.get_attributes_and_values', {
+ return this.call('erpnext.e_commerce.variant_selector.utils.get_attributes_and_values', {
item_code: this.item_code
});
}
@@ -311,9 +311,9 @@ function set_continue_configuration() {
const { itemCode } = $btn_configure.data();
if (localStorage.getItem(`configure:${itemCode}`)) {
- $btn_configure.text(__('Continue Configuration'));
+ $btn_configure.text(__('Continue Selection'));
} else {
- $btn_configure.text(__('Configure'));
+ $btn_configure.text(__('Select Variant'));
}
}
diff --git a/erpnext/templates/generators/item/item_details.html b/erpnext/templates/generators/item/item_details.html
index 3b775858276..028936bf5f7 100644
--- a/erpnext/templates/generators/item/item_details.html
+++ b/erpnext/templates/generators/item/item_details.html
@@ -1,27 +1,63 @@
-
-
-
- {{ item_name }}
-
-
- {{ _("Item Code") }}:
- {{ doc.name }}
-
-{% if has_variants %}
-
- {% include "templates/generators/item/item_configure.html" %}
-{% else %}
-
- {% include "templates/generators/item/item_add_to_cart.html" %}
-{% endif %}
-
-
-{% if frappe.utils.strip_html(doc.web_long_description or '') %}
- {{ doc.web_long_description | safe }}
-{% elif frappe.utils.strip_html(doc.description or '') %}
- {{ doc.description | safe }}
-{% else %}
- {{ _("No description given") }}
-{% endif %}
-
+{% set width_class = "expand" if not slides else "" %}
+{% set cart_settings = shopping_cart.cart_settings %}
+{% set product_info = shopping_cart.product_info %}
+{% set price_info = product_info.get('price') or {} %}
+
+
+
+
+
+ {{ doc.web_item_name }}
+
+
+
+ {% if cart_settings.enable_wishlist %}
+
+
+
+
+
+ {% endif %}
+
+
+
+
+ {{ _(doc.item_group) }}
+
+
+ {{ _("Item Code") }}:
+
+ {{ doc.item_code }}
+
+ {% if has_variants %}
+
+ {% include "templates/generators/item/item_configure.html" %}
+ {% else %}
+
+ {% include "templates/generators/item/item_add_to_cart.html" %}
+ {% endif %}
+
+
+ {% if frappe.utils.strip_html(doc.web_long_description or '') %}
+ {{ doc.web_long_description | safe }}
+ {% elif frappe.utils.strip_html(doc.description or '') %}
+ {{ doc.description | safe }}
+ {% else %}
+ {{ "" }}
+ {% endif %}
+
+
+{% block base_scripts %}
+
+
+{% endblock %}
+
+
\ No newline at end of file
diff --git a/erpnext/templates/generators/item/item_image.html b/erpnext/templates/generators/item/item_image.html
index 39a30d0d7cb..930bb7a67d6 100644
--- a/erpnext/templates/generators/item/item_image.html
+++ b/erpnext/templates/generators/item/item_image.html
@@ -1,29 +1,30 @@
-
+{% set column_size = 5 if slides else 4 %}
+
{% if slides %}
-
- {% for item in slides %}
-
- {% endfor %}
-
- {{ product_image(slides[0].image, 'product-image') }}
-
-
+ $('.item-slideshow-image').removeClass('active');
+ $img.addClass('active');
+ });
+ })
+
{% else %}
- {{ product_image(website_image or image or 'no-image.jpg', alt=website_image_alt or item_name) }}
+ {{ product_image(doc.website_image or doc.image, alt=doc.website_image_alt or doc.item_name) }}
{% endif %}
diff --git a/erpnext/templates/generators/item/item_inquiry.html b/erpnext/templates/generators/item/item_inquiry.html
index 83653b68218..af636f1582b 100644
--- a/erpnext/templates/generators/item/item_inquiry.html
+++ b/erpnext/templates/generators/item/item_inquiry.html
@@ -1,9 +1,9 @@
{% if shopping_cart and shopping_cart.cart_settings.enabled %}
{% set cart_settings = shopping_cart.cart_settings %}
- {% if cart_settings.show_contact_us_button | int %}
-
- {{ _('Contact Us') }}
-
+ {% if cart_settings.show_contact_us_button | int %}
+
+ {{ _('Contact Us') }}
+
{% endif %}
diff --git a/erpnext/templates/generators/item/item_specifications.html b/erpnext/templates/generators/item/item_specifications.html
index d4dfa8e591a..6a6475c9c54 100644
--- a/erpnext/templates/generators/item/item_specifications.html
+++ b/erpnext/templates/generators/item/item_specifications.html
@@ -1,11 +1,17 @@
-{% if doc.website_specifications -%}
-
-
-
- {% for d in doc.website_specifications -%}
+
+{% if website_specifications %}
+
+
+ {% if not show_tabs %}
+
+ Product Details
+
+ {% endif %}
+
+ {% for d in website_specifications -%}
- {{ d.label }}
- {{ d.description }}
+ {{ d.label }}
+ {{ d.description }}
{%- endfor %}
diff --git a/erpnext/templates/generators/item_group.html b/erpnext/templates/generators/item_group.html
index b5f18ba66d1..218481581c5 100644
--- a/erpnext/templates/generators/item_group.html
+++ b/erpnext/templates/generators/item_group.html
@@ -1,17 +1,25 @@
+{% from "erpnext/templates/includes/macros.html" import field_filter_section, attribute_filter_section, discount_range_filters %}
{% extends "templates/web.html" %}
{% block header %}
-
+
{{ _(item_group_name) }}
{% endblock header %}
{% block script %}
{% endblock %}
+{% block breadcrumbs %}
+
+ {% include "templates/includes/breadcrumbs.html" %}
+
+{% endblock %}
+
{% block page_content %}
-
+
- {% if slideshow %}
+ {% if slideshow %}
{{ web_block(
"Hero Slider",
values=slideshow,
@@ -20,91 +28,28 @@
add_bottom_padding=0,
) }}
{% endif %}
-
{{ title }}
- {% if description %}
+
+ {% if description %}
{{ description or ""}}
{% endif %}
-
-
- {% if items %}
- {% for item in items %}
- {% include "erpnext/www/all-products/item_row.html" %}
- {% endfor %}
- {% else %}
- {% include "erpnext/www/all-products/not_found.html" %}
- {% endif %}
-
+
+
+
- {% for field_filter in field_filters %}
- {%- set item_field = field_filter[0] %}
- {%- set values = field_filter[1] %}
-
-
{{ item_field.label }}
+
+ {{ field_filter_section(field_filters) }}
- {% if values | len > 20 %}
-
-
- {% endif %}
+
+ {{ attribute_filter_section(attribute_filters) }}
- {% if values %}
-
- {% for value in values %}
-
-
-
- {{ value }}
-
-
- {% endfor %}
-
- {% else %}
-
{{ _('No values') }}
- {% endif %}
-
- {% endfor %}
-
- {% for attribute in attribute_filters %}
-
-
{{ attribute.name}}
- {% if values | len > 20 %}
-
-
- {% endif %}
-
- {% if attribute.item_attribute_values %}
-
- {% for attr_value in attribute.item_attribute_values %}
-
-
-
- {{ attr_value.attribute_value }}
-
-
- {% endfor %}
-
- {% else %}
-
{{ _('No values') }}
- {% endif %}
-
- {% endfor %}
-
-
-
-
- {% if frappe.form_dict.start|int > 0 %}
-
- {{ _("Prev") }}
-
- {% endif %}
- {% if items|length >= page_length %}
-
- {{ _("Next") }}
-
- {% endif %}
-
-
-
-
{% endblock %}
diff --git a/erpnext/templates/includes/cart.js b/erpnext/templates/includes/cart.js
index c390cd171d3..0c970450be6 100644
--- a/erpnext/templates/includes/cart.js
+++ b/erpnext/templates/includes/cart.js
@@ -4,8 +4,8 @@
// js inside blog page
// shopping cart
-frappe.provide("erpnext.shopping_cart");
-var shopping_cart = erpnext.shopping_cart;
+frappe.provide("erpnext.e_commerce.shopping_cart");
+var shopping_cart = erpnext.e_commerce.shopping_cart;
$.extend(shopping_cart, {
show_error: function(title, text) {
@@ -18,8 +18,8 @@ $.extend(shopping_cart, {
shopping_cart.bind_place_order();
shopping_cart.bind_request_quotation();
shopping_cart.bind_change_qty();
+ shopping_cart.bind_remove_cart_item();
shopping_cart.bind_change_notes();
- shopping_cart.bind_dropdown_cart_buttons();
shopping_cart.bind_coupon_code();
},
@@ -48,7 +48,7 @@ $.extend(shopping_cart, {
const address_name = $card.closest('[data-address-name]').attr('data-address-name');
frappe.call({
type: "POST",
- method: "erpnext.shopping_cart.cart.update_cart_address",
+ method: "erpnext.e_commerce.shopping_cart.cart.update_cart_address",
freeze: true,
args: {
address_type,
@@ -57,7 +57,7 @@ $.extend(shopping_cart, {
callback: function(r) {
d.hide();
if (!r.exc) {
- $(".cart-tax-items").html(r.message.taxes);
+ $(".cart-tax-items").html(r.message.total);
shopping_cart.parent.find(
`.address-container[data-address-type="${address_type}"]`
).html(r.message.address);
@@ -129,8 +129,14 @@ $.extend(shopping_cart, {
}
}
input.val(newVal);
+
+ let notes = input.closest("td").siblings().find(".notes").text().trim();
var item_code = input.attr("data-item-code");
- shopping_cart.shopping_cart_update({item_code, qty: newVal});
+ shopping_cart.shopping_cart_update({
+ item_code,
+ qty: newVal,
+ additional_notes: notes
+ });
});
},
@@ -148,6 +154,18 @@ $.extend(shopping_cart, {
});
},
+ bind_remove_cart_item: function() {
+ $(".cart-items").on("click", ".remove-cart-item", (e) => {
+ const $remove_cart_item_btn = $(e.currentTarget);
+ var item_code = $remove_cart_item_btn.data("item-code");
+
+ shopping_cart.shopping_cart_update({
+ item_code: item_code,
+ qty: 0
+ });
+ });
+ },
+
render_tax_row: function($cart_taxes, doc, shipping_rules) {
var shipping_selector;
if(shipping_rules) {
@@ -185,7 +203,7 @@ $.extend(shopping_cart, {
return frappe.call({
btn: btn,
type: "POST",
- method: "erpnext.shopping_cart.cart.apply_shipping_rule",
+ method: "erpnext.e_commerce.shopping_cart.cart.apply_shipping_rule",
args: { shipping_rule: rule },
callback: function(r) {
if(!r.exc) {
@@ -196,12 +214,15 @@ $.extend(shopping_cart, {
},
place_order: function(btn) {
+ shopping_cart.freeze();
+
return frappe.call({
type: "POST",
- method: "erpnext.shopping_cart.cart.place_order",
+ method: "erpnext.e_commerce.shopping_cart.cart.place_order",
btn: btn,
callback: function(r) {
if(r.exc) {
+ shopping_cart.unfreeze();
var msg = "";
if(r._server_messages) {
msg = JSON.parse(r._server_messages || []).join("
");
@@ -212,7 +233,6 @@ $.extend(shopping_cart, {
.html(msg || frappe._("Something went wrong!"))
.toggle(true);
} else {
- $('.cart-container table').hide();
$(btn).hide();
window.location.href = '/orders/' + encodeURIComponent(r.message);
}
@@ -221,12 +241,15 @@ $.extend(shopping_cart, {
},
request_quotation: function(btn) {
+ shopping_cart.freeze();
+
return frappe.call({
type: "POST",
- method: "erpnext.shopping_cart.cart.request_for_quotation",
+ method: "erpnext.e_commerce.shopping_cart.cart.request_for_quotation",
btn: btn,
callback: function(r) {
if(r.exc) {
+ shopping_cart.unfreeze();
var msg = "";
if(r._server_messages) {
msg = JSON.parse(r._server_messages || []).join("
");
@@ -237,7 +260,6 @@ $.extend(shopping_cart, {
.html(msg || frappe._("Something went wrong!"))
.toggle(true);
} else {
- $('.cart-container table').hide();
$(btn).hide();
window.location.href = '/quotations/' + encodeURIComponent(r.message);
}
@@ -254,7 +276,7 @@ $.extend(shopping_cart, {
apply_coupon_code: function(btn) {
return frappe.call({
type: "POST",
- method: "erpnext.shopping_cart.cart.apply_coupon_code",
+ method: "erpnext.e_commerce.shopping_cart.cart.apply_coupon_code",
btn: btn,
args : {
applied_code : $('.txtcoupon').val(),
diff --git a/erpnext/templates/includes/cart/address_card.html b/erpnext/templates/includes/cart/address_card.html
index 667144bd878..830ed649f5f 100644
--- a/erpnext/templates/includes/cart/address_card.html
+++ b/erpnext/templates/includes/cart/address_card.html
@@ -1,5 +1,5 @@
-
+
{{ _('Change') }}
diff --git a/erpnext/templates/includes/cart/cart_address.html b/erpnext/templates/includes/cart/cart_address.html
index 4482bc10cf7..cf600173731 100644
--- a/erpnext/templates/includes/cart/cart_address.html
+++ b/erpnext/templates/includes/cart/cart_address.html
@@ -4,18 +4,14 @@
{% set select_address = True %}
{% endif %}
-{% set show_coupon_code = frappe.db.get_single_value('Shopping Cart Settings', 'show_apply_coupon_code_in_website') %}
-{% if show_coupon_code == 1%}
-
-
-
- {{ _("Apply Coupon Code") }}
-
-
-
-{% endif %}
-
{{ _("Shipping Address") }}
+
+
{% for address in shipping_addresses %}
{% if doc.shipping_address_name == address.name %}
@@ -27,26 +23,36 @@
{% endif %}
{% endfor %}
+
+
-
- {{ _('Billing Address is same as Shipping Address') }}
+
+ {{ _('Billing Address is same as Shipping Address') }}
-
-
{{ _("Billing Address") }}
-
- {% for address in billing_addresses %}
- {% if doc.customer_address == address.name %}
-
-
- {% include "templates/includes/cart/address_card.html" %}
-
+
+{% if billing_addresses %}
+
+
- {% endif %}
- {% endfor %}
-
-
{{ _("Add a new address") }}
+
+
+ {% for address in billing_addresses %}
+ {% if doc.customer_address == address.name %}
+
+
+ {% include "templates/includes/cart/address_card.html" %}
+
+
+ {% endif %}
+ {% endfor %}
+
+{% endif %}
-->
\ No newline at end of file
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html
index be0d47f3715..889cf1ab38d 100644
--- a/erpnext/templates/includes/macros.html
+++ b/erpnext/templates/includes/macros.html
@@ -7,9 +7,15 @@
{% endmacro %}
-{% macro product_image(website_image, css_class="product-image", alt="") %}
-
-
+{% macro product_image(website_image, css_class="product-image", alt="", no_border=False) %}
+
+ {% if website_image %}
+
+ {% else %}
+
+ {{ frappe.utils.get_abbr(alt) or "NA" }}
+
+ {% endif %}
{% endmacro %}
@@ -59,65 +65,335 @@
{% endmacro %}
-{%- macro item_card(title, image, url, description, rate, category, is_featured=False, is_full_width=False, align="Left") -%}
+{%- macro item_card(item, is_featured=False, is_full_width=False, align="Left") -%}
{%- set align_items_class = resolve_class({
'align-items-end': align == 'Right',
'align-items-center': align == 'Center',
'align-items-start': align == 'Left',
}) -%}
{%- set col_size = 3 if is_full_width else 4 -%}
+{%- set title = item.web_item_name or item.item_name or item.item_code -%}
+{%- set title = title[:50] + "..." if title|len > 50 else title -%}
+{%- set image = item.website_image or item.image -%}
+{%- set description = item.website_description or item.description-%}
+
{% if is_featured %}
-
+
{% if image %}
-
+
- {{ item_card_body(title, description, url, rate, category, is_featured, align) }}
+ {{ item_card_body(title, description, item, is_featured, align) }}
{% else %}
- {{ item_card_body(title, description, url, rate, category, is_featured, align) }}
+ {{ item_card_body(title, description, item, is_featured, align) }}
{% endif %}
{% else %}
-
+
{% if image %}
-
-
-
+
{% else %}
-
- {{ frappe.utils.get_abbr(title) }}
-
+
+
+ {{ frappe.utils.get_abbr(title) }}
+
+
{% endif %}
- {{ item_card_body(title, description, url, rate, category, is_featured, align) }}
+ {{ item_card_body(title, description, item, is_featured, align) }}
{% endif %}
{%- endmacro -%}
-{%- macro item_card_body(title, description, url, rate, category, is_featured, align) -%}
+{%- macro item_card_body(title, description, item, is_featured, align) -%}
{%- set align_class = resolve_class({
'text-right': align == 'Right',
'text-center': align == 'Center' and not is_featured,
'text-left': align == 'Left' or is_featured,
}) -%}
-
-
{{ title or '' }}
+
+
{% if is_featured %}
-
{{ rate or '' }}
-
{{ description or '' }}
+
+ {{ description or '' }}
+
{% else %}
-
{{ category or '' }}
-
{{ rate or '' }}
+
{{ item.item_group or '' }}
{% endif %}
-
+{%- endmacro -%}
+
+
+{%- macro wishlist_card(item, settings) %}
+{%- set title = item.web_item_name or ''-%}
+{%- set title = title[:90] + "..." if title|len > 90 else title -%}
+
+
+
+
+ {{ wishlist_card_body(item, title, settings) }}
+
+
+{%- endmacro -%}
+
+{%- macro wishlist_card_body(item, title, settings) %}
+
+
+
{{ title or ''}}
+
{{ item.item_group or '' }}
+
+
+ {{ item.get("formatted_price") or '' }}
+
+ {% if item.get("formatted_mrp") %}
+
+ {{ item.formatted_mrp }}
+
+
+ {{ item.discount }} OFF
+
+ {% endif %}
+
+
+ {% if (item.available and settings.show_stock_availability) or (not settings.show_stock_availability) %}
+
+
+
+
+
+
+
+ {{ _("Move to Cart") }}
+
+ {% else %}
+
+ {{ _("Out of stock") }}
+
+ {% endif %}
+
+{%- endmacro -%}
+
+{%- macro ratings_with_title(avg_rating, title, size, rating_header_class, for_summary=False) -%}
+
+
+
+ {% for i in range(1,6) %}
+ {% set fill_class = 'star-click' if i <= avg_rating else '' %}
+
+
+
+ {% endfor %}
+
+
+{%- endmacro -%}
+
+{%- macro ratings_summary(reviews, reviews_per_rating, average_rating, average_whole_rating, for_summary=False, total_reviews=None)-%}
+
+
+
+ {{ average_rating or 0 }}
+
+
+ {{ frappe.utils.cstr(total_reviews or 0) + " " + _("ratings") }}
+
+
+
+ {% if reviews %}
+ {% set rating_title = frappe.utils.cstr(average_rating) + " " + _("out of 5") if not for_summary else ''%}
+ {{ ratings_with_title(average_whole_rating, rating_title, "md", "rating-summary-title", for_summary) }}
+ {% endif %}
+
+
{{ frappe.utils.cstr(average_rating or 0) + " " + _("out of 5") }}
+
+
+
+
+ {% for percent in reviews_per_rating %}
+
+ {{ loop.index }} star
+
+
+ {% endfor %}
+
+
+{%- endmacro -%}
+
+{%- macro user_review(reviews)-%}
+
+
+ {% for review in reviews %}
+
+ {{ ratings_with_title(review.rating, _(review.review_title), "sm", "user-review-title") }}
+
+
+
+ {{ _(review.comment) }}
+
+
+
+
+ {{ _(review.customer) }}
+
+ {{ review.published_on }}
+
+
+ {% endfor %}
+
+{%- endmacro -%}
+
+{%- macro field_filter_section(filters)-%}
+{% for field_filter in filters %}
+ {%- set item_field = field_filter[0] %}
+ {%- set values = field_filter[1] %}
+
+
{{ item_field.label }}
+
+ {% if values | len > 20 %}
+
+
+ {% endif %}
+
+ {% if values %}
+
+ {% for value in values %}
+
+
+
+ {{ value }}
+
+
+ {% endfor %}
+
+ {% else %}
+
{{ _('No values') }}
+ {% endif %}
+
+{% endfor %}
+{%- endmacro -%}
+
+{%- macro attribute_filter_section(filters)-%}
+{% for attribute in filters %}
+
+
{{ attribute.name}}
+ {% if values | len > 20 %}
+
+
+ {% endif %}
+
+ {% if attribute.item_attribute_values %}
+
+ {% for attr_value in attribute.item_attribute_values %}
+
+
+
+ {{ attr_value.attribute_value }}
+
+
+ {% endfor %}
+
+ {% else %}
+
{{ _('No values') }}
+ {% endif %}
+
+{% endfor %}
+{%- endmacro -%}
+
+{%- macro recommended_item_row(item)-%}
+
+
+ {% if item.website_item_thumbnail %}
+ {{ product_image(item.website_item_thumbnail, css_class="r-product-image", alt="item.website_item_name", no_border=True) }}
+ {% else %}
+
+ {{ frappe.utils.get_abbr(item.website_item_name) or "NA" }}
+
+ {% endif %}
+
+
+
{%- endmacro -%}
diff --git a/erpnext/templates/includes/navbar/navbar_items.html b/erpnext/templates/includes/navbar/navbar_items.html
index 291220629c9..327552117bf 100644
--- a/erpnext/templates/includes/navbar/navbar_items.html
+++ b/erpnext/templates/includes/navbar/navbar_items.html
@@ -6,7 +6,17 @@
-
+
-
+
+ {% if frappe.db.get_single_value("E Commerce Settings", "enable_wishlist") %}
+
+
+
+
+
+
+
+
+ {% endif %}
{% endblock %}
diff --git a/erpnext/templates/includes/order/order_taxes.html b/erpnext/templates/includes/order/order_taxes.html
index d2c458e0a49..b821e6253d0 100644
--- a/erpnext/templates/includes/order/order_taxes.html
+++ b/erpnext/templates/includes/order/order_taxes.html
@@ -1,9 +1,9 @@
{% if doc.taxes %}
-
+
{{ _("Net Total") }}
-
+
{{ doc.get_formatted("net_total") }}
@@ -12,10 +12,10 @@
{% for d in doc.taxes %}
{% if d.base_tax_amount %}
-
+
{{ d.description }}
-
+
{{ d.get_formatted("base_tax_amount") }}
@@ -23,76 +23,62 @@
{% endfor %}
{% if doc.doctype == 'Quotation' %}
-{% if doc.coupon_code %}
-
-
- {{ _("Discount") }}
-
-
- {% set tot_quotation_discount = [] %}
- {%- for item in doc.items -%}
- {% if tot_quotation_discount.append((((item.price_list_rate * item.qty)
- * item.discount_percentage) / 100)) %}{% endif %}
- {% endfor %}
- {{ frappe.utils.fmt_money((tot_quotation_discount | sum),currency=doc.currency) }}
-
-
-{% endif %}
+ {% if doc.coupon_code %}
+
+
+ {{ _("Savings") }}
+
+
+ {% set tot_quotation_discount = [] %}
+ {%- for item in doc.items -%}
+ {% if tot_quotation_discount.append((((item.price_list_rate * item.qty)
+ * item.discount_percentage) / 100)) %}
+ {% endif %}
+ {% endfor %}
+ {{ frappe.utils.fmt_money((tot_quotation_discount | sum),currency=doc.currency) }}
+
+
+ {% endif %}
{% endif %}
{% if doc.doctype == 'Sales Order' %}
-{% if doc.coupon_code %}
-
-
- {{ _("Total Amount") }}
-
-
-
- {% set total_amount = [] %}
- {%- for item in doc.items -%}
- {% if total_amount.append((item.price_list_rate * item.qty)) %}{% endif %}
- {% endfor %}
- {{ frappe.utils.fmt_money((total_amount | sum),currency=doc.currency) }}
-
-
-
-
-
- {{ _("Applied Coupon Code") }}
-
-
-
- {%- for row in frappe.get_all(doctype="Coupon Code",
- fields=["coupon_code"], filters={ "name":doc.coupon_code}) -%}
- {{ row.coupon_code }}
- {% endfor %}
-
-
-
-
-
- {{ _("Discount") }}
-
-
-
- {% set tot_SO_discount = [] %}
- {%- for item in doc.items -%}
- {% if tot_SO_discount.append((((item.price_list_rate * item.qty)
- * item.discount_percentage) / 100)) %}{% endif %}
- {% endfor %}
- {{ frappe.utils.fmt_money((tot_SO_discount | sum),currency=doc.currency) }}
-
-
-
-{% endif %}
+ {% if doc.coupon_code %}
+
+
+ {{ _("Applied Coupon Code") }}
+
+
+
+ {%- for row in frappe.get_all(doctype="Coupon Code",
+ fields=["coupon_code"], filters={ "name":doc.coupon_code}) -%}
+ {{ row.coupon_code }}
+ {% endfor %}
+
+
+
+
+
+ {{ _("Savings") }}
+
+
+
+ {% set tot_SO_discount = [] %}
+ {%- for item in doc.items -%}
+ {% if tot_SO_discount.append((((item.price_list_rate * item.qty)
+ * item.discount_percentage) / 100)) %}{% endif %}
+ {% endfor %}
+ {{ frappe.utils.fmt_money((tot_SO_discount | sum),currency=doc.currency) }}
+
+
+
+ {% endif %}
{% endif %}
-
-
+
{{ _("Grand Total") }}
-
+
{{ doc.get_formatted("grand_total") }}
diff --git a/erpnext/templates/includes/product_page.js b/erpnext/templates/includes/product_page.js
index 90a1d862c3d..a3979d037b6 100644
--- a/erpnext/templates/includes/product_page.js
+++ b/erpnext/templates/includes/product_page.js
@@ -7,7 +7,7 @@ frappe.ready(function() {
frappe.call({
type: "POST",
- method: "erpnext.shopping_cart.product_info.get_product_info_for_website",
+ method: "erpnext.e_commerce.shopping_cart.product_info.get_product_info_for_website",
args: {
item_code: get_item_code()
},
diff --git a/erpnext/templates/includes/products_as_list.html b/erpnext/templates/includes/products_as_list.html
index 9bf9fd95d73..a9369bb8def 100644
--- a/erpnext/templates/includes/products_as_list.html
+++ b/erpnext/templates/includes/products_as_list.html
@@ -1,5 +1,5 @@
-{% from "erpnext/templates/includes/macros.html" import item_card, item_card_body %}
-
+{% from "erpnext/templates/includes/macros.html" import item_card, item_card_body, product_image_square %}
+
diff --git a/erpnext/templates/pages/cart.html b/erpnext/templates/pages/cart.html
index ea343713a13..fa7b0925599 100644
--- a/erpnext/templates/pages/cart.html
+++ b/erpnext/templates/pages/cart.html
@@ -21,8 +21,9 @@
{% if doc.items %}
-
-
+
+
+
-
-
-
- {% if doc.items %}
-
-
+
{% if doc.items %}
- {% if doc.tc_name %}
-
- {% endif %}
+ {% if doc.terms %}
+
+
{{ _("Terms and Conditions") }}
+
+ {{ doc.terms }}
+
+
+ {% endif %}
+
-
+
+
+ {% set show_coupon_code = cart_settings.show_apply_coupon_code_in_website and cart_settings.enable_checkout %}
+ {% if show_coupon_code == 1%}
+
+
+
+ {{ _("Apply Coupon Code") }}
+
+
+
+ {% endif %}
+
+ {% if cart_settings.enable_checkout %}
+
+ {% include "templates/includes/cart/cart_payment_summary.html" %}
+
+ {% endif %}
+
{% include "templates/includes/cart/cart_address.html" %}
-
+
{% endif %}
@@ -124,11 +120,11 @@
{{ _('Your cart is Empty') }}
{% if cart_settings.enable_checkout %}
-
+
{{ _('See past orders') }}
{% else %}
-
+
{{ _('See past quotations') }}
{% endif %}
diff --git a/erpnext/templates/pages/cart.py b/erpnext/templates/pages/cart.py
index 30b03575785..0d0e6ce4f8f 100644
--- a/erpnext/templates/pages/cart.py
+++ b/erpnext/templates/pages/cart.py
@@ -1,11 +1,10 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-from __future__ import unicode_literals
+
+from erpnext.e_commerce.shopping_cart.cart import get_cart_quotation
no_cache = 1
-import frappe
-from erpnext.shopping_cart.cart import get_cart_quotation
-
def get_context(context):
+ context.body_class = "product-page"
context.update(get_cart_quotation())
diff --git a/erpnext/templates/pages/cart_terms.html b/erpnext/templates/pages/cart_terms.html
deleted file mode 100644
index 6d84fb86a78..00000000000
--- a/erpnext/templates/pages/cart_terms.html
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
{{doc.terms}}
diff --git a/erpnext/templates/pages/courses.py b/erpnext/templates/pages/courses.py
index 92c38f6fcae..7eb01351eae 100644
--- a/erpnext/templates/pages/courses.py
+++ b/erpnext/templates/pages/courses.py
@@ -2,8 +2,8 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
def get_context(context):
diff --git a/erpnext/templates/pages/customer_reviews.html b/erpnext/templates/pages/customer_reviews.html
new file mode 100644
index 00000000000..121bec378cc
--- /dev/null
+++ b/erpnext/templates/pages/customer_reviews.html
@@ -0,0 +1,67 @@
+{% extends "templates/web.html" %}
+{% from "erpnext/templates/includes/macros.html" import user_review, ratings_summary %}
+
+{% block title %} {{ _("Customer Reviews") }} {% endblock %}
+
+{% block page_content %}
+
+ {% if enable_reviews %}
+
+
+
+
+
+
+ {% if frappe.session.user != "Guest" and user_is_customer %}
+
+ {{ _("Write a Review") }}
+
+ {% endif %}
+
+
+
+
+ {{ ratings_summary(reviews, reviews_per_rating, average_rating, average_whole_rating, for_summary=True, total_reviews=total_reviews) }}
+
+
+
+
+ {% if reviews %}
+ {{ user_review(reviews) }}
+
+ {% if not reviews | len >= total_reviews %}
+
+ {{ _("View More") }}
+
+ {% endif %}
+
+ {% else %}
+
+ {{ _("No Reviews") }}
+
+ {% endif %}
+
+ {% else %}
+
+
+
+ {{ _("No Reviews") }}
+
+
+ {% endif %}
+
+
+{% endblock %}
+
+{% block base_scripts %}
+
+
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/erpnext/templates/pages/customer_reviews.js b/erpnext/templates/pages/customer_reviews.js
new file mode 100644
index 00000000000..e13ded6b489
--- /dev/null
+++ b/erpnext/templates/pages/customer_reviews.js
@@ -0,0 +1,138 @@
+$(() => {
+ class CustomerReviews {
+ constructor() {
+ this.bind_button_actions();
+ this.start = 0;
+ this.page_length = 10;
+ }
+
+ bind_button_actions() {
+ this.write_review();
+ this.view_more();
+ }
+
+ write_review() {
+ //TODO: make dialog popup on stray page
+ $('.page_content').on('click', '.btn-write-review', (e) => {
+ // Bind action on write a review button
+ const $btn = $(e.currentTarget);
+
+ let d = new frappe.ui.Dialog({
+ title: __("Write a Review"),
+ fields: [
+ {fieldname: "title", fieldtype: "Data", label: "Headline", reqd: 1},
+ {fieldname: "rating", fieldtype: "Rating", label: "Overall Rating", reqd: 1},
+ {fieldtype: "Section Break"},
+ {fieldname: "comment", fieldtype: "Small Text", label: "Your Review"}
+ ],
+ primary_action: function() {
+ let data = d.get_values();
+ frappe.call({
+ method: "erpnext.e_commerce.doctype.item_review.item_review.add_item_review",
+ args: {
+ web_item: $btn.attr('data-web-item'),
+ title: data.title,
+ rating: data.rating,
+ comment: data.comment
+ },
+ freeze: true,
+ freeze_message: __("Submitting Review ..."),
+ callback: (r) => {
+ if (!r.exc) {
+ frappe.msgprint({
+ message: __("Thank you for submitting your review"),
+ title: __("Review Submitted"),
+ indicator: "green"
+ });
+ d.hide();
+ location.reload();
+ }
+ }
+ });
+ },
+ primary_action_label: __('Submit')
+ });
+ d.show();
+ });
+ }
+
+ view_more() {
+ $('.page_content').on('click', '.btn-view-more', (e) => {
+ // Bind action on view more button
+ const $btn = $(e.currentTarget);
+ $btn.prop('disabled', true);
+
+ this.start += this.page_length;
+ let me = this;
+
+ frappe.call({
+ method: "erpnext.e_commerce.doctype.item_review.item_review.get_item_reviews",
+ args: {
+ web_item: $btn.attr('data-web-item'),
+ start: me.start,
+ end: me.page_length
+ },
+ callback: (result) => {
+ if (result.message) {
+ let res = result.message;
+ me.get_user_review_html(res.reviews);
+
+ $btn.prop('disabled', false);
+ if (res.total_reviews <= (me.start + me.page_length)) {
+ $btn.hide();
+ }
+
+ }
+ }
+ });
+ });
+
+ }
+
+ get_user_review_html(reviews) {
+ let me = this;
+ let $content = $('.user-reviews');
+
+ reviews.forEach((review) => {
+ $content.append(`
+
+
+
+ ${__(review.review_title)}
+
+
+ ${me.get_review_stars(review.rating)}
+
+
+
+
+
+ ${__(review.comment)}
+
+
+
+ ${__(review.customer)}
+
+ ${__(review.published_on)}
+
+
+ `);
+ });
+ }
+
+ get_review_stars(rating) {
+ let stars = ``;
+ for (let i = 1; i < 6; i++) {
+ let fill_class = i <= rating ? 'star-click' : '';
+ stars += `
+
+
+
+ `;
+ }
+ return stars;
+ }
+ }
+
+ new CustomerReviews();
+});
\ No newline at end of file
diff --git a/erpnext/templates/pages/customer_reviews.py b/erpnext/templates/pages/customer_reviews.py
new file mode 100644
index 00000000000..c1f0c93f1aa
--- /dev/null
+++ b/erpnext/templates/pages/customer_reviews.py
@@ -0,0 +1,25 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+import frappe
+
+from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import (
+ get_shopping_cart_settings,
+)
+from erpnext.e_commerce.doctype.item_review.item_review import get_item_reviews
+from erpnext.e_commerce.doctype.website_item.website_item import check_if_user_is_customer
+
+
+def get_context(context):
+ context.body_class = "product-page"
+ context.no_cache = 1
+ context.full_page = True
+ context.reviews = None
+
+ if frappe.form_dict and frappe.form_dict.get("web_item"):
+ context.web_item = frappe.form_dict.get("web_item")
+ context.user_is_customer = check_if_user_is_customer()
+ context.enable_reviews = get_shopping_cart_settings().enable_reviews
+
+ if context.enable_reviews:
+ reviews_data = get_item_reviews(context.web_item)
+ context.update(reviews_data)
diff --git a/erpnext/templates/pages/help.py b/erpnext/templates/pages/help.py
index 4ce2b31d306..366b2835e2e 100644
--- a/erpnext/templates/pages/help.py
+++ b/erpnext/templates/pages/help.py
@@ -1,8 +1,11 @@
from __future__ import unicode_literals
-import frappe, json
+import json
+
+import frappe
import requests
+
def get_context(context):
context.no_cache = 1
settings = frappe.get_doc("Support Settings", "Support Settings")
diff --git a/erpnext/templates/pages/home.py b/erpnext/templates/pages/home.py
index 1c14450b473..3e23fc7253b 100644
--- a/erpnext/templates/pages/home.py
+++ b/erpnext/templates/pages/home.py
@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
no_cache = 1
@@ -10,7 +11,7 @@ def get_context(context):
homepage = frappe.get_doc('Homepage')
for item in homepage.products:
- route = frappe.db.get_value('Item', item.item_code, 'route')
+ route = frappe.db.get_value('Website Item', {"item_code": item.item_code}, 'route')
if route:
item.route = '/' + route
diff --git a/erpnext/templates/pages/integrations/gocardless_checkout.py b/erpnext/templates/pages/integrations/gocardless_checkout.py
index bdef79cfbed..2661a966c75 100644
--- a/erpnext/templates/pages/integrations/gocardless_checkout.py
+++ b/erpnext/templates/pages/integrations/gocardless_checkout.py
@@ -1,12 +1,17 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
+import json
+
import frappe
from frappe import _
-from frappe.utils import flt
-import json
-from erpnext.erpnext_integrations.doctype.gocardless_settings.gocardless_settings import gocardless_initialization, get_gateway_controller
-from frappe.utils import get_url
+from frappe.utils import flt, get_url
+
+from erpnext.erpnext_integrations.doctype.gocardless_settings.gocardless_settings import (
+ get_gateway_controller,
+ gocardless_initialization,
+)
no_cache = 1
diff --git a/erpnext/templates/pages/integrations/gocardless_confirmation.py b/erpnext/templates/pages/integrations/gocardless_confirmation.py
index 0b72e9f8b60..35c8b90bc9e 100644
--- a/erpnext/templates/pages/integrations/gocardless_confirmation.py
+++ b/erpnext/templates/pages/integrations/gocardless_confirmation.py
@@ -1,9 +1,14 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from erpnext.erpnext_integrations.doctype.gocardless_settings.gocardless_settings import gocardless_initialization, get_gateway_controller
+
+from erpnext.erpnext_integrations.doctype.gocardless_settings.gocardless_settings import (
+ get_gateway_controller,
+ gocardless_initialization,
+)
no_cache = 1
diff --git a/erpnext/templates/pages/material_request_info.py b/erpnext/templates/pages/material_request_info.py
index e29860ddd67..c18e201487f 100644
--- a/erpnext/templates/pages/material_request_info.py
+++ b/erpnext/templates/pages/material_request_info.py
@@ -2,11 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-
from frappe.utils import flt
+
def get_context(context):
context.no_cache = 1
context.show_sidebar = True
diff --git a/erpnext/templates/pages/non_profit/join_chapter.py b/erpnext/templates/pages/non_profit/join_chapter.py
index aa54a58eeb1..a1d1893c643 100644
--- a/erpnext/templates/pages/non_profit/join_chapter.py
+++ b/erpnext/templates/pages/non_profit/join_chapter.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def get_context(context):
context.no_cache = True
chapter = frappe.get_doc('Chapter', frappe.form_dict.name)
diff --git a/erpnext/templates/pages/non_profit/leave_chapter.py b/erpnext/templates/pages/non_profit/leave_chapter.py
index 21cb722b884..ebdb6645d49 100644
--- a/erpnext/templates/pages/non_profit/leave_chapter.py
+++ b/erpnext/templates/pages/non_profit/leave_chapter.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
import frappe
+
def get_context(context):
context.no_cache = True
chapter = frappe.get_doc('Chapter', frappe.form_dict.name)
diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html
index 28faea8f4f3..19191d89096 100644
--- a/erpnext/templates/pages/order.html
+++ b/erpnext/templates/pages/order.html
@@ -139,9 +139,12 @@
diff --git a/erpnext/templates/pages/order.py b/erpnext/templates/pages/order.py
index 816a25963f5..a5e48ac883e 100644
--- a/erpnext/templates/pages/order.py
+++ b/erpnext/templates/pages/order.py
@@ -2,10 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
from frappe import _
-from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import show_attachments
+
+from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import show_attachments
+
def get_context(context):
context.no_cache = 1
@@ -22,7 +24,7 @@ def get_context(context):
context.payment_ref = frappe.db.get_value("Payment Request",
{"reference_name": frappe.form_dict.name}, "name")
- context.enabled_checkout = frappe.get_doc("Shopping Cart Settings").enable_checkout
+ context.enabled_checkout = frappe.get_doc("E Commerce Settings").enable_checkout
default_print_format = frappe.db.get_value('Property Setter', dict(property='default_print_format', doc_type=frappe.form_dict.doctype), "value")
if default_print_format:
@@ -36,7 +38,9 @@ def get_context(context):
# check for the loyalty program of the customer
customer_loyalty_program = frappe.db.get_value("Customer", context.doc.customer, "loyalty_program")
if customer_loyalty_program:
- from erpnext.accounts.doctype.loyalty_program.loyalty_program import get_loyalty_program_details_with_points
+ from erpnext.accounts.doctype.loyalty_program.loyalty_program import (
+ get_loyalty_program_details_with_points,
+ )
loyalty_program_details = get_loyalty_program_details_with_points(context.doc.customer, customer_loyalty_program)
context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points"))
diff --git a/erpnext/templates/pages/partners.py b/erpnext/templates/pages/partners.py
index 6725a3e2948..b1c668a2f63 100644
--- a/erpnext/templates/pages/partners.py
+++ b/erpnext/templates/pages/partners.py
@@ -2,8 +2,8 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-import frappe.website.render
page_title = "Partners"
diff --git a/erpnext/templates/pages/product_search.py b/erpnext/templates/pages/product_search.py
index 9ab76deff73..99ad648e530 100644
--- a/erpnext/templates/pages/product_search.py
+++ b/erpnext/templates/pages/product_search.py
@@ -1,11 +1,19 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-from __future__ import unicode_literals
import frappe
-from frappe.utils import cstr, nowdate, cint
+from frappe.utils import cint, cstr
+from redisearch import AutoCompleter, Client, Query
+
+from erpnext.e_commerce.redisearch import (
+ WEBSITE_ITEM_CATEGORY_AUTOCOMPLETE,
+ WEBSITE_ITEM_INDEX,
+ WEBSITE_ITEM_NAME_AUTOCOMPLETE,
+ is_search_module_loaded,
+ make_key,
+)
+from erpnext.e_commerce.shopping_cart.product_info import set_product_info_for_website
from erpnext.setup.doctype.item_group.item_group import get_item_for_list_in_html
-from erpnext.shopping_cart.product_info import set_product_info_for_website
no_cache = 1
@@ -14,36 +22,118 @@ def get_context(context):
@frappe.whitelist(allow_guest=True)
def get_product_list(search=None, start=0, limit=12):
- # limit = 12 because we show 12 items in the grid view
-
- # base query
- query = """select I.name, I.item_name, I.item_code, I.route, I.image, I.website_image, I.thumbnail, I.item_group,
- I.description, I.web_long_description as website_description, I.is_stock_item,
- case when (S.actual_qty - S.reserved_qty) > 0 then 1 else 0 end as in_stock, I.website_warehouse,
- I.has_batch_no
- from `tabItem` I
- left join tabBin S on I.item_code = S.item_code and I.website_warehouse = S.warehouse
- where (I.show_in_website = 1)
- and I.disabled = 0
- and (I.end_of_life is null or I.end_of_life='0000-00-00' or I.end_of_life > %(today)s)"""
-
- # search term condition
- if search:
- query += """ and (I.web_long_description like %(search)s
- or I.description like %(search)s
- or I.item_name like %(search)s
- or I.name like %(search)s)"""
- search = "%" + cstr(search) + "%"
-
- # order by
- query += """ order by I.weightage desc, in_stock desc, I.modified desc limit %s, %s""" % (cint(start), cint(limit))
-
- data = frappe.db.sql(query, {
- "search": search,
- "today": nowdate()
- }, as_dict=1)
+ data = get_product_data(search, start, limit)
for item in data:
set_product_info_for_website(item)
return [get_item_for_list_in_html(r) for r in data]
+
+def get_product_data(search=None, start=0, limit=12):
+ # limit = 12 because we show 12 items in the grid view
+ # base query
+ query = """
+ SELECT
+ web_item_name, item_name, item_code, brand, route,
+ website_image, thumbnail, item_group,
+ description, web_long_description as website_description,
+ website_warehouse, ranking
+ FROM `tabWebsite Item`
+ WHERE published = 1
+ """
+
+ # search term condition
+ if search:
+ query += """ and (item_name like %(search)s
+ or web_item_name like %(search)s
+ or brand like %(search)s
+ or web_long_description like %(search)s)"""
+ search = "%" + cstr(search) + "%"
+
+ # order by
+ query += """ ORDER BY ranking desc, modified desc limit %s, %s""" % (cint(start), cint(limit))
+
+ return frappe.db.sql(query, {
+ "search": search
+ }, as_dict=1)
+
+@frappe.whitelist(allow_guest=True)
+def search(query):
+ product_results = product_search(query)
+ category_results = get_category_suggestions(query)
+
+ return {
+ "product_results": product_results.get("results") or [],
+ "category_results": category_results.get("results") or []
+ }
+
+@frappe.whitelist(allow_guest=True)
+def product_search(query, limit=10, fuzzy_search=True):
+ search_results = {"from_redisearch": True, "results": []}
+
+ if not is_search_module_loaded():
+ # Redisearch module not loaded
+ search_results["from_redisearch"] = False
+ search_results["results"] = get_product_data(query, 0, limit)
+ return search_results
+
+ if not query:
+ return search_results
+
+ red = frappe.cache()
+ query = clean_up_query(query)
+
+ ac = AutoCompleter(make_key(WEBSITE_ITEM_NAME_AUTOCOMPLETE), conn=red)
+ client = Client(make_key(WEBSITE_ITEM_INDEX), conn=red)
+ suggestions = ac.get_suggestions(
+ query,
+ num=limit,
+ fuzzy= fuzzy_search and len(query) > 3 # Fuzzy on length < 3 can be real slow
+ )
+
+ # Build a query
+ query_string = query
+
+ for s in suggestions:
+ query_string += f"|('{clean_up_query(s.string)}')"
+
+ q = Query(query_string)
+
+ results = client.search(q)
+ search_results['results'] = list(map(convert_to_dict, results.docs))
+ search_results['results'] = sorted(search_results['results'], key=lambda k: frappe.utils.cint(k['ranking']), reverse=True)
+
+ return search_results
+
+def clean_up_query(query):
+ return ''.join(c for c in query if c.isalnum() or c.isspace())
+
+def convert_to_dict(redis_search_doc):
+ return redis_search_doc.__dict__
+
+@frappe.whitelist(allow_guest=True)
+def get_category_suggestions(query):
+ search_results = {"results": []}
+
+ if not is_search_module_loaded():
+ # Redisearch module not loaded, query db
+ categories = frappe.db.get_all(
+ "Item Group",
+ filters={
+ "name": ["like", "%{0}%".format(query)],
+ "show_in_website": 1
+ },
+ fields=["name", "route"]
+ )
+ search_results['results'] = categories
+ return search_results
+
+ if not query:
+ return search_results
+
+ ac = AutoCompleter(make_key(WEBSITE_ITEM_CATEGORY_AUTOCOMPLETE), conn=frappe.cache())
+ suggestions = ac.get_suggestions(query, num=10)
+
+ search_results['results'] = [s.string for s in suggestions]
+
+ return search_results
diff --git a/erpnext/templates/pages/projects.py b/erpnext/templates/pages/projects.py
index b369cb6a991..7124a7ed997 100644
--- a/erpnext/templates/pages/projects.py
+++ b/erpnext/templates/pages/projects.py
@@ -2,8 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-import json
+
def get_context(context):
project_user = frappe.db.get_value("Project User", {"parent": frappe.form_dict.project, "user": frappe.session.user} , ["user", "view_attachments"], as_dict= True)
diff --git a/erpnext/templates/pages/regional/india/update_gstin.py b/erpnext/templates/pages/regional/india/update_gstin.py
index f555db0d72a..a8d03d58631 100644
--- a/erpnext/templates/pages/regional/india/update_gstin.py
+++ b/erpnext/templates/pages/regional/india/update_gstin.py
@@ -1,8 +1,9 @@
from __future__ import unicode_literals
+
import frappe
-from frappe import _
from six import iteritems
+
def get_context(context):
context.no_cache = 1
party = frappe.form_dict.party
diff --git a/erpnext/templates/pages/rfq.py b/erpnext/templates/pages/rfq.py
index 67679a1a7d3..b9f646b8a5d 100644
--- a/erpnext/templates/pages/rfq.py
+++ b/erpnext/templates/pages/rfq.py
@@ -2,11 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import formatdate
+
from erpnext.controllers.website_list_for_contact import get_customers_suppliers
+
def get_context(context):
context.no_cache = 1
context.show_sidebar = True
diff --git a/erpnext/templates/pages/search_help.py b/erpnext/templates/pages/search_help.py
index 887d8f4724e..4272b94ffb7 100644
--- a/erpnext/templates/pages/search_help.py
+++ b/erpnext/templates/pages/search_help.py
@@ -1,11 +1,14 @@
from __future__ import unicode_literals
-import frappe, requests
+
+import frappe
+import requests
from frappe import _
-from jinja2 import utils
-from html2text import html2text
-from six import text_type
from frappe.utils import sanitize_html
from frappe.utils.global_search import search
+from html2text import html2text
+from jinja2 import utils
+from six import text_type
+
def get_context(context):
context.no_cache = 1
diff --git a/erpnext/templates/pages/task_info.py b/erpnext/templates/pages/task_info.py
index 260e2788cd0..f219c3deb7b 100644
--- a/erpnext/templates/pages/task_info.py
+++ b/erpnext/templates/pages/task_info.py
@@ -1,7 +1,7 @@
from __future__ import unicode_literals
+
import frappe
-from frappe import _
def get_context(context):
context.no_cache = 1
diff --git a/erpnext/templates/pages/timelog_info.py b/erpnext/templates/pages/timelog_info.py
index ee86483fa29..e0fb60da23d 100644
--- a/erpnext/templates/pages/timelog_info.py
+++ b/erpnext/templates/pages/timelog_info.py
@@ -1,7 +1,7 @@
from __future__ import unicode_literals
+
import frappe
-from frappe import _
def get_context(context):
context.no_cache = 1
diff --git a/erpnext/templates/pages/wishlist.html b/erpnext/templates/pages/wishlist.html
new file mode 100644
index 00000000000..7a81dedb49f
--- /dev/null
+++ b/erpnext/templates/pages/wishlist.html
@@ -0,0 +1,28 @@
+{% extends "templates/web.html" %}
+
+{% block title %} {{ _("Wishlist") }} {% endblock %}
+
+{% block header %}