Merge pull request #4945 from shreyasp/mr-wn-sup17487
[Minor] Displaying 'for warehouse' while creating Material request from BOM
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py
index fd88afd..7e05b95 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.py
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py
@@ -19,7 +19,7 @@
data = []
data.extend(asset or [])
- data.extend(liability or [])
+ data.extend(liability or [])
data.extend(equity or [])
if provisional_profit_loss:
data.append(provisional_profit_loss)
@@ -43,11 +43,11 @@
for period in period_list:
effective_liability = 0.0
if liability:
- effective_liability += flt(liability[-2][period.key])
+ effective_liability += flt(liability[-2].get(period.key))
if equity:
- effective_liability += flt(equity[-2][period.key])
+ effective_liability += flt(equity[-2].get(period.key))
- provisional_profit_loss[period.key] = flt(asset[-2][period.key]) - effective_liability
+ provisional_profit_loss[period.key] = flt(asset[-2].get(period.key)) - effective_liability
if provisional_profit_loss[period.key]:
has_value = True
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index d84f18f..0f10b94 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -92,7 +92,7 @@
if not accounts:
return None
- accounts, accounts_by_name = filter_accounts(accounts)
+ accounts, accounts_by_name, parent_children_map = filter_accounts(accounts)
company_currency = frappe.db.get_value("Company", company, "default_currency")
@@ -109,6 +109,7 @@
calculate_values(accounts_by_name, gl_entries_by_account, period_list, accumulated_values)
accumulate_values_into_parents(accounts, accounts_by_name, period_list, accumulated_values)
out = prepare_data(accounts, balance_must_be, period_list, company_currency)
+ out = filter_out_zero_value_rows(out, parent_children_map)
if out:
add_total_row(out, balance_must_be, period_list, company_currency)
@@ -134,15 +135,15 @@
d.get(period.key, 0.0)
def prepare_data(accounts, balance_must_be, period_list, company_currency):
- out = []
+ data = []
year_start_date = period_list[0]["year_start_date"].strftime("%Y-%m-%d")
year_end_date = period_list[-1]["year_end_date"].strftime("%Y-%m-%d")
-
+
for d in accounts:
# add to output
has_value = False
total = 0
- row = {
+ row = frappe._dict({
"account_name": d.account_name,
"account": d.name,
"parent_account": d.parent_account,
@@ -150,7 +151,7 @@
"year_start_date": year_start_date,
"year_end_date": year_end_date,
"currency": company_currency
- }
+ })
for period in period_list:
if d.get(period.key):
# change sign based on Debit or Credit, since calculation is done using (debit - credit)
@@ -163,11 +164,25 @@
has_value = True
total += flt(row[period.key])
- if has_value:
- row["total"] = total
- out.append(row)
+ row["has_value"] = has_value
+ row["total"] = total
+ data.append(row)
+
+ return data
+
+def filter_out_zero_value_rows(data, parent_children_map):
+ data_with_value = []
+ for d in data:
+ if d.get("has_value"):
+ data_with_value.append(d)
+ else:
+ children = [child.name for child in parent_children_map.get(d.account) or []]
+ for row in data:
+ if row.account in children and row.get("has_value"):
+ data_with_value.append(d)
+ break
- return out
+ return data_with_value
def add_total_row(out, balance_must_be, period_list, company_currency):
total_row = {
@@ -187,10 +202,11 @@
total_row["total"] += flt(row["total"])
row["total"] = ""
- out.append(total_row)
+ if total_row.has_key("total"):
+ out.append(total_row)
- # blank row after Total
- out.append({})
+ # blank row after Total
+ out.append({})
def get_accounts(company, root_type):
return frappe.db.sql("""select name, parent_account, lft, rgt, root_type, report_type, account_name from `tabAccount`
@@ -218,7 +234,7 @@
add_to_list(None, 0)
- return filtered_accounts, accounts_by_name
+ return filtered_accounts, accounts_by_name, parent_children_map
def sort_root_accounts(roots):
"""Sort root types as Asset, Liability, Equity, Income, Expense"""
diff --git a/erpnext/docs/user/manual/en/setting-up/data/bulk-rename.md b/erpnext/docs/user/manual/en/setting-up/data/bulk-rename.md
index 499ee32..d4cb0ba 100644
--- a/erpnext/docs/user/manual/en/setting-up/data/bulk-rename.md
+++ b/erpnext/docs/user/manual/en/setting-up/data/bulk-rename.md
@@ -1,6 +1,6 @@
# Bulk Renaming of Records
-You can rename a document if ERPNext (if it is allowed) by going to **Menu > Rename** in the document.
+You can rename a document in ERPNext (if it is allowed) by going to **Menu > Rename** in the document.
Alternatively, if you want to rename a whole bunch of records, just go to:
diff --git a/erpnext/hr/doctype/process_payroll/process_payroll.py b/erpnext/hr/doctype/process_payroll/process_payroll.py
index 13516b6..a71200c 100644
--- a/erpnext/hr/doctype/process_payroll/process_payroll.py
+++ b/erpnext/hr/doctype/process_payroll/process_payroll.py
@@ -188,7 +188,7 @@
return journal_entry.as_dict()
-
+@frappe.whitelist()
def get_month_details(year, month):
ysd = frappe.db.get_value("Fiscal Year", year, "year_start_date")
if ysd:
diff --git a/erpnext/public/js/pos/pos.js b/erpnext/public/js/pos/pos.js
index b8a6d32..4e3898f 100644
--- a/erpnext/public/js/pos/pos.js
+++ b/erpnext/public/js/pos/pos.js
@@ -433,7 +433,8 @@
options: me.modes_of_payment.join('\n'), reqd: 1,
"default": default_mode},
{fieldtype:'Currency', fieldname:'paid_amount', label:__('Amount Paid'),
- reqd:1, "default": me.frm.doc.grand_total, hidden: 1, change: function() {
+ reqd:1, "default": me.frm.doc.grand_total,
+ change: function() {
var values = dialog.get_values();
var actual_change = flt(values.paid_amount - values.total_amount,
@@ -480,6 +481,9 @@
// set to nearest 5
dialog.set_value("paid_amount", dialog.get_value("total_amount"));
dialog.get_input("paid_amount").trigger("change");
+ } else if (!is_cash) {
+ dialog.set_value("paid_amount", dialog.get_value("total_amount"));
+ dialog.set_value("change", 0);
}
}).trigger("change");
diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js
index b2693b9..e6b636c 100644
--- a/erpnext/public/js/setup_wizard.js
+++ b/erpnext/public/js/setup_wizard.js
@@ -22,6 +22,15 @@
placeholder:__('e.g. "Build tools for builders"'), reqd:1},
{fieldname:'bank_account', label: __('Bank Account'), fieldtype:'Data',
placeholder: __('e.g. "XYZ National Bank"'), reqd:1 },
+ {fieldname:'domain', label: __('Domain'), fieldtype:'Select',
+ options: [
+ __("Distribution"),
+ __("Manufacturing"),
+ __("Retail"),
+ __("Services"),
+ __("Education"),
+ __("Other")
+ ], reqd:1},
{fieldname:'chart_of_accounts', label: __('Chart of Accounts'),
options: "", fieldtype: 'Select'},
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index cc1fc4f..76165ef 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -140,31 +140,6 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
- "fieldname": "country",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "label": "Country",
- "length": 0,
- "no_copy": 0,
- "options": "Country",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
"fieldname": "domain",
"fieldtype": "Select",
"hidden": 0,
@@ -175,7 +150,7 @@
"label": "Domain",
"length": 0,
"no_copy": 0,
- "options": "Distribution\nManufacturing\nRetail\nServices\nEducation",
+ "options": "Distribution\nManufacturing\nRetail\nServices\nEducation\nOther",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@@ -266,6 +241,32 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "fieldname": "default_terms",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Default Terms",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Terms and Conditions",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "column_break_10",
"fieldtype": "Column Break",
"hidden": 0,
@@ -290,6 +291,31 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "fieldname": "country",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "label": "Country",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Country",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "default_currency",
"fieldtype": "Link",
"hidden": 0,
@@ -340,32 +366,6 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
- "fieldname": "default_terms",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Default Terms",
- "length": 0,
- "no_copy": 0,
- "options": "Terms and Conditions",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
"fieldname": "default_settings",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1235,8 +1235,8 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2016-03-02 02:24:21.343229",
- "modified_by": "Administrator",
+ "modified": "2016-03-08 20:21:46.331870",
+ "modified_by": "anand@erpnext.com",
"module": "Setup",
"name": "Company",
"owner": "Administrator",
diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.json b/erpnext/setup/doctype/global_defaults/global_defaults.json
index c67630e..a9397f2 100644
--- a/erpnext/setup/doctype/global_defaults/global_defaults.json
+++ b/erpnext/setup/doctype/global_defaults/global_defaults.json
@@ -1,7 +1,10 @@
{
"allow_copy": 1,
+ "allow_email": 0,
"allow_import": 0,
+ "allow_print": 0,
"allow_rename": 0,
+ "allow_trash": 0,
"creation": "2013-05-02 17:53:24",
"custom": 0,
"docstatus": 0,
@@ -15,13 +18,17 @@
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1,
+ "ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Default Company",
+ "length": 0,
+ "no_column": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@@ -37,13 +44,17 @@
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Current Fiscal Year",
+ "length": 0,
+ "no_column": 0,
"no_copy": 0,
"options": "Fiscal Year",
"permlevel": 0,
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
@@ -59,13 +70,17 @@
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Country",
+ "length": 0,
+ "no_column": 0,
"no_copy": 0,
"options": "Country",
"permlevel": 0,
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@@ -81,12 +96,16 @@
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "length": 0,
+ "no_column": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@@ -103,13 +122,17 @@
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1,
+ "ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Default Currency",
+ "length": 0,
+ "no_column": 0,
"no_copy": 0,
"options": "Currency",
"permlevel": 0,
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
@@ -126,13 +149,17 @@
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Hide Currency Symbol",
+ "length": 0,
+ "no_column": 0,
"no_copy": 0,
"options": "\nNo\nYes",
"permlevel": 0,
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@@ -149,12 +176,42 @@
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Disable Rounded Total",
+ "length": 0,
+ "no_column": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "description": "If disable, 'In Words' field will not be visible in any transaction",
+ "fieldname": "disable_in_words",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "label": "Disable In Words",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@@ -170,9 +227,12 @@
"in_create": 1,
"in_dialog": 0,
"is_submittable": 0,
+ "is_transaction_doc": 0,
"issingle": 1,
"istable": 0,
- "modified": "2015-06-30 03:00:26.420003",
+ "max_attachments": 0,
+ "menu_index": 0,
+ "modified": "2016-03-03 16:14:41.260467",
"modified_by": "Administrator",
"module": "Setup",
"name": "Global Defaults",
@@ -192,6 +252,7 @@
"print": 0,
"read": 1,
"report": 0,
+ "restrict": 0,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
@@ -200,5 +261,9 @@
}
],
"read_only": 1,
- "read_only_onload": 0
+ "read_only_onload": 0,
+ "show_in_menu": 0,
+ "sort_order": "DESC",
+ "use_template": 0,
+ "version": 0
}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.py b/erpnext/setup/doctype/global_defaults/global_defaults.py
index efdc875..9c6eb82 100644
--- a/erpnext/setup/doctype/global_defaults/global_defaults.py
+++ b/erpnext/setup/doctype/global_defaults/global_defaults.py
@@ -17,6 +17,7 @@
'hide_currency_symbol':'hide_currency_symbol',
'account_url':'account_url',
'disable_rounded_total': 'disable_rounded_total',
+ 'disable_in_words': 'disable_in_words',
}
from frappe.model.document import Document
@@ -44,6 +45,7 @@
frappe.db.set_value("Currency", self.default_currency, "enabled", 1)
self.toggle_rounded_total()
+ self.toggle_in_words()
# clear cache
frappe.clear_cache()
@@ -61,3 +63,12 @@
make_property_setter(doctype, "rounded_total", "hidden", self.disable_rounded_total, "Check")
make_property_setter(doctype, "rounded_total", "print_hide", self.disable_rounded_total, "Check")
+
+ def toggle_in_words(self):
+ self.disable_in_words = cint(self.disable_in_words)
+
+ # Make property setters to hide in words fields
+ for doctype in ("Quotation", "Sales Order", "Sales Invoice", "Delivery Note",
+ "Supplier Quotation", "Purchase Order", "Purchase Invoice", "Purchase Receipt"):
+ make_property_setter(doctype, "in_words", "hidden", self.disable_in_words, "Check")
+ make_property_setter(doctype, "in_words", "print_hide", self.disable_in_words, "Check")
diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py
index 5a04682..864d2d0 100644
--- a/erpnext/setup/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/setup_wizard/setup_wizard.py
@@ -19,7 +19,7 @@
frappe.throw(_("Setup Already Complete!!"))
install_fixtures.install(args.get("country"))
-
+
create_fiscal_year_and_company(args)
create_users(args)
set_defaults(args)
@@ -63,22 +63,22 @@
'year_end_date': args.get('fy_end_date'),
}).insert()
args["curr_fiscal_year"] = curr_fiscal_year
-
+
# Company
- if (args.get('company_name')):
+ if (args.get('company_name')):
frappe.get_doc({
"doctype":"Company",
- 'domain': args.get("industry"),
'company_name':args.get('company_name').strip(),
'abbr':args.get('company_abbr'),
'default_currency':args.get('currency'),
'country': args.get('country'),
'chart_of_accounts': args.get(('chart_of_accounts')),
+ 'domain': args.get('domain')
}).insert()
# Bank Account
create_bank_account(args)
-
+
def create_bank_account(args):
if args.get("bank_account"):
company_name = args.get('company_name').strip()
diff --git a/erpnext/startup/notifications.py b/erpnext/startup/notifications.py
index 45f7b81..7555312 100644
--- a/erpnext/startup/notifications.py
+++ b/erpnext/startup/notifications.py
@@ -28,6 +28,7 @@
"Delivery Note": {"docstatus": 0},
"Stock Entry": {"docstatus": 0},
"Material Request": {
+ "docstatus": ("<", 2),
"status": ("not in", ("Stopped",)),
"per_ordered": ("<", 100)
},
diff --git a/erpnext/stock/report/stock_balance/stock_balance.js b/erpnext/stock/report/stock_balance/stock_balance.js
index db334f8..1af32ed 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.js
+++ b/erpnext/stock/report/stock_balance/stock_balance.js
@@ -22,7 +22,40 @@
"label": __("Item"),
"fieldtype": "Link",
"width": "80",
- "options": "Item"
+ "options": "Item",
+ "reqd": 1,
+ "on_change": function(me) {
+ frappe.query_reports["Stock Balance"].toggle_mandatory_filters(me);
+ }
+ },
+ {
+ "fieldname": "warehouse",
+ "label": __("Warehouse"),
+ "fieldtype": "Link",
+ "width": "80",
+ "options": "Warehouse",
+ "reqd": 1,
+ "on_change": function(me) {
+ frappe.query_reports["Stock Balance"].toggle_mandatory_filters(me);
+ }
+ },
+ ],
+
+ "toggle_mandatory_filters": function(me) {
+ var values = me.get_values(false);
+ var item_filter = me.filters_by_name["item_code"];
+ var warehouse_filter = me.filters_by_name["warehouse"];
+
+ if (values.item_code) {
+ warehouse_filter.df.reqd = 0;
+ } else if (values.warehouse) {
+ item_filter.df.reqd = 0;
+ } else {
+ item_filter.df.reqd = 1;
+ warehouse_filter.df.reqd = 1;
}
- ]
+
+ item_filter.set_mandatory(values.item_code);
+ warehouse_filter.set_mandatory(values.warehouse);
+ }
}
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index 7dd728f..d465050 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -9,7 +9,7 @@
def execute(filters=None):
if not filters: filters = {}
- columns = get_columns(filters)
+ columns = get_columns()
item_map = get_item_details(filters)
iwb_map = get_item_warehouse_map(filters)
@@ -30,8 +30,8 @@
return columns, data
-def get_columns(filters):
- """return columns based on filters"""
+def get_columns():
+ """return columns"""
columns = [
_("Item")+":Link/Item:100",
@@ -68,9 +68,11 @@
if filters.get("item_code"):
conditions += " and item_code = '%s'" % frappe.db.escape(filters.get("item_code"), percent=False)
+ if filters.get("warehouse"):
+ conditions += " and warehouse = '%s'" % frappe.db.escape(filters.get("warehouse"), percent=False)
+
return conditions
-#get all details
def get_stock_ledger_entries(filters):
conditions = get_conditions(filters)
return frappe.db.sql("""select item_code, warehouse, posting_date, actual_qty, valuation_rate,
@@ -125,9 +127,13 @@
return iwb_map
def get_item_details(filters):
- item_map = {}
- for d in frappe.db.sql("select name, item_name, stock_uom, item_group, brand, \
- description from tabItem", as_dict=1):
- item_map.setdefault(d.name, d)
+ condition = ''
+ value = ()
+ if filters.get("item_code"):
+ condition = "where item_code=%s"
+ value = (filters["item_code"],)
- return item_map
+ items = frappe.db.sql("""select name, item_name, stock_uom, item_group, brand, description
+ from tabItem {condition}""".format(condition=condition), value, as_dict=1)
+
+ return dict((d.name, d) for d in items)