Merge branch 'develop' of https://github.com/frappe/erpnext into mergify/bp/develop/pr-28935
This commit is contained in:
commit
3b9bea7937
27
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
27
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@ -24,20 +24,6 @@ body:
|
|||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
id: version
|
|
||||||
attributes:
|
|
||||||
label: Version
|
|
||||||
description: Affected versions.
|
|
||||||
multiple: true
|
|
||||||
options:
|
|
||||||
- v12
|
|
||||||
- v13
|
|
||||||
- v14
|
|
||||||
- develop
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
id: module
|
id: module
|
||||||
attributes:
|
attributes:
|
||||||
@ -86,7 +72,7 @@ body:
|
|||||||
- manual install
|
- manual install
|
||||||
- FrappeCloud
|
- FrappeCloud
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: false
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: logs
|
id: logs
|
||||||
@ -95,12 +81,7 @@ body:
|
|||||||
description: Please copy and paste any relevant log output. This will be automatically formatted.
|
description: Please copy and paste any relevant log output. This will be automatically formatted.
|
||||||
render: shell
|
render: shell
|
||||||
|
|
||||||
|
- type: markdown
|
||||||
- type: checkboxes
|
|
||||||
id: terms
|
|
||||||
attributes:
|
attributes:
|
||||||
label: Code of Conduct
|
value: |
|
||||||
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/frappe/erpnext/blob/develop/CODE_OF_CONDUCT.md)
|
By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/frappe/erpnext/blob/develop/CODE_OF_CONDUCT.md)
|
||||||
options:
|
|
||||||
- label: I agree to follow this project's Code of Conduct
|
|
||||||
required: true
|
|
||||||
|
@ -1049,6 +1049,8 @@ class SalesInvoice(SellingController):
|
|||||||
frappe.flags.is_reverse_depr_entry = False
|
frappe.flags.is_reverse_depr_entry = False
|
||||||
asset.flags.ignore_validate_update_after_submit = True
|
asset.flags.ignore_validate_update_after_submit = True
|
||||||
schedule.journal_entry = None
|
schedule.journal_entry = None
|
||||||
|
depreciation_amount = self.get_depreciation_amount_in_je(reverse_journal_entry)
|
||||||
|
asset.finance_books[0].value_after_depreciation += depreciation_amount
|
||||||
asset.save()
|
asset.save()
|
||||||
|
|
||||||
def get_posting_date_of_sales_invoice(self):
|
def get_posting_date_of_sales_invoice(self):
|
||||||
@ -1071,6 +1073,12 @@ class SalesInvoice(SellingController):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_depreciation_amount_in_je(self, journal_entry):
|
||||||
|
if journal_entry.accounts[0].debit_in_account_currency:
|
||||||
|
return journal_entry.accounts[0].debit_in_account_currency
|
||||||
|
else:
|
||||||
|
return journal_entry.accounts[0].credit_in_account_currency
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def enable_discount_accounting(self):
|
def enable_discount_accounting(self):
|
||||||
if not hasattr(self, "_enable_discount_accounting"):
|
if not hasattr(self, "_enable_discount_accounting"):
|
||||||
|
@ -23,6 +23,17 @@ class TestLead(unittest.TestCase):
|
|||||||
customer.customer_group = "_Test Customer Group"
|
customer.customer_group = "_Test Customer Group"
|
||||||
customer.insert()
|
customer.insert()
|
||||||
|
|
||||||
|
#check whether lead contact is carried forward to the customer.
|
||||||
|
contact = frappe.db.get_value('Dynamic Link', {
|
||||||
|
"parenttype": "Contact",
|
||||||
|
"link_doctype": "Lead",
|
||||||
|
"link_name": customer.lead_name,
|
||||||
|
}, "parent")
|
||||||
|
|
||||||
|
if contact:
|
||||||
|
contact_doc = frappe.get_doc("Contact", contact)
|
||||||
|
self.assertEqual(contact_doc.has_link(customer.doctype, customer.name), True)
|
||||||
|
|
||||||
def test_make_customer_from_organization(self):
|
def test_make_customer_from_organization(self):
|
||||||
from erpnext.crm.doctype.lead.lead import make_customer
|
from erpnext.crm.doctype.lead.lead import make_customer
|
||||||
|
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
{
|
|
||||||
"charts": [],
|
|
||||||
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Integrations Settings\", \"col\": 4}}]",
|
|
||||||
"creation": "2020-07-31 10:38:54.021237",
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "Workspace",
|
|
||||||
"for_user": "",
|
|
||||||
"hide_custom": 0,
|
|
||||||
"icon": "setting",
|
|
||||||
"idx": 0,
|
|
||||||
"label": "ERPNext Integrations Settings",
|
|
||||||
"links": [
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Integrations Settings",
|
|
||||||
"link_count": 0,
|
|
||||||
"onboard": 0,
|
|
||||||
"type": "Card Break"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dependencies": "",
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Woocommerce Settings",
|
|
||||||
"link_count": 0,
|
|
||||||
"link_to": "Woocommerce Settings",
|
|
||||||
"link_type": "DocType",
|
|
||||||
"onboard": 0,
|
|
||||||
"type": "Link"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dependencies": "",
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Amazon MWS Settings",
|
|
||||||
"link_count": 0,
|
|
||||||
"link_to": "Amazon MWS Settings",
|
|
||||||
"link_type": "DocType",
|
|
||||||
"onboard": 0,
|
|
||||||
"type": "Link"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dependencies": "",
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Plaid Settings",
|
|
||||||
"link_count": 0,
|
|
||||||
"link_to": "Plaid Settings",
|
|
||||||
"link_type": "DocType",
|
|
||||||
"onboard": 0,
|
|
||||||
"type": "Link"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dependencies": "",
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Exotel Settings",
|
|
||||||
"link_count": 0,
|
|
||||||
"link_to": "Exotel Settings",
|
|
||||||
"link_type": "DocType",
|
|
||||||
"onboard": 0,
|
|
||||||
"type": "Link"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"modified": "2021-11-23 04:30:33.106991",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "ERPNext Integrations",
|
|
||||||
"name": "ERPNext Integrations Settings",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"parent_page": "",
|
|
||||||
"public": 1,
|
|
||||||
"restrict_to_domain": "",
|
|
||||||
"roles": [],
|
|
||||||
"sequence_id": 11,
|
|
||||||
"shortcuts": [],
|
|
||||||
"title": "ERPNext Integrations Settings"
|
|
||||||
}
|
|
@ -374,7 +374,7 @@ scheduler_events = {
|
|||||||
"erpnext.selling.doctype.quotation.quotation.set_expired_status",
|
"erpnext.selling.doctype.quotation.quotation.set_expired_status",
|
||||||
"erpnext.buying.doctype.supplier_quotation.supplier_quotation.set_expired_status",
|
"erpnext.buying.doctype.supplier_quotation.supplier_quotation.set_expired_status",
|
||||||
"erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_auto_email",
|
"erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_auto_email",
|
||||||
"erpnext.non_profit.doctype.membership.membership.set_expired_status"
|
"erpnext.non_profit.doctype.membership.membership.set_expired_status",
|
||||||
"erpnext.hr.doctype.interview.interview.send_daily_feedback_reminder"
|
"erpnext.hr.doctype.interview.interview.send_daily_feedback_reminder"
|
||||||
],
|
],
|
||||||
"daily_long": [
|
"daily_long": [
|
||||||
|
@ -4,6 +4,7 @@ import frappe
|
|||||||
from frappe.utils import add_days, add_months, getdate, nowdate
|
from frappe.utils import add_days, add_months, getdate, nowdate
|
||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
|
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||||
from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import process_expired_allocation
|
from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import process_expired_allocation
|
||||||
from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
|
from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
|
||||||
|
|
||||||
@ -11,18 +12,25 @@ from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
|
|||||||
class TestLeaveAllocation(unittest.TestCase):
|
class TestLeaveAllocation(unittest.TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
|
from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_holiday_list
|
||||||
|
|
||||||
frappe.db.sql("delete from `tabLeave Period`")
|
frappe.db.sql("delete from `tabLeave Period`")
|
||||||
|
emp_id = make_employee("test_emp_leave_allocation@salary.com")
|
||||||
|
cls.employee = frappe.get_doc("Employee", emp_id)
|
||||||
|
|
||||||
|
make_holiday_list()
|
||||||
|
frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", "Salary Slip Test Holiday List")
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
frappe.db.rollback()
|
||||||
|
|
||||||
def test_overlapping_allocation(self):
|
def test_overlapping_allocation(self):
|
||||||
frappe.db.sql("delete from `tabLeave Allocation`")
|
|
||||||
|
|
||||||
employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
|
|
||||||
leaves = [
|
leaves = [
|
||||||
{
|
{
|
||||||
"doctype": "Leave Allocation",
|
"doctype": "Leave Allocation",
|
||||||
"__islocal": 1,
|
"__islocal": 1,
|
||||||
"employee": employee.name,
|
"employee": self.employee.name,
|
||||||
"employee_name": employee.employee_name,
|
"employee_name": self.employee.employee_name,
|
||||||
"leave_type": "_Test Leave Type",
|
"leave_type": "_Test Leave Type",
|
||||||
"from_date": getdate("2015-10-01"),
|
"from_date": getdate("2015-10-01"),
|
||||||
"to_date": getdate("2015-10-31"),
|
"to_date": getdate("2015-10-31"),
|
||||||
@ -32,8 +40,8 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
{
|
{
|
||||||
"doctype": "Leave Allocation",
|
"doctype": "Leave Allocation",
|
||||||
"__islocal": 1,
|
"__islocal": 1,
|
||||||
"employee": employee.name,
|
"employee": self.employee.name,
|
||||||
"employee_name": employee.employee_name,
|
"employee_name": self.employee.employee_name,
|
||||||
"leave_type": "_Test Leave Type",
|
"leave_type": "_Test Leave Type",
|
||||||
"from_date": getdate("2015-09-01"),
|
"from_date": getdate("2015-09-01"),
|
||||||
"to_date": getdate("2015-11-30"),
|
"to_date": getdate("2015-11-30"),
|
||||||
@ -45,13 +53,11 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
self.assertRaises(frappe.ValidationError, frappe.get_doc(leaves[1]).save)
|
self.assertRaises(frappe.ValidationError, frappe.get_doc(leaves[1]).save)
|
||||||
|
|
||||||
def test_invalid_period(self):
|
def test_invalid_period(self):
|
||||||
employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
|
|
||||||
|
|
||||||
doc = frappe.get_doc({
|
doc = frappe.get_doc({
|
||||||
"doctype": "Leave Allocation",
|
"doctype": "Leave Allocation",
|
||||||
"__islocal": 1,
|
"__islocal": 1,
|
||||||
"employee": employee.name,
|
"employee": self.employee.name,
|
||||||
"employee_name": employee.employee_name,
|
"employee_name": self.employee.employee_name,
|
||||||
"leave_type": "_Test Leave Type",
|
"leave_type": "_Test Leave Type",
|
||||||
"from_date": getdate("2015-09-30"),
|
"from_date": getdate("2015-09-30"),
|
||||||
"to_date": getdate("2015-09-1"),
|
"to_date": getdate("2015-09-1"),
|
||||||
@ -62,23 +68,21 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
self.assertRaises(frappe.ValidationError, doc.save)
|
self.assertRaises(frappe.ValidationError, doc.save)
|
||||||
|
|
||||||
def test_allocated_leave_days_over_period(self):
|
def test_allocated_leave_days_over_period(self):
|
||||||
employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
|
|
||||||
doc = frappe.get_doc({
|
doc = frappe.get_doc({
|
||||||
"doctype": "Leave Allocation",
|
"doctype": "Leave Allocation",
|
||||||
"__islocal": 1,
|
"__islocal": 1,
|
||||||
"employee": employee.name,
|
"employee": self.employee.name,
|
||||||
"employee_name": employee.employee_name,
|
"employee_name": self.employee.employee_name,
|
||||||
"leave_type": "_Test Leave Type",
|
"leave_type": "_Test Leave Type",
|
||||||
"from_date": getdate("2015-09-1"),
|
"from_date": getdate("2015-09-1"),
|
||||||
"to_date": getdate("2015-09-30"),
|
"to_date": getdate("2015-09-30"),
|
||||||
"new_leaves_allocated": 35
|
"new_leaves_allocated": 35
|
||||||
})
|
})
|
||||||
|
|
||||||
# allocated leave more than period
|
# allocated leave more than period
|
||||||
self.assertRaises(frappe.ValidationError, doc.save)
|
self.assertRaises(frappe.ValidationError, doc.save)
|
||||||
|
|
||||||
def test_carry_forward_calculation(self):
|
def test_carry_forward_calculation(self):
|
||||||
frappe.db.sql("delete from `tabLeave Allocation`")
|
|
||||||
frappe.db.sql("delete from `tabLeave Ledger Entry`")
|
|
||||||
leave_type = create_leave_type(leave_type_name="_Test_CF_leave", is_carry_forward=1)
|
leave_type = create_leave_type(leave_type_name="_Test_CF_leave", is_carry_forward=1)
|
||||||
leave_type.maximum_carry_forwarded_leaves = 10
|
leave_type.maximum_carry_forwarded_leaves = 10
|
||||||
leave_type.max_leaves_allowed = 30
|
leave_type.max_leaves_allowed = 30
|
||||||
@ -114,8 +118,6 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
self.assertEqual(leave_allocation_2.unused_leaves, 5)
|
self.assertEqual(leave_allocation_2.unused_leaves, 5)
|
||||||
|
|
||||||
def test_carry_forward_leaves_expiry(self):
|
def test_carry_forward_leaves_expiry(self):
|
||||||
frappe.db.sql("delete from `tabLeave Allocation`")
|
|
||||||
frappe.db.sql("delete from `tabLeave Ledger Entry`")
|
|
||||||
leave_type = create_leave_type(
|
leave_type = create_leave_type(
|
||||||
leave_type_name="_Test_CF_leave_expiry",
|
leave_type_name="_Test_CF_leave_expiry",
|
||||||
is_carry_forward=1,
|
is_carry_forward=1,
|
||||||
@ -151,8 +153,6 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
self.assertEqual(leave_allocation_1.unused_leaves, leave_allocation.new_leaves_allocated)
|
self.assertEqual(leave_allocation_1.unused_leaves, leave_allocation.new_leaves_allocated)
|
||||||
|
|
||||||
def test_creation_of_leave_ledger_entry_on_submit(self):
|
def test_creation_of_leave_ledger_entry_on_submit(self):
|
||||||
frappe.db.sql("delete from `tabLeave Allocation`")
|
|
||||||
|
|
||||||
leave_allocation = create_leave_allocation()
|
leave_allocation = create_leave_allocation()
|
||||||
leave_allocation.submit()
|
leave_allocation.submit()
|
||||||
|
|
||||||
@ -168,9 +168,6 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
self.assertFalse(frappe.db.exists("Leave Ledger Entry", {'transaction_name':leave_allocation.name}))
|
self.assertFalse(frappe.db.exists("Leave Ledger Entry", {'transaction_name':leave_allocation.name}))
|
||||||
|
|
||||||
def test_leave_addition_after_submit(self):
|
def test_leave_addition_after_submit(self):
|
||||||
frappe.db.sql("delete from `tabLeave Allocation`")
|
|
||||||
frappe.db.sql("delete from `tabLeave Ledger Entry`")
|
|
||||||
|
|
||||||
leave_allocation = create_leave_allocation()
|
leave_allocation = create_leave_allocation()
|
||||||
leave_allocation.submit()
|
leave_allocation.submit()
|
||||||
self.assertTrue(leave_allocation.total_leaves_allocated, 15)
|
self.assertTrue(leave_allocation.total_leaves_allocated, 15)
|
||||||
@ -179,8 +176,6 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
self.assertTrue(leave_allocation.total_leaves_allocated, 40)
|
self.assertTrue(leave_allocation.total_leaves_allocated, 40)
|
||||||
|
|
||||||
def test_leave_subtraction_after_submit(self):
|
def test_leave_subtraction_after_submit(self):
|
||||||
frappe.db.sql("delete from `tabLeave Allocation`")
|
|
||||||
frappe.db.sql("delete from `tabLeave Ledger Entry`")
|
|
||||||
leave_allocation = create_leave_allocation()
|
leave_allocation = create_leave_allocation()
|
||||||
leave_allocation.submit()
|
leave_allocation.submit()
|
||||||
self.assertTrue(leave_allocation.total_leaves_allocated, 15)
|
self.assertTrue(leave_allocation.total_leaves_allocated, 15)
|
||||||
@ -188,17 +183,14 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
leave_allocation.submit()
|
leave_allocation.submit()
|
||||||
self.assertTrue(leave_allocation.total_leaves_allocated, 10)
|
self.assertTrue(leave_allocation.total_leaves_allocated, 10)
|
||||||
|
|
||||||
def test_against_leave_application_validation_after_submit(self):
|
def test_validation_against_leave_application_after_submit(self):
|
||||||
frappe.db.sql("delete from `tabLeave Allocation`")
|
|
||||||
frappe.db.sql("delete from `tabLeave Ledger Entry`")
|
|
||||||
|
|
||||||
leave_allocation = create_leave_allocation()
|
leave_allocation = create_leave_allocation()
|
||||||
leave_allocation.submit()
|
leave_allocation.submit()
|
||||||
self.assertTrue(leave_allocation.total_leaves_allocated, 15)
|
self.assertTrue(leave_allocation.total_leaves_allocated, 15)
|
||||||
employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
|
|
||||||
leave_application = frappe.get_doc({
|
leave_application = frappe.get_doc({
|
||||||
"doctype": 'Leave Application',
|
"doctype": 'Leave Application',
|
||||||
"employee": employee.name,
|
"employee": self.employee.name,
|
||||||
"leave_type": "_Test Leave Type",
|
"leave_type": "_Test Leave Type",
|
||||||
"from_date": add_months(nowdate(), 2),
|
"from_date": add_months(nowdate(), 2),
|
||||||
"to_date": add_months(add_days(nowdate(), 10), 2),
|
"to_date": add_months(add_days(nowdate(), 10), 2),
|
||||||
@ -208,15 +200,20 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
"leave_approver": 'test@example.com'
|
"leave_approver": 'test@example.com'
|
||||||
})
|
})
|
||||||
leave_application.submit()
|
leave_application.submit()
|
||||||
leave_allocation.new_leaves_allocated = 8
|
leave_application.reload()
|
||||||
leave_allocation.total_leaves_allocated = 8
|
|
||||||
|
# allocate less leaves than the ones which are already approved
|
||||||
|
leave_allocation.new_leaves_allocated = leave_application.total_leave_days - 1
|
||||||
|
leave_allocation.total_leaves_allocated = leave_application.total_leave_days - 1
|
||||||
self.assertRaises(frappe.ValidationError, leave_allocation.submit)
|
self.assertRaises(frappe.ValidationError, leave_allocation.submit)
|
||||||
|
|
||||||
def create_leave_allocation(**args):
|
def create_leave_allocation(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|
||||||
employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
|
emp_id = make_employee("test_emp_leave_allocation@salary.com")
|
||||||
leave_allocation = frappe.get_doc({
|
employee = frappe.get_doc("Employee", emp_id)
|
||||||
|
|
||||||
|
return frappe.get_doc({
|
||||||
"doctype": "Leave Allocation",
|
"doctype": "Leave Allocation",
|
||||||
"__islocal": 1,
|
"__islocal": 1,
|
||||||
"employee": args.employee or employee.name,
|
"employee": args.employee or employee.name,
|
||||||
@ -227,6 +224,5 @@ def create_leave_allocation(**args):
|
|||||||
"carry_forward": args.carry_forward or 0,
|
"carry_forward": args.carry_forward or 0,
|
||||||
"to_date": args.to_date or add_months(nowdate(), 12)
|
"to_date": args.to_date or add_months(nowdate(), 12)
|
||||||
})
|
})
|
||||||
return leave_allocation
|
|
||||||
|
|
||||||
test_dependencies = ["Employee", "Leave Type"]
|
test_dependencies = ["Employee", "Leave Type"]
|
||||||
|
@ -319,4 +319,4 @@ erpnext.patches.v13_0.rename_ksa_qr_field
|
|||||||
erpnext.patches.v13_0.disable_ksa_print_format_for_others # 16-12-2021
|
erpnext.patches.v13_0.disable_ksa_print_format_for_others # 16-12-2021
|
||||||
erpnext.patches.v14_0.add_default_exit_questionnaire_notification_template
|
erpnext.patches.v14_0.add_default_exit_questionnaire_notification_template
|
||||||
erpnext.patches.v13_0.update_tax_category_for_rcm
|
erpnext.patches.v13_0.update_tax_category_for_rcm
|
||||||
|
execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings')
|
||||||
|
@ -22,4 +22,5 @@ def execute():
|
|||||||
|
|
||||||
delivery_settings = frappe.get_doc("Delivery Settings")
|
delivery_settings = frappe.get_doc("Delivery Settings")
|
||||||
delivery_settings.dispatch_template = _("Dispatch Notification")
|
delivery_settings.dispatch_template = _("Dispatch Notification")
|
||||||
|
delivery_settings.flags.ignore_links = True
|
||||||
delivery_settings.save()
|
delivery_settings.save()
|
||||||
|
@ -97,6 +97,8 @@ def execute():
|
|||||||
'itc_central_tax': 0,
|
'itc_central_tax': 0,
|
||||||
'itc_cess_amount': 0
|
'itc_cess_amount': 0
|
||||||
})
|
})
|
||||||
|
if not gst_accounts:
|
||||||
|
continue
|
||||||
|
|
||||||
if d.account_head in gst_accounts.get('igst_account'):
|
if d.account_head in gst_accounts.get('igst_account'):
|
||||||
amount_map[d.parent]['itc_integrated_tax'] += d.amount
|
amount_map[d.parent]['itc_integrated_tax'] += d.amount
|
||||||
|
@ -32,4 +32,5 @@ def execute():
|
|||||||
hr_settings = frappe.get_doc('HR Settings')
|
hr_settings = frappe.get_doc('HR Settings')
|
||||||
hr_settings.interview_reminder_template = _('Interview Reminder')
|
hr_settings.interview_reminder_template = _('Interview Reminder')
|
||||||
hr_settings.feedback_reminder_notification_template = _('Interview Feedback Reminder')
|
hr_settings.feedback_reminder_notification_template = _('Interview Feedback Reminder')
|
||||||
|
hr_settings.flags.ignore_links = True
|
||||||
hr_settings.save()
|
hr_settings.save()
|
||||||
|
@ -24,4 +24,5 @@ def execute():
|
|||||||
|
|
||||||
hr_settings = frappe.get_doc("HR Settings")
|
hr_settings = frappe.get_doc("HR Settings")
|
||||||
hr_settings.exit_questionnaire_notification_template = template
|
hr_settings.exit_questionnaire_notification_template = template
|
||||||
|
hr_settings.flags.ignore_links = True
|
||||||
hr_settings.save()
|
hr_settings.save()
|
||||||
|
@ -680,7 +680,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
var item = frappe.get_doc(cdt, cdn);
|
var item = frappe.get_doc(cdt, cdn);
|
||||||
frappe.model.round_floats_in(item, ["price_list_rate", "discount_percentage"]);
|
frappe.model.round_floats_in(item, ["price_list_rate", "discount_percentage"]);
|
||||||
|
|
||||||
// check if child doctype is Sales Order Item/Qutation Item and calculate the rate
|
// check if child doctype is Sales Order Item/Quotation Item and calculate the rate
|
||||||
if (in_list(["Quotation Item", "Sales Order Item", "Delivery Note Item", "Sales Invoice Item", "POS Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Purchase Receipt Item"]), cdt)
|
if (in_list(["Quotation Item", "Sales Order Item", "Delivery Note Item", "Sales Invoice Item", "POS Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Purchase Receipt Item"]), cdt)
|
||||||
this.apply_pricing_rule_on_item(item);
|
this.apply_pricing_rule_on_item(item);
|
||||||
else
|
else
|
||||||
@ -1582,25 +1582,27 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
|
|
||||||
_set_values_for_item_list(children) {
|
_set_values_for_item_list(children) {
|
||||||
var me = this;
|
var me = this;
|
||||||
var price_list_rate_changed = false;
|
|
||||||
var items_rule_dict = {};
|
var items_rule_dict = {};
|
||||||
|
|
||||||
for(var i=0, l=children.length; i<l; i++) {
|
for(var i=0, l=children.length; i<l; i++) {
|
||||||
var d = children[i] ;
|
var d = children[i] ;
|
||||||
|
let item_row = frappe.get_doc(d.doctype, d.name);
|
||||||
var existing_pricing_rule = frappe.model.get_value(d.doctype, d.name, "pricing_rules");
|
var existing_pricing_rule = frappe.model.get_value(d.doctype, d.name, "pricing_rules");
|
||||||
for(var k in d) {
|
for(var k in d) {
|
||||||
var v = d[k];
|
var v = d[k];
|
||||||
if (["doctype", "name"].indexOf(k)===-1) {
|
if (["doctype", "name"].indexOf(k)===-1) {
|
||||||
if(k=="price_list_rate") {
|
if(k=="price_list_rate") {
|
||||||
if(flt(v) != flt(d.price_list_rate)) price_list_rate_changed = true;
|
item_row['rate'] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (k !== 'free_item_data') {
|
if (k !== 'free_item_data') {
|
||||||
frappe.model.set_value(d.doctype, d.name, k, v);
|
item_row[k] = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frappe.model.round_floats_in(item_row, ["price_list_rate", "discount_percentage"]);
|
||||||
|
|
||||||
// if pricing rule set as blank from an existing value, apply price_list
|
// if pricing rule set as blank from an existing value, apply price_list
|
||||||
if(!me.frm.doc.ignore_pricing_rule && existing_pricing_rule && !d.pricing_rules) {
|
if(!me.frm.doc.ignore_pricing_rule && existing_pricing_rule && !d.pricing_rules) {
|
||||||
me.apply_price_list(frappe.get_doc(d.doctype, d.name));
|
me.apply_price_list(frappe.get_doc(d.doctype, d.name));
|
||||||
@ -1617,9 +1619,10 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
me.frm.refresh_field('items');
|
||||||
me.apply_rule_on_other_items(items_rule_dict);
|
me.apply_rule_on_other_items(items_rule_dict);
|
||||||
|
|
||||||
if(!price_list_rate_changed) me.calculate_taxes_and_totals();
|
me.calculate_taxes_and_totals();
|
||||||
}
|
}
|
||||||
|
|
||||||
apply_rule_on_other_items(args) {
|
apply_rule_on_other_items(args) {
|
||||||
|
@ -196,7 +196,6 @@ class Customer(TransactionBase):
|
|||||||
if not lead.lead_name:
|
if not lead.lead_name:
|
||||||
frappe.throw(_("Please mention the Lead Name in Lead {0}").format(self.lead_name))
|
frappe.throw(_("Please mention the Lead Name in Lead {0}").format(self.lead_name))
|
||||||
|
|
||||||
if lead.company_name:
|
|
||||||
contact_names = frappe.get_all('Dynamic Link', filters={
|
contact_names = frappe.get_all('Dynamic Link', filters={
|
||||||
"parenttype":"Contact",
|
"parenttype":"Contact",
|
||||||
"link_doctype":"Lead",
|
"link_doctype":"Lead",
|
||||||
@ -209,7 +208,7 @@ class Customer(TransactionBase):
|
|||||||
contact.append('links', dict(link_doctype='Customer', link_name=self.name))
|
contact.append('links', dict(link_doctype='Customer', link_name=self.name))
|
||||||
contact.save(ignore_permissions=self.flags.ignore_permissions)
|
contact.save(ignore_permissions=self.flags.ignore_permissions)
|
||||||
|
|
||||||
else:
|
if not contact_names:
|
||||||
lead.lead_name = lead.lead_name.lstrip().split(" ")
|
lead.lead_name = lead.lead_name.lstrip().split(" ")
|
||||||
lead.first_name = lead.lead_name[0]
|
lead.first_name = lead.lead_name[0]
|
||||||
lead.last_name = " ".join(lead.lead_name[1:])
|
lead.last_name = " ".join(lead.lead_name[1:])
|
||||||
|
@ -61,6 +61,7 @@ def get_data(conditions, filters):
|
|||||||
IF(so.status in ('Completed','To Bill'), 0, (SELECT delay_days)) as delay,
|
IF(so.status in ('Completed','To Bill'), 0, (SELECT delay_days)) as delay,
|
||||||
soi.qty, soi.delivered_qty,
|
soi.qty, soi.delivered_qty,
|
||||||
(soi.qty - soi.delivered_qty) AS pending_qty,
|
(soi.qty - soi.delivered_qty) AS pending_qty,
|
||||||
|
IF((SELECT pending_qty) = 0, (TO_SECONDS(Max(dn.posting_date))-TO_SECONDS(so.transaction_date)), 0) as time_taken_to_deliver,
|
||||||
IFNULL(SUM(sii.qty), 0) as billed_qty,
|
IFNULL(SUM(sii.qty), 0) as billed_qty,
|
||||||
soi.base_amount as amount,
|
soi.base_amount as amount,
|
||||||
(soi.delivered_qty * soi.base_rate) as delivered_qty_amount,
|
(soi.delivered_qty * soi.base_rate) as delivered_qty_amount,
|
||||||
@ -70,9 +71,13 @@ def get_data(conditions, filters):
|
|||||||
so.company, soi.name
|
so.company, soi.name
|
||||||
FROM
|
FROM
|
||||||
`tabSales Order` so,
|
`tabSales Order` so,
|
||||||
`tabSales Order Item` soi
|
(`tabSales Order Item` soi
|
||||||
LEFT JOIN `tabSales Invoice Item` sii
|
LEFT JOIN `tabSales Invoice Item` sii
|
||||||
ON sii.so_detail = soi.name and sii.docstatus = 1
|
ON sii.so_detail = soi.name and sii.docstatus = 1)
|
||||||
|
LEFT JOIN `tabDelivery Note Item` dni
|
||||||
|
on dni.so_detail = soi.name
|
||||||
|
RIGHT JOIN `tabDelivery Note` dn
|
||||||
|
on dni.parent = dn.name and dn.docstatus = 1
|
||||||
WHERE
|
WHERE
|
||||||
soi.parent = so.name
|
soi.parent = so.name
|
||||||
and so.status not in ('Stopped', 'Closed', 'On Hold')
|
and so.status not in ('Stopped', 'Closed', 'On Hold')
|
||||||
@ -259,6 +264,12 @@ def get_columns(filters):
|
|||||||
"fieldname": "delay",
|
"fieldname": "delay",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"width": 100
|
"width": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Time Taken to Deliver"),
|
||||||
|
"fieldname": "time_taken_to_deliver",
|
||||||
|
"fieldtype": "Duration",
|
||||||
|
"width": 100
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
if not filters.get("group_by_so"):
|
if not filters.get("group_by_so"):
|
||||||
|
@ -150,7 +150,7 @@
|
|||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"in_filter": 1,
|
"in_filter": 1,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Actual Quantity",
|
"label": "Qty Change",
|
||||||
"oldfieldname": "actual_qty",
|
"oldfieldname": "actual_qty",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"print_width": "150px",
|
"print_width": "150px",
|
||||||
@ -189,7 +189,7 @@
|
|||||||
"fieldname": "qty_after_transaction",
|
"fieldname": "qty_after_transaction",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"in_filter": 1,
|
"in_filter": 1,
|
||||||
"label": "Actual Qty After Transaction",
|
"label": "Qty After Transaction",
|
||||||
"oldfieldname": "bin_aqat",
|
"oldfieldname": "bin_aqat",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"print_width": "150px",
|
"print_width": "150px",
|
||||||
@ -210,7 +210,7 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "stock_value",
|
"fieldname": "stock_value",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Stock Value",
|
"label": "Balance Stock Value",
|
||||||
"oldfieldname": "stock_value",
|
"oldfieldname": "stock_value",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
@ -219,14 +219,14 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "stock_value_difference",
|
"fieldname": "stock_value_difference",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Stock Value Difference",
|
"label": "Change in Stock Value",
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "stock_queue",
|
"fieldname": "stock_queue",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Text",
|
||||||
"label": "Stock Queue (FIFO)",
|
"label": "FIFO Stock Queue (qty, rate)",
|
||||||
"oldfieldname": "fcfs_stack",
|
"oldfieldname": "fcfs_stack",
|
||||||
"oldfieldtype": "Text",
|
"oldfieldtype": "Text",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
@ -317,10 +317,11 @@
|
|||||||
"in_create": 1,
|
"in_create": 1,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-10-08 13:42:51.857631",
|
"modified": "2021-12-21 06:25:30.040801",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Stock Ledger Entry",
|
"name": "Stock Ledger Entry",
|
||||||
|
"naming_rule": "Expression (old style)",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
@ -338,5 +339,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC"
|
"sort_order": "DESC",
|
||||||
|
"states": []
|
||||||
}
|
}
|
@ -1097,7 +1097,7 @@ def apply_price_list(args, as_doc=False):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def apply_price_list_on_item(args):
|
def apply_price_list_on_item(args):
|
||||||
item_doc = frappe.get_doc("Item", args.item_code)
|
item_doc = frappe.db.get_value("Item", args.item_code, ['name', 'variant_of'], as_dict=1)
|
||||||
item_details = get_price_list_rate(args, item_doc)
|
item_details = get_price_list_rate(args, item_doc)
|
||||||
|
|
||||||
item_details.update(get_pricing_rule_for_item(args, item_details.price_list_rate))
|
item_details.update(get_pricing_rule_for_item(args, item_details.price_list_rate))
|
||||||
|
@ -8,7 +8,8 @@ const DIFFERNCE_FIELD_NAMES = [
|
|||||||
"fifo_value_diff",
|
"fifo_value_diff",
|
||||||
"fifo_valuation_diff",
|
"fifo_valuation_diff",
|
||||||
"valuation_diff",
|
"valuation_diff",
|
||||||
"fifo_difference_diff"
|
"fifo_difference_diff",
|
||||||
|
"diff_value_diff"
|
||||||
];
|
];
|
||||||
|
|
||||||
frappe.query_reports["Stock Ledger Invariant Check"] = {
|
frappe.query_reports["Stock Ledger Invariant Check"] = {
|
||||||
|
@ -50,6 +50,7 @@ def get_stock_ledger_entries(filters):
|
|||||||
|
|
||||||
def add_invariant_check_fields(sles):
|
def add_invariant_check_fields(sles):
|
||||||
balance_qty = 0.0
|
balance_qty = 0.0
|
||||||
|
balance_stock_value = 0.0
|
||||||
for idx, sle in enumerate(sles):
|
for idx, sle in enumerate(sles):
|
||||||
queue = json.loads(sle.stock_queue)
|
queue = json.loads(sle.stock_queue)
|
||||||
|
|
||||||
@ -60,6 +61,7 @@ def add_invariant_check_fields(sles):
|
|||||||
fifo_value += qty * rate
|
fifo_value += qty * rate
|
||||||
|
|
||||||
balance_qty += sle.actual_qty
|
balance_qty += sle.actual_qty
|
||||||
|
balance_stock_value += sle.stock_value_difference
|
||||||
if sle.voucher_type == "Stock Reconciliation" and not sle.batch_no:
|
if sle.voucher_type == "Stock Reconciliation" and not sle.batch_no:
|
||||||
balance_qty = sle.qty_after_transaction
|
balance_qty = sle.qty_after_transaction
|
||||||
|
|
||||||
@ -70,6 +72,7 @@ def add_invariant_check_fields(sles):
|
|||||||
sle.stock_value / sle.qty_after_transaction if sle.qty_after_transaction else None
|
sle.stock_value / sle.qty_after_transaction if sle.qty_after_transaction else None
|
||||||
)
|
)
|
||||||
sle.expected_qty_after_transaction = balance_qty
|
sle.expected_qty_after_transaction = balance_qty
|
||||||
|
sle.stock_value_from_diff = balance_stock_value
|
||||||
|
|
||||||
# set difference fields
|
# set difference fields
|
||||||
sle.difference_in_qty = sle.qty_after_transaction - sle.expected_qty_after_transaction
|
sle.difference_in_qty = sle.qty_after_transaction - sle.expected_qty_after_transaction
|
||||||
@ -81,6 +84,7 @@ def add_invariant_check_fields(sles):
|
|||||||
sle.valuation_diff = (
|
sle.valuation_diff = (
|
||||||
sle.valuation_rate - sle.balance_value_by_qty if sle.balance_value_by_qty else None
|
sle.valuation_rate - sle.balance_value_by_qty if sle.balance_value_by_qty else None
|
||||||
)
|
)
|
||||||
|
sle.diff_value_diff = sle.stock_value_from_diff - sle.stock_value
|
||||||
|
|
||||||
if idx > 0:
|
if idx > 0:
|
||||||
sle.fifo_stock_diff = sle.fifo_stock_value - sles[idx - 1].fifo_stock_value
|
sle.fifo_stock_diff = sle.fifo_stock_value - sles[idx - 1].fifo_stock_value
|
||||||
@ -191,12 +195,21 @@ def get_columns():
|
|||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "D - E",
|
"label": "D - E",
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"fieldname": "stock_value_difference",
|
"fieldname": "stock_value_difference",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "(F) Stock Value Difference",
|
"label": "(F) Stock Value Difference",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "stock_value_from_diff",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"label": "Balance Stock Value using (F)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "diff_value_diff",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"label": "K - D",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "fifo_stock_diff",
|
"fieldname": "fifo_stock_diff",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
|
@ -98,6 +98,7 @@ class TestIssue(TestSetUp):
|
|||||||
issue.save()
|
issue.save()
|
||||||
|
|
||||||
self.assertEqual(issue.on_hold_since, frappe.flags.current_time)
|
self.assertEqual(issue.on_hold_since, frappe.flags.current_time)
|
||||||
|
self.assertFalse(issue.resolution_by)
|
||||||
|
|
||||||
creation = get_datetime("2020-03-04 5:00")
|
creation = get_datetime("2020-03-04 5:00")
|
||||||
frappe.flags.current_time = get_datetime("2020-03-04 5:00")
|
frappe.flags.current_time = get_datetime("2020-03-04 5:00")
|
||||||
|
@ -476,7 +476,7 @@ def update_response_and_resolution_metrics(doc, apply_sla_for_resolution):
|
|||||||
priority = get_response_and_resolution_duration(doc)
|
priority = get_response_and_resolution_duration(doc)
|
||||||
start_date_time = get_datetime(doc.get("service_level_agreement_creation") or doc.creation)
|
start_date_time = get_datetime(doc.get("service_level_agreement_creation") or doc.creation)
|
||||||
set_response_by(doc, start_date_time, priority)
|
set_response_by(doc, start_date_time, priority)
|
||||||
if apply_sla_for_resolution:
|
if apply_sla_for_resolution and not doc.get('on_hold_since'): # resolution_by is reset if on hold
|
||||||
set_resolution_by(doc, start_date_time, priority)
|
set_resolution_by(doc, start_date_time, priority)
|
||||||
|
|
||||||
|
|
||||||
@ -624,9 +624,6 @@ def reset_resolution_metrics(doc):
|
|||||||
if doc.meta.has_field("user_resolution_time"):
|
if doc.meta.has_field("user_resolution_time"):
|
||||||
doc.user_resolution_time = None
|
doc.user_resolution_time = None
|
||||||
|
|
||||||
if doc.meta.has_field("agreement_status"):
|
|
||||||
doc.agreement_status = "First Response Due"
|
|
||||||
|
|
||||||
|
|
||||||
# called via hooks on communication update
|
# called via hooks on communication update
|
||||||
def on_communication_update(doc, status):
|
def on_communication_update(doc, status):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user