Merge pull request #22096 from marination/valuation-rate
fix: '>=' not supported between instances of 'str' and 'int'
diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml
new file mode 100644
index 0000000..d36b115
--- /dev/null
+++ b/.github/workflows/docker-release.yml
@@ -0,0 +1,14 @@
+name: Trigger Docker build on release
+on:
+ release:
+ types: [created]
+jobs:
+ curl:
+ runs-on: ubuntu-latest
+ container:
+ image: alpine:latest
+ steps:
+ - name: curl
+ run: |
+ apk add curl bash
+ curl -s -X POST -H "Content-Type: application/json" -H "Accept: application/json" -H "Travis-API-Version: 3" -H "Authorization: token ${{ secrets.TRAVIS_CI_TOKEN }}" -d '{"request":{"branch":"master"}}' https://api.travis-ci.org/repo/frappe%2Ffrappe_docker/requests
diff --git a/CODEOWNERS b/CODEOWNERS
index 5e1113d..7cf65a7 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -3,17 +3,16 @@
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
-* @nabinhait
-manufacturing/ @rohitwaghchaure
+manufacturing/ @rohitwaghchaure @marination
accounts/ @deepeshgarg007 @nextchamp-saqib
-loan_management/ @deepeshgarg007
-pos* @nextchamp-saqib
-assets/ @nextchamp-saqib
+loan_management/ @deepeshgarg007 @rohitwaghchaure
+pos* @nextchamp-saqib @rohitwaghchaure
+assets/ @nextchamp-saqib @deepeshgarg007
stock/ @marination @rohitwaghchaure
-buying/ @marination @rohitwaghchaure
-hr/ @Anurag810
-projects/ @hrwX
-support/ @hrwX
-healthcare/ @ruchamahabal
-erpnext_integrations/ @Mangesh-Khairnar
+buying/ @marination @deepeshgarg007
+hr/ @Anurag810 @rohitwaghchaure
+projects/ @hrwX @nextchamp-saqib
+support/ @hrwX @marination
+healthcare/ @ruchamahabal @marination
+erpnext_integrations/ @Mangesh-Khairnar @nextchamp-saqib
requirements.txt @gavindsouza
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.js b/erpnext/accounts/doctype/cost_center/cost_center.js
index 9e2f6ee..f341f78 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.js
+++ b/erpnext/accounts/doctype/cost_center/cost_center.js
@@ -14,7 +14,18 @@
is_group: 1
}
}
- })
+ });
+
+ frm.set_query("cost_center", "distributed_cost_center", function() {
+ return {
+ filters: {
+ company: frm.doc.company,
+ is_group: 0,
+ enable_distributed_cost_center: 0,
+ name: ['!=', frm.doc.name]
+ }
+ };
+ });
},
refresh: function(frm) {
if (!frm.is_new()) {
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.json b/erpnext/accounts/doctype/cost_center/cost_center.json
index 5013c92..c9bbbab 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.json
+++ b/erpnext/accounts/doctype/cost_center/cost_center.json
@@ -16,6 +16,9 @@
"cb0",
"is_group",
"disabled",
+ "section_break_9",
+ "enable_distributed_cost_center",
+ "distributed_cost_center",
"lft",
"rgt",
"old_parent"
@@ -119,6 +122,24 @@
"fieldname": "disabled",
"fieldtype": "Check",
"label": "Disabled"
+ },
+ {
+ "default": "0",
+ "fieldname": "enable_distributed_cost_center",
+ "fieldtype": "Check",
+ "label": "Enable Distributed Cost Center"
+ },
+ {
+ "depends_on": "eval:doc.is_group==0",
+ "fieldname": "section_break_9",
+ "fieldtype": "Section Break"
+ },
+ {
+ "depends_on": "enable_distributed_cost_center",
+ "fieldname": "distributed_cost_center",
+ "fieldtype": "Table",
+ "label": "Distributed Cost Center",
+ "options": "Distributed Cost Center"
}
],
"icon": "fa fa-money",
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.py b/erpnext/accounts/doctype/cost_center/cost_center.py
index 0294e78..12094d4 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.py
+++ b/erpnext/accounts/doctype/cost_center/cost_center.py
@@ -19,6 +19,24 @@
def validate(self):
self.validate_mandatory()
self.validate_parent_cost_center()
+ self.validate_distributed_cost_center()
+
+ def validate_distributed_cost_center(self):
+ if cint(self.enable_distributed_cost_center):
+ if not self.distributed_cost_center:
+ frappe.throw(_("Please enter distributed cost center"))
+ if sum(x.percentage_allocation for x in self.distributed_cost_center) != 100:
+ frappe.throw(_("Total percentage allocation for distributed cost center should be equal to 100"))
+ if not self.get('__islocal'):
+ if not cint(frappe.get_cached_value("Cost Center", {"name": self.name}, "enable_distributed_cost_center")) \
+ and self.check_if_part_of_distributed_cost_center():
+ frappe.throw(_("Cannot enable Distributed Cost Center for a Cost Center already allocated in another Distributed Cost Center"))
+ if next((True for x in self.distributed_cost_center if x.cost_center == x.parent), False):
+ frappe.throw(_("Parent Cost Center cannot be added in Distributed Cost Center"))
+ if check_if_distributed_cost_center_enabled(list(x.cost_center for x in self.distributed_cost_center)):
+ frappe.throw(_("A Distributed Cost Center cannot be added in the Distributed Cost Center allocation table."))
+ else:
+ self.distributed_cost_center = []
def validate_mandatory(self):
if self.cost_center_name != self.company and not self.parent_cost_center:
@@ -43,12 +61,15 @@
return 1
def convert_ledger_to_group(self):
+ if cint(self.enable_distributed_cost_center):
+ frappe.throw(_("Cost Center with enabled distributed cost center can not be converted to group"))
+ if self.check_if_part_of_distributed_cost_center():
+ frappe.throw(_("Cost Center Already Allocated in a Distributed Cost Center cannot be converted to group"))
if self.check_gle_exists():
frappe.throw(_("Cost Center with existing transactions can not be converted to group"))
- else:
- self.is_group = 1
- self.save()
- return 1
+ self.is_group = 1
+ self.save()
+ return 1
def check_gle_exists(self):
return frappe.db.get_value("GL Entry", {"cost_center": self.name})
@@ -57,6 +78,9 @@
return frappe.db.sql("select name from `tabCost Center` where \
parent_cost_center = %s and docstatus != 2", self.name)
+ def check_if_part_of_distributed_cost_center(self):
+ return frappe.db.get_value("Distributed Cost Center", {"cost_center": self.name})
+
def before_rename(self, olddn, newdn, merge=False):
# Add company abbr if not provided
from erpnext.setup.doctype.company.company import get_name_with_abbr
@@ -100,3 +124,7 @@
if account_number and not new_account[0].isdigit():
new_account = account_number + " - " + new_account
return new_account
+
+def check_if_distributed_cost_center_enabled(cost_center_list):
+ value_list = frappe.get_list("Cost Center", {"name": ["in", cost_center_list]}, "enable_distributed_cost_center", as_list=1)
+ return next((True for x in value_list if x[0]), False)
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/cost_center/test_cost_center.py b/erpnext/accounts/doctype/cost_center/test_cost_center.py
index 8f23d90..b5fc7e3 100644
--- a/erpnext/accounts/doctype/cost_center/test_cost_center.py
+++ b/erpnext/accounts/doctype/cost_center/test_cost_center.py
@@ -22,6 +22,33 @@
self.assertRaises(frappe.ValidationError, cost_center.save)
+ def test_validate_distributed_cost_center(self):
+
+ if not frappe.db.get_value('Cost Center', {'name': '_Test Cost Center - _TC'}):
+ frappe.get_doc(test_records[0]).insert()
+
+ if not frappe.db.get_value('Cost Center', {'name': '_Test Cost Center 2 - _TC'}):
+ frappe.get_doc(test_records[1]).insert()
+
+ invalid_distributed_cost_center = frappe.get_doc({
+ "company": "_Test Company",
+ "cost_center_name": "_Test Distributed Cost Center",
+ "doctype": "Cost Center",
+ "is_group": 0,
+ "parent_cost_center": "_Test Company - _TC",
+ "enable_distributed_cost_center": 1,
+ "distributed_cost_center": [{
+ "cost_center": "_Test Cost Center - _TC",
+ "percentage_allocation": 40
+ }, {
+ "cost_center": "_Test Cost Center 2 - _TC",
+ "percentage_allocation": 50
+ }
+ ]
+ })
+
+ self.assertRaises(frappe.ValidationError, invalid_distributed_cost_center.save)
+
def create_cost_center(**args):
args = frappe._dict(args)
if args.cost_center_name:
diff --git a/erpnext/accounts/doctype/distributed_cost_center/__init__.py b/erpnext/accounts/doctype/distributed_cost_center/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/distributed_cost_center/__init__.py
diff --git a/erpnext/accounts/doctype/distributed_cost_center/distributed_cost_center.json b/erpnext/accounts/doctype/distributed_cost_center/distributed_cost_center.json
new file mode 100644
index 0000000..45b0e2d
--- /dev/null
+++ b/erpnext/accounts/doctype/distributed_cost_center/distributed_cost_center.json
@@ -0,0 +1,40 @@
+{
+ "actions": [],
+ "creation": "2020-03-19 12:34:01.500390",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "cost_center",
+ "percentage_allocation"
+ ],
+ "fields": [
+ {
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Cost Center",
+ "options": "Cost Center",
+ "reqd": 1
+ },
+ {
+ "fieldname": "percentage_allocation",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Percentage Allocation",
+ "reqd": 1
+ }
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2020-03-19 12:54:43.674655",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Distributed Cost Center",
+ "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/accounts/doctype/distributed_cost_center/distributed_cost_center.py b/erpnext/accounts/doctype/distributed_cost_center/distributed_cost_center.py
new file mode 100644
index 0000000..48c589f
--- /dev/null
+++ b/erpnext/accounts/doctype/distributed_cost_center/distributed_cost_center.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class DistributedCostCenter(Document):
+ pass
diff --git a/erpnext/accounts/doctype/shipping_rule/shipping_rule.py b/erpnext/accounts/doctype/shipping_rule/shipping_rule.py
index b2638c7..d32a348 100644
--- a/erpnext/accounts/doctype/shipping_rule/shipping_rule.py
+++ b/erpnext/accounts/doctype/shipping_rule/shipping_rule.py
@@ -45,7 +45,9 @@
shipping_amount = 0.0
by_value = False
- self.validate_countries(doc)
+ if doc.get_shipping_address():
+ # validate country only if there is address
+ self.validate_countries(doc)
if self.calculate_based_on == 'Net Total':
value = doc.base_net_total
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
index 05dc282..9c9ada8 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
@@ -29,37 +29,60 @@
for dimension in dimensions:
dimension_items = cam_map.get(dimension)
if dimension_items:
- for account, monthwise_data in iteritems(dimension_items):
- row = [dimension, account]
- totals = [0, 0, 0]
- for year in get_fiscal_years(filters):
- last_total = 0
- for relevant_months in period_month_ranges:
- period_data = [0, 0, 0]
- for month in relevant_months:
- if monthwise_data.get(year[0]):
- month_data = monthwise_data.get(year[0]).get(month, {})
- for i, fieldname in enumerate(["target", "actual", "variance"]):
- value = flt(month_data.get(fieldname))
- period_data[i] += value
- totals[i] += value
-
- period_data[0] += last_total
-
- if filters.get("show_cumulative"):
- last_total = period_data[0] - period_data[1]
-
- period_data[2] = period_data[0] - period_data[1]
- row += period_data
- totals[2] = totals[0] - totals[1]
- if filters["period"] != "Yearly":
- row += totals
- data.append(row)
+ data = get_final_data(dimension, dimension_items, filters, period_month_ranges, data, 0)
+ else:
+ DCC_allocation = frappe.db.sql('''SELECT parent, sum(percentage_allocation) as percentage_allocation
+ FROM `tabDistributed Cost Center`
+ WHERE cost_center IN %(dimension)s
+ AND parent NOT IN %(dimension)s
+ GROUP BY parent''',{'dimension':[dimension]})
+ if DCC_allocation:
+ filters['budget_against_filter'] = [DCC_allocation[0][0]]
+ cam_map = get_dimension_account_month_map(filters)
+ dimension_items = cam_map.get(DCC_allocation[0][0])
+ if dimension_items:
+ data = get_final_data(dimension, dimension_items, filters, period_month_ranges, data, DCC_allocation[0][1])
chart = get_chart_data(filters, columns, data)
return columns, data, None, chart
+def get_final_data(dimension, dimension_items, filters, period_month_ranges, data, DCC_allocation):
+
+ for account, monthwise_data in iteritems(dimension_items):
+ row = [dimension, account]
+ totals = [0, 0, 0]
+ for year in get_fiscal_years(filters):
+ last_total = 0
+ for relevant_months in period_month_ranges:
+ period_data = [0, 0, 0]
+ for month in relevant_months:
+ if monthwise_data.get(year[0]):
+ month_data = monthwise_data.get(year[0]).get(month, {})
+ for i, fieldname in enumerate(["target", "actual", "variance"]):
+ value = flt(month_data.get(fieldname))
+ period_data[i] += value
+ totals[i] += value
+
+ period_data[0] += last_total
+
+ if DCC_allocation:
+ period_data[0] = period_data[0]*(DCC_allocation/100)
+ period_data[1] = period_data[1]*(DCC_allocation/100)
+
+ if(filters.get("show_cumulative")):
+ last_total = period_data[0] - period_data[1]
+
+ period_data[2] = period_data[0] - period_data[1]
+ row += period_data
+ totals[2] = totals[0] - totals[1]
+ if filters["period"] != "Yearly" :
+ row += totals
+ data.append(row)
+
+ return data
+
+
def get_columns(filters):
columns = [
{
@@ -366,7 +389,7 @@
budget_values[i] += values[index]
actual_values[i] += values[index+1]
index += 3
-
+
return {
'data': {
'labels': labels,
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 4a35a66..0339e49 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -387,11 +387,41 @@
key: value
})
+ distributed_cost_center_query = ""
+ if filters and filters.get('cost_center'):
+ distributed_cost_center_query = """
+ UNION ALL
+ SELECT posting_date,
+ account,
+ debit*(DCC_allocation.percentage_allocation/100) as debit,
+ credit*(DCC_allocation.percentage_allocation/100) as credit,
+ is_opening,
+ fiscal_year,
+ debit_in_account_currency*(DCC_allocation.percentage_allocation/100) as debit_in_account_currency,
+ credit_in_account_currency*(DCC_allocation.percentage_allocation/100) as credit_in_account_currency,
+ account_currency
+ FROM `tabGL Entry`,
+ (
+ SELECT parent, sum(percentage_allocation) as percentage_allocation
+ FROM `tabDistributed Cost Center`
+ WHERE cost_center IN %(cost_center)s
+ AND parent NOT IN %(cost_center)s
+ GROUP BY parent
+ ) as DCC_allocation
+ WHERE company=%(company)s
+ {additional_conditions}
+ AND posting_date <= %(to_date)s
+ AND cost_center = DCC_allocation.parent
+ """.format(additional_conditions=additional_conditions.replace("and cost_center in %(cost_center)s ", ''))
+
gl_entries = frappe.db.sql("""select posting_date, account, debit, credit, is_opening, fiscal_year, debit_in_account_currency, credit_in_account_currency, account_currency from `tabGL Entry`
where company=%(company)s
{additional_conditions}
and posting_date <= %(to_date)s
- order by account, posting_date""".format(additional_conditions=additional_conditions), gl_filters, as_dict=True) #nosec
+ {distributed_cost_center_query}
+ order by account, posting_date""".format(
+ additional_conditions=additional_conditions,
+ distributed_cost_center_query=distributed_cost_center_query), gl_filters, as_dict=True) #nosec
if filters and filters.get('presentation_currency'):
convert_to_presentation_currency(gl_entries, get_currency(filters))
@@ -489,4 +519,4 @@
"width": 150
})
- return columns
+ return columns
\ No newline at end of file
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index f83a259..fcd36e4 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -128,18 +128,53 @@
filters['company_fb'] = frappe.db.get_value("Company",
filters.get("company"), 'default_finance_book')
+ distributed_cost_center_query = ""
+ if filters and filters.get('cost_center'):
+ select_fields_with_percentage = """, debit*(DCC_allocation.percentage_allocation/100) as debit, credit*(DCC_allocation.percentage_allocation/100) as credit, debit_in_account_currency*(DCC_allocation.percentage_allocation/100) as debit_in_account_currency,
+ credit_in_account_currency*(DCC_allocation.percentage_allocation/100) as credit_in_account_currency """
+
+ distributed_cost_center_query = """
+ UNION ALL
+ SELECT name as gl_entry,
+ posting_date,
+ account,
+ party_type,
+ party,
+ voucher_type,
+ voucher_no,
+ cost_center, project,
+ against_voucher_type,
+ against_voucher,
+ account_currency,
+ remarks, against,
+ is_opening, `tabGL Entry`.creation {select_fields_with_percentage}
+ FROM `tabGL Entry`,
+ (
+ SELECT parent, sum(percentage_allocation) as percentage_allocation
+ FROM `tabDistributed Cost Center`
+ WHERE cost_center IN %(cost_center)s
+ AND parent NOT IN %(cost_center)s
+ GROUP BY parent
+ ) as DCC_allocation
+ WHERE company=%(company)s
+ {conditions}
+ AND posting_date <= %(to_date)s
+ AND cost_center = DCC_allocation.parent
+ """.format(select_fields_with_percentage=select_fields_with_percentage, conditions=get_conditions(filters).replace("and cost_center in %(cost_center)s ", ''))
+
gl_entries = frappe.db.sql(
"""
select
name as gl_entry, posting_date, account, party_type, party,
voucher_type, voucher_no, cost_center, project,
against_voucher_type, against_voucher, account_currency,
- remarks, against, is_opening {select_fields}
+ remarks, against, is_opening, creation {select_fields}
from `tabGL Entry`
where company=%(company)s {conditions}
+ {distributed_cost_center_query}
{order_by_statement}
""".format(
- select_fields=select_fields, conditions=get_conditions(filters),
+ select_fields=select_fields, conditions=get_conditions(filters), distributed_cost_center_query=distributed_cost_center_query,
order_by_statement=order_by_statement
),
filters, as_dict=1)
diff --git a/erpnext/accounts/report/profitability_analysis/profitability_analysis.py b/erpnext/accounts/report/profitability_analysis/profitability_analysis.py
index 6e9b31f..60e675f 100644
--- a/erpnext/accounts/report/profitability_analysis/profitability_analysis.py
+++ b/erpnext/accounts/report/profitability_analysis/profitability_analysis.py
@@ -105,6 +105,7 @@
def prepare_data(accounts, filters, total_row, parent_children_map, based_on):
data = []
+ new_accounts = accounts
company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency")
for d in accounts:
@@ -118,6 +119,19 @@
"currency": company_currency,
"based_on": based_on
}
+ if based_on == 'cost_center':
+ cost_center_doc = frappe.get_doc("Cost Center",d.name)
+ if not cost_center_doc.enable_distributed_cost_center:
+ DCC_allocation = frappe.db.sql("""SELECT parent, sum(percentage_allocation) as percentage_allocation
+ FROM `tabDistributed Cost Center`
+ WHERE cost_center IN %(cost_center)s
+ AND parent NOT IN %(cost_center)s
+ GROUP BY parent""",{'cost_center': [d.name]})
+ if DCC_allocation:
+ for account in new_accounts:
+ if account['name'] == DCC_allocation[0][0]:
+ for value in value_fields:
+ d[value] += account[value]*(DCC_allocation[0][1]/100)
for key in value_fields:
row[key] = flt(d.get(key, 0.0), 3)
diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py
index 4ac0f65..a9fb237 100644
--- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py
+++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py
@@ -111,7 +111,7 @@
# {"purchase_invoice": list of dict of all gle created for this invoice}
gle_map = {}
gle = frappe.db.get_all('GL Entry',\
- {"voucher_no": ["in", [d.get("name") for d in filters["invoices"]]]},
+ {"voucher_no": ["in", [d.get("name") for d in filters["invoices"]]], 'is_cancelled': 0},
["fiscal_year", "credit", "debit", "account", "voucher_no", "posting_date"])
for d in gle:
diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py
index 29f8dd5..50b17ab 100644
--- a/erpnext/controllers/item_variant.py
+++ b/erpnext/controllers/item_variant.py
@@ -70,7 +70,7 @@
else:
attributes_list = attribute_values.get(attribute.lower(), [])
- validate_item_attribute_value(attributes_list, attribute, value, item.name)
+ validate_item_attribute_value(attributes_list, attribute, value, item.name, from_variant=True)
def validate_is_incremental(numeric_attribute, attribute, value, item):
from_range = numeric_attribute.from_range
@@ -93,13 +93,20 @@
.format(attribute, from_range, to_range, increment, item),
InvalidItemAttributeValueError, title=_('Invalid Attribute'))
-def validate_item_attribute_value(attributes_list, attribute, attribute_value, item):
+def validate_item_attribute_value(attributes_list, attribute, attribute_value, item, from_variant=True):
allow_rename_attribute_value = frappe.db.get_single_value('Item Variant Settings', 'allow_rename_attribute_value')
if allow_rename_attribute_value:
pass
elif attribute_value not in attributes_list:
- frappe.throw(_("The value {0} is already assigned to an exisiting Item {2}.").format(
- attribute_value, attribute, item), InvalidItemAttributeValueError, title=_('Rename Not Allowed'))
+ if from_variant:
+ frappe.throw(_("{0} is not a valid Value for Attribute {1} of Item {2}.").format(
+ frappe.bold(attribute_value), frappe.bold(attribute), frappe.bold(item)), InvalidItemAttributeValueError, title=_("Invalid Value"))
+ else:
+ msg = _("The value {0} is already assigned to an exisiting Item {1}.").format(
+ frappe.bold(attribute_value), frappe.bold(item))
+ msg += "<br>" + _("To still proceed with editing this Attribute Value, enable {0} in Item Variant Settings.").format(frappe.bold("Allow Rename Attribute Value"))
+
+ frappe.throw(msg, InvalidItemAttributeValueError, title=_('Edit Not Allowed'))
def get_attribute_values(item):
if not frappe.flags.attribute_values:
diff --git a/erpnext/education/doctype/program_course/program_course.json b/erpnext/education/doctype/program_course/program_course.json
index a24e88a..940358e 100644
--- a/erpnext/education/doctype/program_course/program_course.json
+++ b/erpnext/education/doctype/program_course/program_course.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2015-09-07 14:37:01.886859",
"doctype": "DocType",
"editable_grid": 1,
@@ -16,26 +17,33 @@
"in_list_view": 1,
"label": "Course",
"options": "Course",
- "reqd": 1
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
- {
+ {
+ "fetch_from": "course.course_name",
"fieldname": "course_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Course Name",
- "fetch_from": "course.course_name",
- "read_only":1
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
},
{
"default": "0",
"fieldname": "required",
"fieldtype": "Check",
"in_list_view": 1,
- "label": "Mandatory"
+ "label": "Mandatory",
+ "show_days": 1,
+ "show_seconds": 1
}
],
"istable": 1,
- "modified": "2019-06-12 12:42:12.845972",
+ "links": [],
+ "modified": "2020-06-09 18:56:10.213241",
"modified_by": "Administrator",
"module": "Education",
"name": "Program Course",
@@ -45,4 +53,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/connectors/shopify_connection.py b/erpnext/erpnext_integrations/connectors/shopify_connection.py
index 7046038..d59f909 100644
--- a/erpnext/erpnext_integrations/connectors/shopify_connection.py
+++ b/erpnext/erpnext_integrations/connectors/shopify_connection.py
@@ -241,14 +241,17 @@
return taxes
def update_taxes_with_shipping_lines(taxes, shipping_lines, shopify_settings):
+ """Shipping lines represents the shipping details,
+ each such shipping detail consists of a list of tax_lines"""
for shipping_charge in shipping_lines:
- taxes.append({
- "charge_type": _("Actual"),
- "account_head": get_tax_account_head(shipping_charge),
- "description": shipping_charge["title"],
- "tax_amount": shipping_charge["price"],
- "cost_center": shopify_settings.cost_center
- })
+ for tax in shipping_charge.get("tax_lines"):
+ taxes.append({
+ "charge_type": _("Actual"),
+ "account_head": get_tax_account_head(tax),
+ "description": tax["title"],
+ "tax_amount": tax["price"],
+ "cost_center": shopify_settings.cost_center
+ })
return taxes
diff --git a/erpnext/hr/desk_page/hr/hr.json b/erpnext/hr/desk_page/hr/hr.json
index 7ac000b..1c24444 100644
--- a/erpnext/hr/desk_page/hr/hr.json
+++ b/erpnext/hr/desk_page/hr/hr.json
@@ -18,7 +18,7 @@
{
"hidden": 0,
"label": "Leaves",
- "links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Application\",\n \"name\": \"Leave Application\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Allocation\",\n \"name\": \"Leave Allocation\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Leave Type\"\n ],\n \"label\": \"Leave Policy\",\n \"name\": \"Leave Policy\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Period\",\n \"name\": \"Leave Period\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Leave Type\",\n \"name\": \"Leave Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Holiday List\",\n \"name\": \"Holiday List\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Compensatory Leave Request\",\n \"name\": \"Compensatory Leave Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Encashment\",\n \"name\": \"Leave Encashment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Leave Block List\",\n \"name\": \"Leave Block List\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Leave Application\"\n ],\n \"doctype\": \"Leave Application\",\n \"is_query_report\": true,\n \"label\": \"Employee Leave Balance\",\n \"name\": \"Employee Leave Balance\",\n \"type\": \"report\"\n }\n]"
+ "links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Application\",\n \"name\": \"Leave Application\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Allocation\",\n \"name\": \"Leave Allocation\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Leave Type\"\n ],\n \"label\": \"Leave Policy\",\n \"name\": \"Leave Policy\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Leave Period\",\n \"name\": \"Leave Period\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Leave Type\",\n \"name\": \"Leave Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Holiday List\",\n \"name\": \"Holiday List\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Compensatory Leave Request\",\n \"name\": \"Compensatory Leave Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Encashment\",\n \"name\": \"Leave Encashment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Leave Block List\",\n \"name\": \"Leave Block List\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Leave Application\"\n ],\n \"doctype\": \"Leave Application\",\n \"is_query_report\": true,\n \"label\": \"Employee Leave Balance\",\n \"name\": \"Employee Leave Balance\",\n \"type\": \"report\"\n }\n]"
},
{
"hidden": 0,
@@ -93,7 +93,7 @@
"idx": 0,
"is_standard": 1,
"label": "HR",
- "modified": "2020-05-28 13:36:07.710600",
+ "modified": "2020-06-10 12:41:41.695669",
"modified_by": "Administrator",
"module": "HR",
"name": "HR",
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js
index fb23103..6bb9af9 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.js
@@ -243,7 +243,6 @@
},
update_employee_advance_claimed_amount: function(frm) {
- console.log("update_employee_advance_claimed_amount")
let amount_to_be_allocated = frm.doc.grand_total;
$.each(frm.doc.advances || [], function(i, advance){
if (amount_to_be_allocated >= advance.unclaimed_amount){
@@ -295,6 +294,16 @@
frm.events.get_advances(frm);
},
+ cost_center: function(frm) {
+ frm.events.set_child_cost_center(frm);
+ },
+ set_child_cost_center: function(frm){
+ (frm.doc.expenses || []).forEach(function(d) {
+ if (!d.cost_center){
+ d.cost_center = frm.doc.cost_center;
+ }
+ });
+ },
get_taxes: function(frm) {
if(frm.doc.taxes) {
frappe.call({
@@ -338,8 +347,7 @@
frappe.ui.form.on("Expense Claim Detail", {
expenses_add: function(frm, cdt, cdn) {
- var row = frappe.get_doc(cdt, cdn);
- frm.script_manager.copy_from_first_row("expenses", row, ["cost_center"]);
+ frm.events.set_child_cost_center(frm);
},
amount: function(frm, cdt, cdn) {
var child = locals[cdt][cdn];
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index 473aae6..15ce468 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -38,6 +38,9 @@
},
validate: function(frm) {
+ if (frm.doc.from_date == frm.doc.to_date && frm.doc.half_day == 1){
+ frm.doc.half_day_date = frm.doc.from_date;
+ }
frm.toggle_reqd("half_day_date", frm.doc.half_day == 1);
},
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index f2968bc..c2b4cdf 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -33,6 +33,7 @@
self.validate_block_days()
self.validate_salary_processed_days()
self.validate_attendance()
+ self.set_half_day_date()
if frappe.db.get_value("Leave Type", self.leave_type, 'is_optional_leave'):
self.validate_optional_leave()
self.validate_applicable_after()
@@ -131,8 +132,6 @@
for dt in daterange(getdate(self.from_date), getdate(self.to_date)):
date = dt.strftime("%Y-%m-%d")
status = "Half Day" if getdate(date) == getdate(self.half_day_date) else "On Leave"
- print("-------->>>", status)
- # frappe.throw("Hello")
attendance_name = frappe.db.exists('Attendance', dict(employee = self.employee,
attendance_date = date, docstatus = ('!=', 2)))
@@ -292,6 +291,10 @@
frappe.throw(_("{0} is not in Optional Holiday List").format(formatdate(day)), NotAnOptionalHoliday)
day = add_days(day, 1)
+ def set_half_day_date(self):
+ if self.from_date == self.to_date and self.half_day == 1:
+ self.half_day_date = self.from_date
+
def notify_employee(self):
employee = frappe.get_doc("Employee", self.employee)
if not employee.user_id:
@@ -442,6 +445,7 @@
total_allocated_leaves = frappe.db.get_value('Leave Allocation', {
'from_date': ('<=', date),
'to_date': ('>=', date),
+ 'employee': employee,
'leave_type': allocation.leave_type,
}, 'SUM(total_leaves_allocated)') or 0
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index cd12510..8d95924 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -73,11 +73,11 @@
def assign_task_to_users(self, task, users):
for user in users:
args = {
- 'assign_to' : user,
- 'doctype' : task.doctype,
- 'name' : task.name,
- 'description' : task.description or task.subject,
- 'notify': self.notify_users_by_email
+ 'assign_to': [user],
+ 'doctype': task.doctype,
+ 'name': task.name,
+ 'description': task.description or task.subject,
+ 'notify': self.notify_users_by_email
}
assign_to.add(args)
diff --git a/erpnext/loan_management/desk_page/loan/loan.json b/erpnext/loan_management/desk_page/loan/loan.json
index d79860a..48193b0 100644
--- a/erpnext/loan_management/desk_page/loan/loan.json
+++ b/erpnext/loan_management/desk_page/loan/loan.json
@@ -23,7 +23,7 @@
{
"hidden": 0,
"label": "Reports",
- "links": "[\n {\n \"dependencies\": [\n \"Loan Repayment\"\n ],\n \"doctype\": \"Loan Repayment\",\n \"incomplete_dependencies\": [\n \"Loan Repayment\"\n ],\n \"is_query_report\": true,\n \"label\": \"Loan Repayment and Closure\",\n \"name\": \"Loan Repayment and Closure\",\n \"route\": \"#query-report/Loan Repayment and Closure\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Loan Security Pledge\"\n ],\n \"doctype\": \"Loan Security Pledge\",\n \"incomplete_dependencies\": [\n \"Loan Security Pledge\"\n ],\n \"is_query_report\": true,\n \"label\": \"Loan Security Status\",\n \"name\": \"Loan Security Status\",\n \"route\": \"#query-report/Loan Security Status\",\n \"type\": \"report\"\n }\n]"
+ "links": "[\n {\n \"doctype\": \"Loan Repayment\",\n \"is_query_report\": true,\n \"label\": \"Loan Repayment and Closure\",\n \"name\": \"Loan Repayment and Closure\",\n \"route\": \"#query-report/Loan Repayment and Closure\",\n \"type\": \"report\"\n },\n {\n \"doctype\": \"Loan Security Pledge\",\n \"is_query_report\": true,\n \"label\": \"Loan Security Status\",\n \"name\": \"Loan Security Status\",\n \"route\": \"#query-report/Loan Security Status\",\n \"type\": \"report\"\n }\n]"
}
],
"category": "Modules",
@@ -34,11 +34,10 @@
"docstatus": 0,
"doctype": "Desk Page",
"extends_another_page": 0,
- "hide_custom": 0,
"idx": 0,
"is_standard": 1,
"label": "Loan",
- "modified": "2020-05-28 13:37:42.017709",
+ "modified": "2020-06-07 19:42:14.947902",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan",
diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
index c9e36a8..d44088b 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
+++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
@@ -27,6 +27,7 @@
def on_cancel(self):
self.make_gl_entries(cancel=1)
+ self.ignore_linked_doctypes = ['GL Entry']
def set_missing_values(self):
if not self.disbursement_date:
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 094b9c6..e6ceb55 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
@@ -31,6 +31,7 @@
self.update_is_accrued()
self.make_gl_entries(cancel=1)
+ self.ignore_linked_doctypes = ['GL Entry']
def update_is_accrued(self):
frappe.db.set_value('Repayment Schedule', self.repayment_schedule_name, 'is_accrued', 0)
@@ -176,21 +177,23 @@
return term_loans
def make_loan_interest_accrual_entry(args):
- loan_interest_accrual = frappe.new_doc("Loan Interest Accrual")
- loan_interest_accrual.loan = args.loan
- loan_interest_accrual.applicant_type = args.applicant_type
- loan_interest_accrual.applicant = args.applicant
- loan_interest_accrual.interest_income_account = args.interest_income_account
- loan_interest_accrual.loan_account = args.loan_account
- loan_interest_accrual.pending_principal_amount = flt(args.pending_principal_amount, 2)
- loan_interest_accrual.interest_amount = flt(args.interest_amount, 2)
- loan_interest_accrual.posting_date = args.posting_date or nowdate()
- loan_interest_accrual.process_loan_interest_accrual = args.process_loan_interest
- loan_interest_accrual.repayment_schedule_name = args.repayment_schedule_name
- loan_interest_accrual.payable_principal_amount = args.payable_principal
+ precision = cint(frappe.db.get_default("currency_precision")) or 2
- loan_interest_accrual.save()
- loan_interest_accrual.submit()
+ loan_interest_accrual = frappe.new_doc("Loan Interest Accrual")
+ loan_interest_accrual.loan = args.loan
+ loan_interest_accrual.applicant_type = args.applicant_type
+ loan_interest_accrual.applicant = args.applicant
+ loan_interest_accrual.interest_income_account = args.interest_income_account
+ loan_interest_accrual.loan_account = args.loan_account
+ loan_interest_accrual.pending_principal_amount = flt(args.pending_principal_amount, precision)
+ loan_interest_accrual.interest_amount = flt(args.interest_amount, precision)
+ loan_interest_accrual.posting_date = args.posting_date or nowdate()
+ loan_interest_accrual.process_loan_interest_accrual = args.process_loan_interest
+ loan_interest_accrual.repayment_schedule_name = args.repayment_schedule_name
+ loan_interest_accrual.payable_principal_amount = args.payable_principal
+
+ loan_interest_accrual.save()
+ loan_interest_accrual.submit()
def get_no_of_days_for_interest_accural(loan, posting_date):
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index 2ab668a..c28994e 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -6,7 +6,7 @@
import frappe, erpnext
import json
from frappe import _
-from frappe.utils import flt, getdate
+from frappe.utils import flt, getdate, cint
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
@@ -29,8 +29,11 @@
def on_cancel(self):
self.mark_as_unpaid()
self.make_gl_entries(cancel=1)
+ self.ignore_linked_doctypes = ['GL Entry']
def set_missing_values(self, amounts):
+ precision = cint(frappe.db.get_default("currency_precision")) or 2
+
if not self.posting_date:
self.posting_date = get_datetime()
@@ -38,24 +41,26 @@
self.cost_center = erpnext.get_default_cost_center(self.company)
if not self.interest_payable:
- self.interest_payable = flt(amounts['interest_amount'], 2)
+ self.interest_payable = flt(amounts['interest_amount'], precision)
if not self.penalty_amount:
- self.penalty_amount = flt(amounts['penalty_amount'], 2)
+ self.penalty_amount = flt(amounts['penalty_amount'], precision)
if not self.pending_principal_amount:
- self.pending_principal_amount = flt(amounts['pending_principal_amount'], 2)
+ self.pending_principal_amount = flt(amounts['pending_principal_amount'], precision)
if not self.payable_principal_amount and self.is_term_loan:
- self.payable_principal_amount = flt(amounts['payable_principal_amount'], 2)
+ self.payable_principal_amount = flt(amounts['payable_principal_amount'], precision)
if not self.payable_amount:
- self.payable_amount = flt(amounts['payable_amount'], 2)
+ self.payable_amount = flt(amounts['payable_amount'], precision)
if amounts.get('due_date'):
self.due_date = amounts.get('due_date')
def validate_amount(self):
+ precision = cint(frappe.db.get_default("currency_precision")) or 2
+
if not self.amount_paid:
frappe.throw(_("Amount paid cannot be zero"))
@@ -63,11 +68,13 @@
msg = _("Paid amount cannot be less than {0}").format(self.penalty_amount)
frappe.throw(msg)
- if self.payment_type == "Loan Closure" and flt(self.amount_paid, 2) < flt(self.payable_amount, 2):
+ if self.payment_type == "Loan Closure" and flt(self.amount_paid, precision) < flt(self.payable_amount, precision):
msg = _("Amount of {0} is required for Loan closure").format(self.payable_amount)
frappe.throw(msg)
def update_paid_amount(self):
+ precision = cint(frappe.db.get_default("currency_precision")) or 2
+
loan = frappe.get_doc("Loan", self.against_loan)
for payment in self.repayment_details:
@@ -75,9 +82,9 @@
SET paid_principal_amount = `paid_principal_amount` + %s,
paid_interest_amount = `paid_interest_amount` + %s
WHERE name = %s""",
- (flt(payment.paid_principal_amount), flt(payment.paid_interest_amount), payment.loan_interest_accrual))
+ (flt(payment.paid_principal_amount, precision), flt(payment.paid_interest_amount, precision), payment.loan_interest_accrual))
- if flt(loan.total_principal_paid + self.principal_amount_paid, 2) >= flt(loan.total_payment, 2):
+ if flt(loan.total_principal_paid + self.principal_amount_paid, precision) >= flt(loan.total_payment, precision):
if loan.is_secured_loan:
frappe.db.set_value("Loan", self.against_loan, "status", "Loan Closure Requested")
else:
@@ -253,6 +260,7 @@
# So it pulls all the unpaid Loan Interest Accrual Entries and calculates the penalty if applicable
def get_amounts(amounts, against_loan, posting_date, payment_type):
+ precision = cint(frappe.db.get_default("currency_precision")) or 2
against_loan_doc = frappe.get_doc("Loan", against_loan)
loan_type_details = frappe.get_doc("Loan Type", against_loan_doc.loan_type)
@@ -282,8 +290,8 @@
payable_principal_amount += entry.payable_principal_amount
pending_accrual_entries.setdefault(entry.name, {
- 'interest_amount': flt(entry.interest_amount),
- 'payable_principal_amount': flt(entry.payable_principal_amount)
+ 'interest_amount': flt(entry.interest_amount, precision),
+ 'payable_principal_amount': flt(entry.payable_principal_amount, precision)
})
if not final_due_date:
@@ -301,11 +309,11 @@
per_day_interest = (payable_principal_amount * (loan_type_details.rate_of_interest / 100))/365
total_pending_interest += (pending_days * per_day_interest)
- amounts["pending_principal_amount"] = pending_principal_amount
- amounts["payable_principal_amount"] = payable_principal_amount
- amounts["interest_amount"] = total_pending_interest
- amounts["penalty_amount"] = penalty_amount
- amounts["payable_amount"] = payable_principal_amount + total_pending_interest + penalty_amount
+ amounts["pending_principal_amount"] = flt(pending_principal_amount, precision)
+ amounts["payable_principal_amount"] = flt(payable_principal_amount, precision)
+ amounts["interest_amount"] = flt(total_pending_interest, precision)
+ amounts["penalty_amount"] = flt(penalty_amount, precision)
+ amounts["payable_amount"] = flt(payable_principal_amount + total_pending_interest + penalty_amount, precision)
amounts["pending_accrual_entries"] = pending_accrual_entries
if final_due_date:
diff --git a/erpnext/loan_management/doctype/loan_type/loan_type.json b/erpnext/loan_management/doctype/loan_type/loan_type.json
index 51c5cb9..1dd3710 100644
--- a/erpnext/loan_management/doctype/loan_type/loan_type.json
+++ b/erpnext/loan_management/doctype/loan_type/loan_type.json
@@ -41,6 +41,7 @@
"options": "Company:company:default_currency"
},
{
+ "default": "0",
"fieldname": "rate_of_interest",
"fieldtype": "Percent",
"label": "Rate of Interest (%) Yearly",
@@ -143,7 +144,7 @@
],
"is_submittable": 1,
"links": [],
- "modified": "2020-04-15 00:24:43.259963",
+ "modified": "2020-06-07 18:55:59.346292",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Type",
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 ea6a2ee6..1951855 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
@@ -76,7 +76,8 @@
"fieldtype": "Link",
"fieldname": "currency",
"options": "Currency",
- "width": 50
+ "width": 50,
+ "hidden": 1
}
]
@@ -84,17 +85,13 @@
def get_data(filters):
- loan_security_price_map = frappe._dict(frappe.get_all("Loan Security",
- fields=["name", "loan_security_price"], as_list=1
- ))
-
data = []
conditions = get_conditions(filters)
loan_security_pledges = frappe.db.sql("""
SELECT
p.name, p.applicant, p.loan, p.status, p.pledge_time,
- c.loan_security, c.qty
+ c.loan_security, c.qty, c.loan_security_price, c.amount
FROM
`tabLoan Security Pledge` p, `tabPledge` c
WHERE
@@ -115,8 +112,8 @@
row["pledge_time"] = pledge.pledge_time
row["loan_security"] = pledge.loan_security
row["qty"] = pledge.qty
- row["loan_security_price"] = loan_security_price_map.get(pledge.loan_security)
- row["loan_security_value"] = row["loan_security_price"] * pledge.qty
+ row["loan_security_price"] = pledge.loan_security_price
+ row["loan_security_value"] = pledge.amount
row["currency"] = default_currency
data.append(row)
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 cac8067..2ca9f16 100644
--- a/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py
+++ b/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py
@@ -217,6 +217,8 @@
}
def get_summary_data(self):
+ if not self.data: return
+
return [
{
"value": sum(self.total_demand),
diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js
index 5862963..3570a0f 100644
--- a/erpnext/projects/doctype/project/project.js
+++ b/erpnext/projects/doctype/project/project.js
@@ -18,7 +18,7 @@
};
},
onload: function (frm) {
- var so = frm.get_docfield("Project", "sales_order");
+ var so = frappe.meta.get_docfield("Project", "sales_order");
so.get_route_options_for_new_doc = function (field) {
if (frm.is_new()) return;
return {
@@ -135,4 +135,4 @@
frappe.ui.form.make_quick_entry(doctype, null, null, new_doc);
});
-}
+}
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 524a958..9421668 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -917,7 +917,7 @@
shipping_rule: function() {
var me = this;
- if(this.frm.doc.shipping_rule && this.frm.doc.shipping_address) {
+ if(this.frm.doc.shipping_rule) {
return this.frm.call({
doc: this.frm.doc,
method: "apply_shipping_rule",
diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.py b/erpnext/stock/doctype/item_attribute/item_attribute.py
index 71b998f..2f75bbd 100644
--- a/erpnext/stock/doctype/item_attribute/item_attribute.py
+++ b/erpnext/stock/doctype/item_attribute/item_attribute.py
@@ -34,7 +34,7 @@
if self.numeric_values:
validate_is_incremental(self, self.name, item.value, item.name)
else:
- validate_item_attribute_value(attributes_list, self.name, item.value, item.name)
+ validate_item_attribute_value(attributes_list, self.name, item.value, item.name, from_variant=False)
def validate_numeric(self):
if self.numeric_values:
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index 3562181..3a8deb6 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -18,7 +18,7 @@
// formatter for material request item
frm.set_indicator_formatter('item_code',
- function(doc) { return (doc.qty<=doc.ordered_qty) ? "green" : "orange"; });
+ function(doc) { return (doc.stock_qty<=doc.ordered_qty) ? "green" : "orange"; });
frm.set_query("item_code", "items", function() {
return {
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 18d6853..5fbd512 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -500,7 +500,7 @@
if raw_material_cost and self.purpose == "Manufacture":
d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate"))
d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
- elif self.purpose == "Repack" and total_fg_qty:
+ elif self.purpose == "Repack" and total_fg_qty and not d.set_basic_rate_manually:
d.basic_rate = flt(raw_material_cost) / flt(total_fg_qty)
d.basic_amount = d.basic_rate * d.qty
diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
index c16a41c..7b9c129 100644
--- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
+++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
@@ -23,6 +23,7 @@
"image",
"image_view",
"quantity_and_rate",
+ "set_basic_rate_manually",
"qty",
"basic_rate",
"basic_amount",
@@ -491,12 +492,21 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:parent.purpose===\"Repack\" && doc.t_warehouse",
+ "fieldname": "set_basic_rate_manually",
+ "fieldtype": "Check",
+ "label": "Set Basic Rate Manually",
+ "show_days": 1,
+ "show_seconds": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-04-23 19:19:28.539769",
+ "modified": "2020-06-08 12:57:03.172887",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry Detail",