Merge pull request #25777 from Anuja-pawar/fix-process-SOA-format
fix: Process Statement of Accounts formatting
diff --git a/.pylintrc b/.pylintrc
deleted file mode 100644
index 4b2ea0a..0000000
--- a/.pylintrc
+++ /dev/null
@@ -1 +0,0 @@
-disable=access-member-before-definition
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json b/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json
index 6e7768d..bbf1ba0 100644
--- a/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json
+++ b/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json
@@ -46,6 +46,7 @@
"reqd": 1
},
{
+ "default": "0",
"fieldname": "closing_amount",
"fieldtype": "Currency",
"in_list_view": 1,
@@ -57,7 +58,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-10-23 16:45:43.662034",
+ "modified": "2021-05-19 20:08:44.523861",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Closing Entry Detail",
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index 473db56..f55fdab 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -455,32 +455,26 @@
@frappe.whitelist()
def get_stock_availability(item_code, warehouse):
- latest_sle = frappe.db.sql("""select qty_after_transaction
- from `tabStock Ledger Entry`
+ bin_qty = frappe.db.sql("""select actual_qty from `tabBin`
where item_code = %s and warehouse = %s
- order by posting_date desc, posting_time desc
limit 1""", (item_code, warehouse), as_dict=1)
pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
- sle_qty = latest_sle[0].qty_after_transaction or 0 if latest_sle else 0
+ bin_qty = bin_qty[0].actual_qty or 0 if bin_qty else 0
- if sle_qty and pos_sales_qty:
- return sle_qty - pos_sales_qty
- else:
- return sle_qty
+ return bin_qty - pos_sales_qty
def get_pos_reserved_qty(item_code, warehouse):
reserved_qty = frappe.db.sql("""select sum(p_item.qty) as qty
from `tabPOS Invoice` p, `tabPOS Invoice Item` p_item
where p.name = p_item.parent
- and p.consolidated_invoice is NULL
- and p.docstatus = 1
+ and ifnull(p.consolidated_invoice, '') = ''
and p_item.docstatus = 1
and p_item.item_code = %s
and p_item.warehouse = %s
""", (item_code, warehouse), as_dict=1)
-
+
return reserved_qty[0].qty or 0 if reserved_qty else 0
@frappe.whitelist()
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
index bc78743..08e072e 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
@@ -42,8 +42,9 @@
if return_against_status != "Consolidated":
# if return entry is not getting merged in the current pos closing and if it is not consolidated
bold_unconsolidated = frappe.bold("not Consolidated")
- msg = (_("Row #{}: Original Invoice {} of return invoice {} is {}. ")
+ msg = (_("Row #{}: Original Invoice {} of return invoice {} is {}.")
.format(d.idx, bold_return_against, bold_pos_invoice, bold_unconsolidated))
+ msg += " "
msg += _("Original invoice should be consolidated before or along with the return invoice.")
msg += "<br><br>"
msg += _("You can add original invoice {} manually to proceed.").format(bold_return_against)
@@ -56,12 +57,12 @@
sales = [d for d in pos_invoice_docs if d.get('is_return') == 0]
sales_invoice, credit_note = "", ""
- if sales:
- sales_invoice = self.process_merging_into_sales_invoice(sales)
-
if returns:
credit_note = self.process_merging_into_credit_note(returns)
+ if sales:
+ sales_invoice = self.process_merging_into_sales_invoice(sales)
+
self.save() # save consolidated_sales_invoice & consolidated_credit_note ref in merge log
self.update_pos_invoices(pos_invoice_docs, sales_invoice, credit_note)
@@ -274,9 +275,9 @@
closing_entry.db_set('error_message', '')
closing_entry.update_opening_entry()
- except Exception:
+ except Exception as e:
frappe.db.rollback()
- message_log = frappe.message_log.pop()
+ message_log = frappe.message_log.pop() if frappe.message_log else str(e)
error_message = safe_load_json(message_log)
if closing_entry:
@@ -300,9 +301,9 @@
closing_entry.db_set('error_message', '')
closing_entry.update_opening_entry(for_cancel=True)
- except Exception:
+ except Exception as e:
frappe.db.rollback()
- message_log = frappe.message_log.pop()
+ message_log = frappe.message_log.pop() if frappe.message_log else str(e)
error_message = safe_load_json(message_log)
if closing_entry:
@@ -348,11 +349,9 @@
return True
def safe_load_json(message):
- JSONDecodeError = ValueError if six.PY2 else json.JSONDecodeError
-
try:
json_message = json.loads(message).get('message')
- except JSONDecodeError:
+ except Exception:
json_message = message
return json_message
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json
index 4cc5753..38b8dfd 100644
--- a/erpnext/buying/doctype/supplier/supplier.json
+++ b/erpnext/buying/doctype/supplier/supplier.json
@@ -383,8 +383,14 @@
"icon": "fa fa-user",
"idx": 370,
"image_field": "image",
- "links": [],
- "modified": "2021-01-06 19:51:40.939087",
+ "links": [
+ {
+ "group": "Item Group",
+ "link_doctype": "Supplier Item Group",
+ "link_fieldname": "supplier"
+ }
+ ],
+ "modified": "2021-05-18 15:10:11.087191",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",
diff --git a/erpnext/buying/doctype/supplier_item_group/__init__.py b/erpnext/buying/doctype/supplier_item_group/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_item_group/__init__.py
diff --git a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.js b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.js
new file mode 100644
index 0000000..f7da90d
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.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('Supplier Item Group', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.json b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.json
new file mode 100644
index 0000000..1971458
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.json
@@ -0,0 +1,77 @@
+{
+ "actions": [],
+ "creation": "2021-05-07 18:16:40.621421",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "supplier",
+ "item_group"
+ ],
+ "fields": [
+ {
+ "fieldname": "supplier",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Supplier",
+ "options": "Supplier",
+ "reqd": 1
+ },
+ {
+ "fieldname": "item_group",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item Group",
+ "options": "Item Group",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-05-19 13:48:16.742303",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Supplier Item Group",
+ "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": "Purchase User",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Purchase Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.py b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.py
new file mode 100644
index 0000000..3a2e5d6
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.model.document import Document
+
+class SupplierItemGroup(Document):
+ def validate(self):
+ exists = frappe.db.exists({
+ 'doctype': 'Supplier Item Group',
+ 'supplier': self.supplier,
+ 'item_group': self.item_group
+ })
+ if exists:
+ frappe.throw(_("Item Group has already been linked to this supplier."))
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_item_group/test_supplier_item_group.py b/erpnext/buying/doctype/supplier_item_group/test_supplier_item_group.py
new file mode 100644
index 0000000..c75044d
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_item_group/test_supplier_item_group.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestSupplierItemGroup(unittest.TestCase):
+ pass
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 996c4ed..544e624 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1011,7 +1011,7 @@
else:
grand_total -= self.get("total_advance")
base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total"))
- print(grand_total, base_grand_total)
+
if total != flt(grand_total, self.precision("grand_total")) or \
base_total != flt(base_grand_total, self.precision("base_grand_total")):
frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total"))
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index b31724f..46301b7 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -204,7 +204,7 @@
if "description" in searchfields:
searchfields.remove("description")
-
+
columns = ''
extra_searchfields = [field for field in searchfields
if not field in ["name", "item_group", "description"]]
@@ -216,11 +216,22 @@
if not field in searchfields]
searchfields = " or ".join([field + " like %(txt)s" for field in searchfields])
+ if filters.get('supplier'):
+ item_group_list = frappe.get_all('Supplier Item Group', filters = {'supplier': filters.get('supplier')}, fields = ['item_group'])
+
+ item_groups = []
+ for i in item_group_list:
+ item_groups.append(i.item_group)
+
+ del filters['supplier']
+
+ if item_groups:
+ filters['item_group'] = ['in', item_groups]
+
description_cond = ''
if frappe.db.count('Item', cache=True) < 50000:
# scan description only if items are less than 50000
description_cond = 'or tabItem.description LIKE %(txt)s'
-
return frappe.db.sql("""select tabItem.name,
if(length(tabItem.item_name) > 40,
concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
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 f713684..7fd3b34 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
@@ -7,6 +7,7 @@
from __future__ import unicode_literals
import urllib
+from urllib.parse import quote
import hashlib
import hmac
import base64
@@ -68,8 +69,9 @@
"""
md = hashlib.md5()
md.update(string)
- return base64.encodestring(md.digest()).strip('\n') if six.PY2 \
- else base64.encodebytes(md.digest()).decode().strip()
+ return base64.encodebytes(md.digest()).decode().strip()
+
+
def remove_empty(d):
"""
@@ -177,7 +179,6 @@
'SignatureMethod': 'HmacSHA256',
}
params.update(extra_data)
- quote = urllib.quote if six.PY2 else urllib.parse.quote
request_description = '&'.join(['%s=%s' % (k, quote(params[k], safe='-_.~')) for k in sorted(params)])
signature = self.calc_signature(method, request_description)
url = '%s%s?%s&Signature=%s' % (self.domain, self.uri, request_description, quote(signature))
diff --git a/erpnext/projects/report/project_profitability/test_project_profitability.py b/erpnext/projects/report/project_profitability/test_project_profitability.py
index f2b9c25..ea6bdb5 100644
--- a/erpnext/projects/report/project_profitability/test_project_profitability.py
+++ b/erpnext/projects/report/project_profitability/test_project_profitability.py
@@ -8,7 +8,7 @@
from erpnext.projects.report.project_profitability.project_profitability import execute
class TestProjectProfitability(unittest.TestCase):
- @classmethod
+
def setUp(self):
emp = make_employee('test_employee_9@salary.com', company='_Test Company')
if not frappe.db.exists('Salary Component', 'Timesheet Component'):
@@ -21,7 +21,7 @@
self.sales_invoice.due_date = nowdate()
self.sales_invoice.submit()
- frappe.db.set_value("HR Settings", "HR Settings", "standard_working_hours", 8)
+ frappe.db.set_value('HR Settings', None, 'standard_working_hours', 8)
def test_project_profitability(self):
filters = {
@@ -55,4 +55,4 @@
def tearDown(self):
frappe.get_doc("Sales Invoice", self.sales_invoice.name).cancel()
frappe.get_doc("Salary Slip", self.salary_slip.name).cancel()
- frappe.get_doc("Timesheet", self.timesheet.name).cancel()
\ No newline at end of file
+ frappe.get_doc("Timesheet", self.timesheet.name).cancel()
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index cdfd909..e7dcd41 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -84,13 +84,13 @@
if (me.frm.doc.is_subcontracted == "Yes") {
return{
query: "erpnext.controllers.queries.item_query",
- filters:{ 'is_sub_contracted_item': 1 }
+ filters:{ 'supplier': me.frm.doc.supplier, 'is_sub_contracted_item': 1 }
}
}
else {
return{
query: "erpnext.controllers.queries.item_query",
- filters: {'is_purchase_item': 1}
+ filters: { 'supplier': me.frm.doc.supplier, 'is_purchase_item': 1 }
}
}
});
diff --git a/erpnext/regional/germany/utils/datev/datev_csv.py b/erpnext/regional/germany/utils/datev/datev_csv.py
index 826d51f..122c15f 100644
--- a/erpnext/regional/germany/utils/datev/datev_csv.py
+++ b/erpnext/regional/germany/utils/datev/datev_csv.py
@@ -55,8 +55,7 @@
quoting=QUOTE_NONNUMERIC
)
- if not six.PY2:
- data = data.encode('latin_1', errors='replace')
+ data = data.encode('latin_1', errors='replace')
header = get_header(filters, csv_class)
header = ';'.join(header).encode('latin_1', errors='replace')
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index 70e6d07..843fb01 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -43,7 +43,7 @@
invalid_supply_type = doc.get('gst_category') not in ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export']
company_transaction = doc.get('billing_address_gstin') == doc.get('company_gstin')
no_taxes_applied = not doc.get('taxes')
- has_non_gst_item = any(d for d in doc.get('items') if d.get('is_non_gst'))
+ has_non_gst_item = any(d for d in doc.get('items', []) if d.get('is_non_gst'))
if invalid_company or invalid_supply_type or company_transaction or no_taxes_applied or has_non_gst_item:
return False
@@ -534,11 +534,9 @@
return einvoice
def safe_json_load(json_string):
- JSONDecodeError = ValueError if six.PY2 else json.JSONDecodeError
-
try:
return json.loads(json_string)
- except JSONDecodeError as e:
+ except json.JSONDecodeError as e:
# print a snippet of 40 characters around the location where error occured
pos = e.pos
start, end = max(0, pos-20), min(len(json_string)-1, pos+20)
diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.py b/erpnext/setup/doctype/global_defaults/global_defaults.py
index e587217..a0ba1ef 100644
--- a/erpnext/setup/doctype/global_defaults/global_defaults.py
+++ b/erpnext/setup/doctype/global_defaults/global_defaults.py
@@ -59,13 +59,15 @@
# Make property setters to hide rounded total fields
for doctype in ("Quotation", "Sales Order", "Sales Invoice", "Delivery Note",
- "Supplier Quotation", "Purchase Order", "Purchase Invoice"):
+ "Supplier Quotation", "Purchase Order", "Purchase Invoice", "Purchase Receipt"):
make_property_setter(doctype, "base_rounded_total", "hidden", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
make_property_setter(doctype, "base_rounded_total", "print_hide", 1, "Check", validate_fields_for_doctype=False)
make_property_setter(doctype, "rounded_total", "hidden", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
make_property_setter(doctype, "rounded_total", "print_hide", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
+ make_property_setter(doctype, "disable_rounded_total", "default", cint(self.disable_rounded_total), "Text", validate_fields_for_doctype=False)
+
def toggle_in_words(self):
self.disable_in_words = cint(self.disable_in_words)
diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js
index db05739..a657ecf 100644
--- a/erpnext/stock/dashboard/item_dashboard.js
+++ b/erpnext/stock/dashboard/item_dashboard.js
@@ -230,7 +230,6 @@
},
],
});
- var submitted = false;
dialog.show();
dialog.get_field('item_code').set_input(item);
@@ -254,7 +253,6 @@
}
dialog.set_primary_action(__('Submit'), function () {
- if(submitted) return;
var values = dialog.get_values();
if (!values) {
return;
@@ -267,11 +265,12 @@
frappe.msgprint(__('Source and target warehouse must be different'));
}
- submitted = true;
frappe.call({
method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry',
args: values,
+ btn: dialog.get_primary_btn(),
freeze: true,
+ freeze_message: __('Creating Stock Entry'),
callback: function (r) {
frappe.show_alert(__('Stock Entry {0} created',
['<a href="/app/stock-entry/' + r.message.name + '">' + r.message.name + '</a>']));
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index daa1e51..de23e76 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -600,7 +600,6 @@
add_to_transit: function(frm) {
if(frm.doc.add_to_transit && frm.doc.purpose=='Material Transfer') {
frm.set_value('to_warehouse', '');
- frm.set_value('stock_entry_type', 'Material Transfer');
frm.fields_dict.to_warehouse.get_query = function() {
return {
filters:{
@@ -610,12 +609,13 @@
}
};
};
- frm.trigger('set_tansit_warehouse');
+ frm.trigger('set_transit_warehouse');
}
},
- set_tansit_warehouse: function(frm) {
- if(frm.doc.add_to_transit && frm.doc.purpose == 'Material Transfer' && !frm.doc.to_warehouse) {
+ set_transit_warehouse: function(frm) {
+ if(frm.doc.add_to_transit && frm.doc.purpose == 'Material Transfer' && !frm.doc.to_warehouse
+ && frm.doc.from_warehouse) {
let dt = frm.doc.from_warehouse ? 'Warehouse' : 'Company';
let dn = frm.doc.from_warehouse ? frm.doc.from_warehouse : frm.doc.company;
frappe.db.get_value(dt, dn, 'default_in_transit_warehouse', (r) => {
@@ -985,7 +985,7 @@
},
from_warehouse: function(doc) {
- this.frm.trigger('set_tansit_warehouse');
+ this.frm.trigger('set_transit_warehouse');
this.set_warehouse_in_children(doc.items, "s_warehouse", doc.from_warehouse);
},
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index 98c047a..7f94591 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -637,6 +637,8 @@
{
"default": "0",
"depends_on": "eval: doc.purpose=='Material Transfer' && !doc.outgoing_stock_entry",
+ "fetch_from": "stock_entry_type.add_to_transit",
+ "fetch_if_empty": 1,
"fieldname": "add_to_transit",
"fieldtype": "Check",
"label": "Add to Transit",
@@ -655,7 +657,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-12-09 14:58:13.267321",
+ "modified": "2021-05-21 11:29:11.917161",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry",
diff --git a/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json b/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json
index 0f2b55e..eee38be 100644
--- a/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json
+++ b/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json
@@ -6,7 +6,8 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "purpose"
+ "purpose",
+ "add_to_transit"
],
"fields": [
{
@@ -18,10 +19,17 @@
"options": "\nMaterial Issue\nMaterial Receipt\nMaterial Transfer\nMaterial Transfer for Manufacture\nMaterial Consumption for Manufacture\nManufacture\nRepack\nSend to Subcontractor",
"reqd": 1,
"set_only_once": 1
+ },
+ {
+ "default": "0",
+ "depends_on": "eval: doc.purpose == 'Material Transfer'",
+ "fieldname": "add_to_transit",
+ "fieldtype": "Check",
+ "label": "Add to Transit"
}
],
"links": [],
- "modified": "2020-08-10 23:24:37.160817",
+ "modified": "2021-05-21 11:27:01.144110",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry Type",
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 a4116ab..1069ec8 100644
--- a/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py
+++ b/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py
@@ -7,4 +7,6 @@
from frappe.model.document import Document
class StockEntryType(Document):
- pass
+ def validate(self):
+ if self.add_to_transit and self.purpose != 'Material Transfer':
+ self.add_to_transit = 0
diff --git a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
index 85c7ebe..6bbba05 100644
--- a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
+++ b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2015-02-17 01:06:05.072764",
"doctype": "DocType",
"document_type": "Other",
@@ -170,6 +171,7 @@
},
{
"default": "0",
+ "depends_on": "allow_zero_valuation_rate",
"fieldname": "allow_zero_valuation_rate",
"fieldtype": "Check",
"label": "Allow Zero Valuation Rate",
@@ -179,7 +181,7 @@
],
"istable": 1,
"links": [],
- "modified": "2021-03-23 11:09:44.407157",
+ "modified": "2021-05-21 12:13:33.041266",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Reconciliation Item",
@@ -189,4 +191,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
+}
\ No newline at end of file
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 e8449cc..d8563d7 100644
--- a/erpnext/stock/report/item_variant_details/item_variant_details.py
+++ b/erpnext/stock/report/item_variant_details/item_variant_details.py
@@ -14,47 +14,58 @@
if not item:
return []
item_dicts = []
- variants = None
- variant_results = frappe.db.sql("""select name from `tabItem`
- where variant_of = %s""", item, as_dict=1)
+ variant_results = frappe.db.get_all(
+ "Item",
+ fields=["name"],
+ filters={
+ "variant_of": ["=", item],
+ "disabled": 0
+ }
+ )
+
if not variant_results:
- frappe.msgprint(_("There isn't any item variant for the selected item"))
+ frappe.msgprint(_("There aren't any item variants for the selected item"))
return []
else:
- variants = ", ".join([frappe.db.escape(variant['name']) for variant in variant_results])
+ variant_list = [variant['name'] for variant in variant_results]
- order_count_map = get_open_sales_orders_map(variants)
- stock_details_map = get_stock_details_map(variants)
- buying_price_map = get_buying_price_map(variants)
- selling_price_map = get_selling_price_map(variants)
- attr_val_map = get_attribute_values_map(variants)
+ order_count_map = get_open_sales_orders_count(variant_list)
+ stock_details_map = get_stock_details_map(variant_list)
+ buying_price_map = get_buying_price_map(variant_list)
+ selling_price_map = get_selling_price_map(variant_list)
+ attr_val_map = get_attribute_values_map(variant_list)
- attribute_list = [d[0] for d in frappe.db.sql("""select attribute
- from `tabItem Variant Attribute`
- where parent in ({variants}) group by attribute""".format(variants=variants))]
+ attributes = frappe.db.get_all(
+ "Item Variant Attribute",
+ fields=["attribute"],
+ filters={
+ "parent": ["in", variant_list]
+ },
+ group_by="attribute"
+ )
+ attribute_list = [row.get("attribute") for row in attributes]
# Prepare dicts
variant_dicts = [{"variant_name": d['name']} for d in variant_results]
for item_dict in variant_dicts:
- name = item_dict["variant_name"]
+ name = item_dict.get("variant_name")
- for d in attribute_list:
- attr_dict = attr_val_map[name]
- if attr_dict and attr_dict.get(d):
- item_dict[d] = attr_val_map[name][d]
+ for attribute in attribute_list:
+ attr_dict = attr_val_map.get(name)
+ if attr_dict and attr_dict.get(attribute):
+ item_dict[frappe.scrub(attribute)] = attr_val_map.get(name).get(attribute)
- item_dict["Open Orders"] = order_count_map.get(name) or 0
+ item_dict["open_orders"] = order_count_map.get(name) or 0
if stock_details_map.get(name):
- item_dict["Inventory"] = stock_details_map.get(name)["Inventory"] or 0
- item_dict["In Production"] = stock_details_map.get(name)["In Production"] or 0
- item_dict["Available Selling"] = stock_details_map.get(name)["Available Selling"] or 0
+ item_dict["current_stock"] = stock_details_map.get(name)["Inventory"] or 0
+ item_dict["in_production"] = stock_details_map.get(name)["In Production"] or 0
else:
- item_dict["Inventory"] = item_dict["In Production"] = item_dict["Available Selling"] = 0
+ item_dict["current_stock"] = item_dict["in_production"] = 0
- item_dict["Avg. Buying Price List Rate"] = buying_price_map.get(name) or 0
- item_dict["Avg. Selling Price List Rate"] = selling_price_map.get(name) or 0
+ item_dict["avg_buying_price_list_rate"] = buying_price_map.get(name) or 0
+ item_dict["avg_selling_price_list_rate"] = selling_price_map.get(name) or 0
item_dicts.append(item_dict)
@@ -71,117 +82,158 @@
item_doc = frappe.get_doc("Item", item)
- for d in item_doc.attributes:
- columns.append(d.attribute + ":Data:100")
+ for entry in item_doc.attributes:
+ columns.append({
+ "fieldname": frappe.scrub(entry.attribute),
+ "label": entry.attribute,
+ "fieldtype": "Data",
+ "width": 100
+ })
- columns += [_("Avg. Buying Price List Rate") + ":Currency:110", _("Avg. Selling Price List Rate") + ":Currency:110",
- _("Inventory") + ":Float:100", _("In Production") + ":Float:100",
- _("Open Orders") + ":Float:100", _("Available Selling") + ":Float:100"
+ additional_columns = [
+ {
+ "fieldname": "avg_buying_price_list_rate",
+ "label": _("Avg. Buying Price List Rate"),
+ "fieldtype": "Currency",
+ "width": 150
+ },
+ {
+ "fieldname": "avg_selling_price_list_rate",
+ "label": _("Avg. Selling Price List Rate"),
+ "fieldtype": "Currency",
+ "width": 150
+ },
+ {
+ "fieldname": "current_stock",
+ "label": _("Current Stock"),
+ "fieldtype": "Float",
+ "width": 120
+ },
+ {
+ "fieldname": "in_production",
+ "label": _("In Production"),
+ "fieldtype": "Float",
+ "width": 150
+ },
+ {
+ "fieldname": "open_orders",
+ "label": _("Open Sales Orders"),
+ "fieldtype": "Float",
+ "width": 150
+ }
]
+ columns.extend(additional_columns)
return columns
-def get_open_sales_orders_map(variants):
- open_sales_orders = frappe.db.sql("""
- select
- count(*) as count,
- item_code
- from
- `tabSales Order Item`
- where
- docstatus = 1 and
- qty > ifnull(delivered_qty, 0) and
- item_code in ({variants})
- group by
- item_code
- """.format(variants=variants), as_dict=1)
+def get_open_sales_orders_count(variants_list):
+ open_sales_orders = frappe.db.get_list(
+ "Sales Order",
+ fields=[
+ "name",
+ "`tabSales Order Item`.item_code"
+ ],
+ filters=[
+ ["Sales Order", "docstatus", "=", 1],
+ ["Sales Order Item", "item_code", "in", variants_list]
+ ],
+ distinct=1
+ )
order_count_map = {}
- for d in open_sales_orders:
- order_count_map[d["item_code"]] = d["count"]
+ for row in open_sales_orders:
+ item_code = row.get("item_code")
+ if order_count_map.get(item_code) is None:
+ order_count_map[item_code] = 1
+ else:
+ order_count_map[item_code] += 1
return order_count_map
-def get_stock_details_map(variants):
- stock_details = frappe.db.sql("""
- select
- sum(planned_qty) as planned_qty,
- sum(actual_qty) as actual_qty,
- sum(projected_qty) as projected_qty,
- item_code
- from
- `tabBin`
- where
- item_code in ({variants})
- group by
- item_code
- """.format(variants=variants), as_dict=1)
+def get_stock_details_map(variant_list):
+ stock_details = frappe.db.get_all(
+ "Bin",
+ fields=[
+ "sum(planned_qty) as planned_qty",
+ "sum(actual_qty) as actual_qty",
+ "sum(projected_qty) as projected_qty",
+ "item_code",
+ ],
+ filters={
+ "item_code": ["in", variant_list]
+ },
+ group_by="item_code"
+ )
stock_details_map = {}
- for d in stock_details:
- name = d["item_code"]
+ for row in stock_details:
+ name = row.get("item_code")
stock_details_map[name] = {
- "Inventory" :d["actual_qty"],
- "In Production" :d["planned_qty"],
- "Available Selling" :d["projected_qty"]
+ "Inventory": row.get("actual_qty"),
+ "In Production": row.get("planned_qty")
}
return stock_details_map
-def get_buying_price_map(variants):
- buying = frappe.db.sql("""
- select
- avg(price_list_rate) as avg_rate,
- item_code
- from
- `tabItem Price`
- where
- item_code in ({variants}) and buying=1
- group by
- item_code
- """.format(variants=variants), as_dict=1)
+def get_buying_price_map(variant_list):
+ buying = frappe.db.get_all(
+ "Item Price",
+ fields=[
+ "avg(price_list_rate) as avg_rate",
+ "item_code",
+ ],
+ filters={
+ "item_code": ["in", variant_list],
+ "buying": 1
+ },
+ group_by="item_code"
+ )
buying_price_map = {}
- for d in buying:
- buying_price_map[d["item_code"]] = d["avg_rate"]
+ for row in buying:
+ buying_price_map[row.get("item_code")] = row.get("avg_rate")
return buying_price_map
-def get_selling_price_map(variants):
- selling = frappe.db.sql("""
- select
- avg(price_list_rate) as avg_rate,
- item_code
- from
- `tabItem Price`
- where
- item_code in ({variants}) and selling=1
- group by
- item_code
- """.format(variants=variants), as_dict=1)
+def get_selling_price_map(variant_list):
+ selling = frappe.db.get_all(
+ "Item Price",
+ fields=[
+ "avg(price_list_rate) as avg_rate",
+ "item_code",
+ ],
+ filters={
+ "item_code": ["in", variant_list],
+ "selling": 1
+ },
+ group_by="item_code"
+ )
selling_price_map = {}
- for d in selling:
- selling_price_map[d["item_code"]] = d["avg_rate"]
+ for row in selling:
+ selling_price_map[row.get("item_code")] = row.get("avg_rate")
return selling_price_map
-def get_attribute_values_map(variants):
- list_attr = frappe.db.sql("""
- select
- attribute, attribute_value, parent
- from
- `tabItem Variant Attribute`
- where
- parent in ({variants})
- """.format(variants=variants), as_dict=1)
+def get_attribute_values_map(variant_list):
+ attribute_list = frappe.db.get_all(
+ "Item Variant Attribute",
+ fields=[
+ "attribute",
+ "attribute_value",
+ "parent"
+ ],
+ filters={
+ "parent": ["in", variant_list]
+ }
+ )
attr_val_map = {}
- for d in list_attr:
- name = d["parent"]
+ for row in attribute_list:
+ name = row.get("parent")
if not attr_val_map.get(name):
attr_val_map[name] = {}
- attr_val_map[name][d["attribute"]] = d["attribute_value"]
+ attr_val_map[name][row.get("attribute")] = row.get("attribute_value")
return attr_val_map
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 9729987..b2825fc 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -232,7 +232,8 @@
and is_cancelled = 0
and timestamp(posting_date, time_format(posting_time, %(time_format)s)) < timestamp(%(posting_date)s, time_format(%(posting_time)s, %(time_format)s))
order by timestamp(posting_date, posting_time) desc, creation desc
- limit 1""", args, as_dict=1)
+ limit 1
+ for update""", args, as_dict=1)
return sle[0] if sle else frappe._dict()
@@ -623,7 +624,7 @@
break
# If no entry found with outgoing rate, collapse stack
- if index == None:
+ if index is None: # nosemgrep
new_stock_value = sum((d[0]*d[1] for d in self.wh_data.stock_queue)) - qty_to_pop*outgoing_rate
new_stock_qty = sum((d[0] for d in self.wh_data.stock_queue)) - qty_to_pop
self.wh_data.stock_queue = [[new_stock_qty, new_stock_value/new_stock_qty if new_stock_qty > 0 else outgoing_rate]]
diff --git a/requirements.txt b/requirements.txt
index f1ffeb8..32da48e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -10,4 +10,3 @@
taxjar~=1.9.2
tweepy~=3.10.0
Unidecode~=1.2.0
-WooCommerce~=3.0.0