Merge branch 'develop' into UX
This commit is contained in:
commit
99522252c4
@ -328,6 +328,21 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
self.assertEquals(item.discount_amount, 110)
|
self.assertEquals(item.discount_amount, 110)
|
||||||
self.assertEquals(item.rate, 990)
|
self.assertEquals(item.rate, 990)
|
||||||
|
|
||||||
|
def test_pricing_rule_with_margin_and_discount_amount(self):
|
||||||
|
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
||||||
|
make_pricing_rule(selling=1, margin_type="Percentage", margin_rate_or_amount=10,
|
||||||
|
rate_or_discount="Discount Amount", discount_amount=110)
|
||||||
|
si = create_sales_invoice(do_not_save=True)
|
||||||
|
si.items[0].price_list_rate = 1000
|
||||||
|
si.payment_schedule = []
|
||||||
|
si.insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
item = si.items[0]
|
||||||
|
self.assertEquals(item.margin_rate_or_amount, 10)
|
||||||
|
self.assertEquals(item.rate_with_margin, 1100)
|
||||||
|
self.assertEquals(item.discount_amount, 110)
|
||||||
|
self.assertEquals(item.rate, 990)
|
||||||
|
|
||||||
def test_pricing_rule_for_product_discount_on_same_item(self):
|
def test_pricing_rule_for_product_discount_on_same_item(self):
|
||||||
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
||||||
test_record = {
|
test_record = {
|
||||||
@ -560,6 +575,7 @@ def make_pricing_rule(**args):
|
|||||||
"margin_rate_or_amount": args.margin_rate_or_amount or 0.0,
|
"margin_rate_or_amount": args.margin_rate_or_amount or 0.0,
|
||||||
"condition": args.condition or '',
|
"condition": args.condition or '',
|
||||||
"priority": 1,
|
"priority": 1,
|
||||||
|
"discount_amount": args.discount_amount or 0.0,
|
||||||
"apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0
|
"apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -127,7 +127,6 @@
|
|||||||
"write_off_cost_center",
|
"write_off_cost_center",
|
||||||
"advances_section",
|
"advances_section",
|
||||||
"allocate_advances_automatically",
|
"allocate_advances_automatically",
|
||||||
"adjust_advance_taxes",
|
|
||||||
"get_advances",
|
"get_advances",
|
||||||
"advances",
|
"advances",
|
||||||
"payment_schedule_section",
|
"payment_schedule_section",
|
||||||
@ -1326,13 +1325,6 @@
|
|||||||
"label": "Project",
|
"label": "Project",
|
||||||
"options": "Project"
|
"options": "Project"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"default": "0",
|
|
||||||
"description": "Taxes paid while advance payment will be adjusted against this invoice",
|
|
||||||
"fieldname": "adjust_advance_taxes",
|
|
||||||
"fieldtype": "Check",
|
|
||||||
"label": "Adjust Advance Taxes"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.is_internal_supplier",
|
"depends_on": "eval:doc.is_internal_supplier",
|
||||||
"description": "Unrealized Profit / Loss account for intra-company transfers",
|
"description": "Unrealized Profit / Loss account for intra-company transfers",
|
||||||
@ -1378,7 +1370,7 @@
|
|||||||
"idx": 204,
|
"idx": 204,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-03-09 21:12:30.422084",
|
"modified": "2021-03-30 21:45:58.334107",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice",
|
"name": "Purchase Invoice",
|
||||||
|
|||||||
@ -406,9 +406,10 @@ def check_if_advance_entry_modified(args):
|
|||||||
throw(_("""Payment Entry has been modified after you pulled it. Please pull it again."""))
|
throw(_("""Payment Entry has been modified after you pulled it. Please pull it again."""))
|
||||||
|
|
||||||
def validate_allocated_amount(args):
|
def validate_allocated_amount(args):
|
||||||
|
precision = args.get('precision') or frappe.db.get_single_value("System Settings", "currency_precision")
|
||||||
if args.get("allocated_amount") < 0:
|
if args.get("allocated_amount") < 0:
|
||||||
throw(_("Allocated amount cannot be negative"))
|
throw(_("Allocated amount cannot be negative"))
|
||||||
elif args.get("allocated_amount") > args.get("unadjusted_amount"):
|
elif flt(args.get("allocated_amount"), precision) > flt(args.get("unadjusted_amount"), precision):
|
||||||
throw(_("Allocated amount cannot be greater than unadjusted amount"))
|
throw(_("Allocated amount cannot be greater than unadjusted amount"))
|
||||||
|
|
||||||
def update_reference_in_journal_entry(d, jv_obj):
|
def update_reference_in_journal_entry(d, jv_obj):
|
||||||
|
|||||||
@ -659,6 +659,7 @@ class AccountsController(TransactionBase):
|
|||||||
'dr_or_cr': dr_or_cr,
|
'dr_or_cr': dr_or_cr,
|
||||||
'unadjusted_amount': flt(d.advance_amount),
|
'unadjusted_amount': flt(d.advance_amount),
|
||||||
'allocated_amount': flt(d.allocated_amount),
|
'allocated_amount': flt(d.allocated_amount),
|
||||||
|
'precision': d.precision('advance_amount'),
|
||||||
'exchange_rate': (self.conversion_rate
|
'exchange_rate': (self.conversion_rate
|
||||||
if self.party_account_currency != self.company_currency else 1),
|
if self.party_account_currency != self.company_currency else 1),
|
||||||
'grand_total': (self.base_grand_total
|
'grand_total': (self.base_grand_total
|
||||||
|
|||||||
@ -406,8 +406,7 @@ class StockController(AccountsController):
|
|||||||
def set_rate_of_stock_uom(self):
|
def set_rate_of_stock_uom(self):
|
||||||
if self.doctype in ["Purchase Receipt", "Purchase Invoice", "Purchase Order", "Sales Invoice", "Sales Order", "Delivery Note", "Quotation"]:
|
if self.doctype in ["Purchase Receipt", "Purchase Invoice", "Purchase Order", "Sales Invoice", "Sales Order", "Delivery Note", "Quotation"]:
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
if d.conversion_factor:
|
d.stock_uom_rate = d.rate / (d.conversion_factor or 1)
|
||||||
d.stock_uom_rate = d.rate / d.conversion_factor
|
|
||||||
|
|
||||||
def validate_internal_transfer(self):
|
def validate_internal_transfer(self):
|
||||||
if self.doctype in ('Sales Invoice', 'Delivery Note', 'Purchase Invoice', 'Purchase Receipt') \
|
if self.doctype in ('Sales Invoice', 'Delivery Note', 'Purchase Invoice', 'Purchase Receipt') \
|
||||||
|
|||||||
8
erpnext/crm/doctype/lead_source/lead_source.js
Normal file
8
erpnext/crm/doctype/lead_source/lead_source.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on('Lead Source', {
|
||||||
|
// refresh: function(frm) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
});
|
||||||
62
erpnext/crm/doctype/lead_source/lead_source.json
Normal file
62
erpnext/crm/doctype/lead_source/lead_source.json
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"autoname": "field:source_name",
|
||||||
|
"creation": "2016-09-16 01:47:47.382372",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"source_name",
|
||||||
|
"details"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "source_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Source Name",
|
||||||
|
"reqd": 1,
|
||||||
|
"unique": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "details",
|
||||||
|
"fieldtype": "Text Editor",
|
||||||
|
"label": "Details"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"links": [],
|
||||||
|
"modified": "2021-02-08 12:51:48.971517",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "CRM",
|
||||||
|
"name": "Lead Source",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Sales Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Sales User",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"quick_entry": 1,
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC"
|
||||||
|
}
|
||||||
@ -1,9 +1,9 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
# import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
class LeadSource(Document):
|
class LeadSource(Document):
|
||||||
@ -1,12 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
# See license.txt
|
# See license.txt
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import frappe
|
# import frappe
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
# test_records = frappe.get_test_records('Lead Source')
|
|
||||||
|
|
||||||
class TestLeadSource(unittest.TestCase):
|
class TestLeadSource(unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
@ -23,6 +23,7 @@
|
|||||||
"rate_of_interest",
|
"rate_of_interest",
|
||||||
"is_secured_loan",
|
"is_secured_loan",
|
||||||
"disbursement_date",
|
"disbursement_date",
|
||||||
|
"closure_date",
|
||||||
"disbursed_amount",
|
"disbursed_amount",
|
||||||
"column_break_11",
|
"column_break_11",
|
||||||
"maximum_loan_amount",
|
"maximum_loan_amount",
|
||||||
@ -348,12 +349,18 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "closure_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "Closure Date",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-11-24 12:27:23.208240",
|
"modified": "2021-04-10 09:28:21.946972",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Loan",
|
"name": "Loan",
|
||||||
|
|||||||
@ -523,33 +523,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
self.assertEqual(flt(repayment_entry.total_interest_paid, 0), flt(interest_amount, 0))
|
self.assertEqual(flt(repayment_entry.total_interest_paid, 0), flt(interest_amount, 0))
|
||||||
|
|
||||||
def test_penalty(self):
|
def test_penalty(self):
|
||||||
pledge = [{
|
loan, amounts = create_loan_scenario_for_penalty(self)
|
||||||
"loan_security": "Test Security 1",
|
|
||||||
"qty": 4000.00
|
|
||||||
}]
|
|
||||||
|
|
||||||
loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
|
|
||||||
create_pledge(loan_application)
|
|
||||||
|
|
||||||
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
|
||||||
loan.submit()
|
|
||||||
|
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
|
||||||
|
|
||||||
first_date = '2019-10-01'
|
|
||||||
last_date = '2019-10-30'
|
|
||||||
|
|
||||||
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
|
|
||||||
process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
|
|
||||||
|
|
||||||
amounts = calculate_amounts(loan.name, add_days(last_date, 1))
|
|
||||||
paid_amount = amounts['interest_amount']/2
|
|
||||||
|
|
||||||
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
|
|
||||||
paid_amount)
|
|
||||||
|
|
||||||
repayment_entry.submit()
|
|
||||||
|
|
||||||
# 30 days - grace period
|
# 30 days - grace period
|
||||||
penalty_days = 30 - 4
|
penalty_days = 30 - 4
|
||||||
penalty_applicable_amount = flt(amounts['interest_amount']/2)
|
penalty_applicable_amount = flt(amounts['interest_amount']/2)
|
||||||
@ -559,8 +533,28 @@ class TestLoan(unittest.TestCase):
|
|||||||
calculated_penalty_amount = frappe.db.get_value('Loan Interest Accrual',
|
calculated_penalty_amount = frappe.db.get_value('Loan Interest Accrual',
|
||||||
{'process_loan_interest_accrual': process, 'loan': loan.name}, 'penalty_amount')
|
{'process_loan_interest_accrual': process, 'loan': loan.name}, 'penalty_amount')
|
||||||
|
|
||||||
|
self.assertEquals(loan.loan_amount, 1000000)
|
||||||
self.assertEquals(calculated_penalty_amount, penalty_amount)
|
self.assertEquals(calculated_penalty_amount, penalty_amount)
|
||||||
|
|
||||||
|
def test_penalty_repayment(self):
|
||||||
|
loan, dummy = create_loan_scenario_for_penalty(self)
|
||||||
|
amounts = calculate_amounts(loan.name, '2019-11-30 00:00:00')
|
||||||
|
|
||||||
|
first_penalty = 10000
|
||||||
|
second_penalty = amounts['penalty_amount'] - 10000
|
||||||
|
|
||||||
|
repayment_entry = create_repayment_entry(loan.name, self.applicant2, '2019-11-30 00:00:00', 10000)
|
||||||
|
repayment_entry.submit()
|
||||||
|
|
||||||
|
amounts = calculate_amounts(loan.name, '2019-11-30 00:00:01')
|
||||||
|
self.assertEquals(amounts['penalty_amount'], second_penalty)
|
||||||
|
|
||||||
|
repayment_entry = create_repayment_entry(loan.name, self.applicant2, '2019-11-30 00:00:01', second_penalty)
|
||||||
|
repayment_entry.submit()
|
||||||
|
|
||||||
|
amounts = calculate_amounts(loan.name, '2019-11-30 00:00:02')
|
||||||
|
self.assertEquals(amounts['penalty_amount'], 0)
|
||||||
|
|
||||||
def test_loan_write_off_limit(self):
|
def test_loan_write_off_limit(self):
|
||||||
pledge = [{
|
pledge = [{
|
||||||
"loan_security": "Test Security 1",
|
"loan_security": "Test Security 1",
|
||||||
@ -651,6 +645,32 @@ class TestLoan(unittest.TestCase):
|
|||||||
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
||||||
self.assertEquals(flt(amounts['pending_principal_amount'], 0), 0)
|
self.assertEquals(flt(amounts['pending_principal_amount'], 0), 0)
|
||||||
|
|
||||||
|
def create_loan_scenario_for_penalty(doc):
|
||||||
|
pledge = [{
|
||||||
|
"loan_security": "Test Security 1",
|
||||||
|
"qty": 4000.00
|
||||||
|
}]
|
||||||
|
|
||||||
|
loan_application = create_loan_application('_Test Company', doc.applicant2, 'Demand Loan', pledge)
|
||||||
|
create_pledge(loan_application)
|
||||||
|
loan = create_demand_loan(doc.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||||
|
loan.submit()
|
||||||
|
|
||||||
|
first_date = '2019-10-01'
|
||||||
|
last_date = '2019-10-30'
|
||||||
|
|
||||||
|
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
|
||||||
|
process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
|
||||||
|
|
||||||
|
amounts = calculate_amounts(loan.name, add_days(last_date, 1))
|
||||||
|
paid_amount = amounts['interest_amount']/2
|
||||||
|
|
||||||
|
repayment_entry = create_repayment_entry(loan.name, doc.applicant2, add_days(last_date, 5),
|
||||||
|
paid_amount)
|
||||||
|
|
||||||
|
repayment_entry.submit()
|
||||||
|
|
||||||
|
return loan, amounts
|
||||||
|
|
||||||
def create_loan_accounts():
|
def create_loan_accounts():
|
||||||
if not frappe.db.exists("Account", "Loans and Advances (Assets) - _TC"):
|
if not frappe.db.exists("Account", "Loans and Advances (Assets) - _TC"):
|
||||||
|
|||||||
@ -20,6 +20,10 @@
|
|||||||
"cost_center",
|
"cost_center",
|
||||||
"customer_details_section",
|
"customer_details_section",
|
||||||
"bank_account",
|
"bank_account",
|
||||||
|
"disbursement_references_section",
|
||||||
|
"reference_date",
|
||||||
|
"column_break_17",
|
||||||
|
"reference_number",
|
||||||
"amended_from"
|
"amended_from"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
@ -126,12 +130,31 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "column_break_8",
|
"fieldname": "column_break_8",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "disbursement_references_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Disbursement References"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "reference_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "Reference Date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_17",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "reference_number",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Reference Number"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-11-06 10:04:30.882322",
|
"modified": "2021-04-10 10:03:41.502210",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Loan Disbursement",
|
"name": "Loan Disbursement",
|
||||||
|
|||||||
@ -239,14 +239,16 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "total_penalty_paid",
|
"fieldname": "total_penalty_paid",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
|
"hidden": 1,
|
||||||
"label": "Total Penalty Paid",
|
"label": "Total Penalty Paid",
|
||||||
"options": "Company:company:default_currency"
|
"options": "Company:company:default_currency",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-04-05 13:45:19.137896",
|
"modified": "2021-04-10 10:00:31.859076",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Loan Repayment",
|
"name": "Loan Repayment",
|
||||||
|
|||||||
@ -75,7 +75,7 @@ class LoanRepayment(AccountsController):
|
|||||||
"docstatus": 1, "against_loan": self.against_loan}, 'posting_date')
|
"docstatus": 1, "against_loan": self.against_loan}, 'posting_date')
|
||||||
|
|
||||||
if future_repayment_date:
|
if future_repayment_date:
|
||||||
frappe.throw("Repayment already made till date {0}".format(getdate(future_repayment_date)))
|
frappe.throw("Repayment already made till date {0}".format(get_datetime(future_repayment_date)))
|
||||||
|
|
||||||
def validate_amount(self):
|
def validate_amount(self):
|
||||||
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||||
@ -83,10 +83,6 @@ class LoanRepayment(AccountsController):
|
|||||||
if not self.amount_paid:
|
if not self.amount_paid:
|
||||||
frappe.throw(_("Amount paid cannot be zero"))
|
frappe.throw(_("Amount paid cannot be zero"))
|
||||||
|
|
||||||
if not self.shortfall_amount and self.amount_paid < self.penalty_amount:
|
|
||||||
msg = _("Paid amount cannot be less than {0}").format(self.penalty_amount)
|
|
||||||
frappe.throw(msg)
|
|
||||||
|
|
||||||
def book_unaccrued_interest(self):
|
def book_unaccrued_interest(self):
|
||||||
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||||
if self.total_interest_paid > self.interest_payable:
|
if self.total_interest_paid > self.interest_payable:
|
||||||
@ -231,6 +227,14 @@ class LoanRepayment(AccountsController):
|
|||||||
gle_map = []
|
gle_map = []
|
||||||
loan_details = frappe.get_doc("Loan", self.against_loan)
|
loan_details = frappe.get_doc("Loan", self.against_loan)
|
||||||
|
|
||||||
|
if self.shortfall_amount and self.amount_paid > self.shortfall_amount:
|
||||||
|
remarks = _("Shortfall Repayment of {0}.\nRepayment against Loan: {1}").format(self.shortfall_amount,
|
||||||
|
self.against_loan)
|
||||||
|
elif self.shortfall_amount:
|
||||||
|
remarks = _("Shortfall Repayment of {0}").format(self.shortfall_amount)
|
||||||
|
else:
|
||||||
|
remarks = _("Repayment against Loan: ") + self.against_loan
|
||||||
|
|
||||||
if self.total_penalty_paid:
|
if self.total_penalty_paid:
|
||||||
gle_map.append(
|
gle_map.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
@ -271,7 +275,7 @@ class LoanRepayment(AccountsController):
|
|||||||
"debit_in_account_currency": self.amount_paid,
|
"debit_in_account_currency": self.amount_paid,
|
||||||
"against_voucher_type": "Loan",
|
"against_voucher_type": "Loan",
|
||||||
"against_voucher": self.against_loan,
|
"against_voucher": self.against_loan,
|
||||||
"remarks": _("Repayment against Loan: ") + self.against_loan,
|
"remarks": remarks,
|
||||||
"cost_center": self.cost_center,
|
"cost_center": self.cost_center,
|
||||||
"posting_date": getdate(self.posting_date)
|
"posting_date": getdate(self.posting_date)
|
||||||
})
|
})
|
||||||
@ -287,7 +291,7 @@ class LoanRepayment(AccountsController):
|
|||||||
"credit_in_account_currency": self.amount_paid,
|
"credit_in_account_currency": self.amount_paid,
|
||||||
"against_voucher_type": "Loan",
|
"against_voucher_type": "Loan",
|
||||||
"against_voucher": self.against_loan,
|
"against_voucher": self.against_loan,
|
||||||
"remarks": _("Repayment against Loan: ") + self.against_loan,
|
"remarks": remarks,
|
||||||
"cost_center": self.cost_center,
|
"cost_center": self.cost_center,
|
||||||
"posting_date": getdate(self.posting_date)
|
"posting_date": getdate(self.posting_date)
|
||||||
})
|
})
|
||||||
@ -338,6 +342,18 @@ def get_accrued_interest_entries(against_loan, posting_date=None):
|
|||||||
|
|
||||||
return unpaid_accrued_entries
|
return unpaid_accrued_entries
|
||||||
|
|
||||||
|
def get_penalty_details(against_loan):
|
||||||
|
penalty_details = frappe.db.sql("""
|
||||||
|
SELECT posting_date, (penalty_amount - total_penalty_paid) as pending_penalty_amount
|
||||||
|
FROM `tabLoan Repayment` where posting_date >= (SELECT MAX(posting_date) from `tabLoan Repayment`
|
||||||
|
where against_loan = %s) and docstatus = 1 and against_loan = %s
|
||||||
|
""", (against_loan, against_loan))
|
||||||
|
|
||||||
|
if penalty_details:
|
||||||
|
return penalty_details[0][0], flt(penalty_details[0][1])
|
||||||
|
else:
|
||||||
|
return None, 0
|
||||||
|
|
||||||
# This function returns the amounts that are payable at the time of loan repayment based on posting date
|
# This function returns the amounts that are payable at the time of loan repayment based on posting date
|
||||||
# So it pulls all the unpaid Loan Interest Accrual Entries and calculates the penalty if applicable
|
# So it pulls all the unpaid Loan Interest Accrual Entries and calculates the penalty if applicable
|
||||||
|
|
||||||
@ -348,6 +364,7 @@ def get_amounts(amounts, against_loan, posting_date):
|
|||||||
loan_type_details = frappe.get_doc("Loan Type", against_loan_doc.loan_type)
|
loan_type_details = frappe.get_doc("Loan Type", against_loan_doc.loan_type)
|
||||||
accrued_interest_entries = get_accrued_interest_entries(against_loan_doc.name, posting_date)
|
accrued_interest_entries = get_accrued_interest_entries(against_loan_doc.name, posting_date)
|
||||||
|
|
||||||
|
computed_penalty_date, pending_penalty_amount = get_penalty_details(against_loan)
|
||||||
pending_accrual_entries = {}
|
pending_accrual_entries = {}
|
||||||
|
|
||||||
total_pending_interest = 0
|
total_pending_interest = 0
|
||||||
@ -362,8 +379,13 @@ def get_amounts(amounts, against_loan, posting_date):
|
|||||||
# and if no_of_late days are positive then penalty is levied
|
# and if no_of_late days are positive then penalty is levied
|
||||||
|
|
||||||
due_date = add_days(entry.posting_date, 1)
|
due_date = add_days(entry.posting_date, 1)
|
||||||
no_of_late_days = date_diff(posting_date,
|
due_date_after_grace_period = add_days(due_date, loan_type_details.grace_period_in_days)
|
||||||
add_days(due_date, loan_type_details.grace_period_in_days)) + 1
|
|
||||||
|
# Consider one day after already calculated penalty
|
||||||
|
if computed_penalty_date and getdate(computed_penalty_date) >= due_date_after_grace_period:
|
||||||
|
due_date_after_grace_period = add_days(computed_penalty_date, 1)
|
||||||
|
|
||||||
|
no_of_late_days = date_diff(posting_date, due_date_after_grace_period) + 1
|
||||||
|
|
||||||
if no_of_late_days > 0 and (not against_loan_doc.repay_from_salary) and entry.accrual_type == 'Regular':
|
if no_of_late_days > 0 and (not against_loan_doc.repay_from_salary) and entry.accrual_type == 'Regular':
|
||||||
penalty_amount += (entry.interest_amount * (loan_type_details.penalty_interest_rate / 100) * no_of_late_days)
|
penalty_amount += (entry.interest_amount * (loan_type_details.penalty_interest_rate / 100) * no_of_late_days)
|
||||||
@ -401,7 +423,7 @@ def get_amounts(amounts, against_loan, posting_date):
|
|||||||
amounts["pending_principal_amount"] = flt(pending_principal_amount, precision)
|
amounts["pending_principal_amount"] = flt(pending_principal_amount, precision)
|
||||||
amounts["payable_principal_amount"] = flt(payable_principal_amount, precision)
|
amounts["payable_principal_amount"] = flt(payable_principal_amount, precision)
|
||||||
amounts["interest_amount"] = flt(total_pending_interest, precision)
|
amounts["interest_amount"] = flt(total_pending_interest, precision)
|
||||||
amounts["penalty_amount"] = flt(penalty_amount, precision)
|
amounts["penalty_amount"] = flt(penalty_amount + pending_penalty_amount, precision)
|
||||||
amounts["payable_amount"] = flt(payable_principal_amount + total_pending_interest + penalty_amount, precision)
|
amounts["payable_amount"] = flt(payable_principal_amount + total_pending_interest + penalty_amount, precision)
|
||||||
amounts["pending_accrual_entries"] = pending_accrual_entries
|
amounts["pending_accrual_entries"] = pending_accrual_entries
|
||||||
amounts["unaccrued_interest"] = flt(unaccrued_interest, precision)
|
amounts["unaccrued_interest"] = flt(unaccrued_interest, precision)
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import get_datetime, flt
|
from frappe.utils import get_datetime, flt, getdate
|
||||||
import json
|
import json
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
from erpnext.loan_management.doctype.loan_security_price.loan_security_price import get_loan_security_price
|
from erpnext.loan_management.doctype.loan_security_price.loan_security_price import get_loan_security_price
|
||||||
@ -113,7 +113,11 @@ class LoanSecurityUnpledge(Document):
|
|||||||
pledged_qty += qty
|
pledged_qty += qty
|
||||||
|
|
||||||
if not pledged_qty:
|
if not pledged_qty:
|
||||||
frappe.db.set_value('Loan', self.loan, 'status', 'Closed')
|
frappe.db.set_value('Loan', self.loan,
|
||||||
|
{
|
||||||
|
'status': 'Closed',
|
||||||
|
'closure_date': getdate()
|
||||||
|
})
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_pledged_security_qty(loan):
|
def get_pledged_security_qty(loan):
|
||||||
|
|||||||
@ -763,4 +763,5 @@ erpnext.patches.v13_0.setup_gratuity_rule_for_india_and_uae
|
|||||||
erpnext.patches.v13_0.setup_uae_vat_fields
|
erpnext.patches.v13_0.setup_uae_vat_fields
|
||||||
execute:frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext')
|
execute:frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext')
|
||||||
erpnext.patches.v13_0.rename_discharge_date_in_ip_record
|
erpnext.patches.v13_0.rename_discharge_date_in_ip_record
|
||||||
|
erpnext.patches.v12_0.add_gst_category_in_delivery_note
|
||||||
erpnext.patches.v12_0.purchase_receipt_status
|
erpnext.patches.v12_0.purchase_receipt_status
|
||||||
|
|||||||
19
erpnext/patches/v12_0/add_gst_category_in_delivery_note.py
Normal file
19
erpnext/patches/v12_0/add_gst_category_in_delivery_note.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||||
|
if not company:
|
||||||
|
return
|
||||||
|
|
||||||
|
custom_fields = {
|
||||||
|
'Delivery Note': [
|
||||||
|
dict(fieldname='gst_category', label='GST Category',
|
||||||
|
fieldtype='Select', insert_after='gst_vehicle_type', print_hide=1,
|
||||||
|
options='\nRegistered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nConsumer\nDeemed Export\nUIN Holders',
|
||||||
|
fetch_from='customer.gst_category', fetch_if_empty=1),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
create_custom_fields(custom_fields, update=True)
|
||||||
@ -18,6 +18,7 @@ def execute():
|
|||||||
|
|
||||||
for old_dt, new_dt in doctypes.items():
|
for old_dt, new_dt in doctypes.items():
|
||||||
if not frappe.db.table_exists(new_dt) and frappe.db.table_exists(old_dt):
|
if not frappe.db.table_exists(new_dt) and frappe.db.table_exists(old_dt):
|
||||||
|
frappe.reload_doc('healthcare', 'doctype', frappe.scrub(old_dt))
|
||||||
frappe.rename_doc('DocType', old_dt, new_dt, force=True)
|
frappe.rename_doc('DocType', old_dt, new_dt, force=True)
|
||||||
frappe.reload_doc('healthcare', 'doctype', frappe.scrub(new_dt))
|
frappe.reload_doc('healthcare', 'doctype', frappe.scrub(new_dt))
|
||||||
frappe.delete_doc_if_exists('DocType', old_dt)
|
frappe.delete_doc_if_exists('DocType', old_dt)
|
||||||
@ -36,6 +37,18 @@ def execute():
|
|||||||
SET parentfield = %(parentfield)s
|
SET parentfield = %(parentfield)s
|
||||||
""".format(doctype), {'parentfield': parentfield})
|
""".format(doctype), {'parentfield': parentfield})
|
||||||
|
|
||||||
|
# copy renamed child table fields (fields were already renamed in old doctype json, hence sql)
|
||||||
|
frappe.db.sql("""UPDATE `tabNormal Test Result` SET lab_test_name = test_name""")
|
||||||
|
frappe.db.sql("""UPDATE `tabNormal Test Result` SET lab_test_event = test_event""")
|
||||||
|
frappe.db.sql("""UPDATE `tabNormal Test Result` SET lab_test_uom = test_uom""")
|
||||||
|
frappe.db.sql("""UPDATE `tabNormal Test Result` SET lab_test_comment = test_comment""")
|
||||||
|
frappe.db.sql("""UPDATE `tabNormal Test Template` SET lab_test_event = test_event""")
|
||||||
|
frappe.db.sql("""UPDATE `tabNormal Test Template` SET lab_test_uom = test_uom""")
|
||||||
|
frappe.db.sql("""UPDATE `tabDescriptive Test Result` SET lab_test_particulars = test_particulars""")
|
||||||
|
frappe.db.sql("""UPDATE `tabLab Test Group Template` SET lab_test_template = test_template""")
|
||||||
|
frappe.db.sql("""UPDATE `tabLab Test Group Template` SET lab_test_description = test_description""")
|
||||||
|
frappe.db.sql("""UPDATE `tabLab Test Group Template` SET lab_test_rate = test_rate""")
|
||||||
|
|
||||||
# rename field
|
# rename field
|
||||||
frappe.reload_doc('healthcare', 'doctype', 'lab_test')
|
frappe.reload_doc('healthcare', 'doctype', 'lab_test')
|
||||||
if frappe.db.has_column('Lab Test', 'special_toggle'):
|
if frappe.db.has_column('Lab Test', 'special_toggle'):
|
||||||
|
|||||||
@ -20,9 +20,11 @@ def execute():
|
|||||||
frappe.clear_cache()
|
frappe.clear_cache()
|
||||||
frappe.flags.warehouse_account_map = {}
|
frappe.flags.warehouse_account_map = {}
|
||||||
|
|
||||||
|
company_list = []
|
||||||
|
|
||||||
data = frappe.db.sql('''
|
data = frappe.db.sql('''
|
||||||
SELECT
|
SELECT
|
||||||
name, item_code, warehouse, voucher_type, voucher_no, posting_date, posting_time
|
name, item_code, warehouse, voucher_type, voucher_no, posting_date, posting_time, company
|
||||||
FROM
|
FROM
|
||||||
`tabStock Ledger Entry`
|
`tabStock Ledger Entry`
|
||||||
WHERE
|
WHERE
|
||||||
@ -36,6 +38,9 @@ def execute():
|
|||||||
total_sle = len(data)
|
total_sle = len(data)
|
||||||
i = 0
|
i = 0
|
||||||
for d in data:
|
for d in data:
|
||||||
|
if d.company not in company_list:
|
||||||
|
company_list.append(d.company)
|
||||||
|
|
||||||
update_entries_after({
|
update_entries_after({
|
||||||
"item_code": d.item_code,
|
"item_code": d.item_code,
|
||||||
"warehouse": d.warehouse,
|
"warehouse": d.warehouse,
|
||||||
@ -53,8 +58,10 @@ def execute():
|
|||||||
|
|
||||||
print("Reposting General Ledger Entries...")
|
print("Reposting General Ledger Entries...")
|
||||||
|
|
||||||
for row in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
|
if data:
|
||||||
update_gl_entries_after(posting_date, posting_time, company=row.name)
|
for row in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
|
||||||
|
if row.name in company_list:
|
||||||
|
update_gl_entries_after(posting_date, posting_time, company=row.name)
|
||||||
|
|
||||||
frappe.db.auto_commit_on_many_writes = 0
|
frappe.db.auto_commit_on_many_writes = 0
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ def execute():
|
|||||||
|
|
||||||
frappe.reload_doc("healthcare", "doctype", "Therapy Session")
|
frappe.reload_doc("healthcare", "doctype", "Therapy Session")
|
||||||
frappe.reload_doc("healthcare", "doctype", "Inpatient Medication Order")
|
frappe.reload_doc("healthcare", "doctype", "Inpatient Medication Order")
|
||||||
|
frappe.reload_doc("healthcare", "doctype", "Clinical Procedure")
|
||||||
frappe.reload_doc("healthcare", "doctype", "Patient History Settings")
|
frappe.reload_doc("healthcare", "doctype", "Patient History Settings")
|
||||||
frappe.reload_doc("healthcare", "doctype", "Patient History Standard Document Type")
|
frappe.reload_doc("healthcare", "doctype", "Patient History Standard Document Type")
|
||||||
frappe.reload_doc("healthcare", "doctype", "Patient History Custom Document Type")
|
frappe.reload_doc("healthcare", "doctype", "Patient History Custom Document Type")
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from frappe import _
|
|||||||
def execute():
|
def execute():
|
||||||
from erpnext.setup.setup_wizard.operations.install_fixtures import default_lead_sources
|
from erpnext.setup.setup_wizard.operations.install_fixtures import default_lead_sources
|
||||||
|
|
||||||
frappe.reload_doc('selling', 'doctype', 'lead_source')
|
frappe.reload_doc('crm', 'doctype', 'lead_source')
|
||||||
|
|
||||||
frappe.local.lang = frappe.db.get_default("lang") or 'en'
|
frappe.local.lang = frappe.db.get_default("lang") or 'en'
|
||||||
|
|
||||||
|
|||||||
@ -33,12 +33,16 @@ class TestProject(unittest.TestCase):
|
|||||||
|
|
||||||
def test_project_template_having_parent_child_tasks(self):
|
def test_project_template_having_parent_child_tasks(self):
|
||||||
project_name = "Test Project with Template - Tasks with Parent-Child Relation"
|
project_name = "Test Project with Template - Tasks with Parent-Child Relation"
|
||||||
|
|
||||||
|
if frappe.db.get_value('Project', {'project_name': project_name}, 'name'):
|
||||||
|
project_name = frappe.db.get_value('Project', {'project_name': project_name}, 'name')
|
||||||
|
|
||||||
frappe.db.sql(""" delete from tabTask where project = %s """, project_name)
|
frappe.db.sql(""" delete from tabTask where project = %s """, project_name)
|
||||||
frappe.delete_doc('Project', project_name)
|
frappe.delete_doc('Project', project_name)
|
||||||
|
|
||||||
task1 = task_exists("Test Template Task Parent")
|
task1 = task_exists("Test Template Task Parent")
|
||||||
if not task1:
|
if not task1:
|
||||||
task1 = create_task(subject="Test Template Task Parent", is_group=1, is_template=1, begin=1, duration=4)
|
task1 = create_task(subject="Test Template Task Parent", is_group=1, is_template=1, begin=1, duration=10)
|
||||||
|
|
||||||
task2 = task_exists("Test Template Task Child 1")
|
task2 = task_exists("Test Template Task Child 1")
|
||||||
if not task2:
|
if not task2:
|
||||||
@ -53,7 +57,7 @@ class TestProject(unittest.TestCase):
|
|||||||
tasks = frappe.get_all('Task', ['subject','exp_end_date','depends_on_tasks', 'name', 'parent_task'], dict(project=project.name), order_by='creation asc')
|
tasks = frappe.get_all('Task', ['subject','exp_end_date','depends_on_tasks', 'name', 'parent_task'], dict(project=project.name), order_by='creation asc')
|
||||||
|
|
||||||
self.assertEqual(tasks[0].subject, 'Test Template Task Parent')
|
self.assertEqual(tasks[0].subject, 'Test Template Task Parent')
|
||||||
self.assertEqual(getdate(tasks[0].exp_end_date), calculate_end_date(project, 1, 4))
|
self.assertEqual(getdate(tasks[0].exp_end_date), calculate_end_date(project, 1, 10))
|
||||||
|
|
||||||
self.assertEqual(tasks[1].subject, 'Test Template Task Child 1')
|
self.assertEqual(tasks[1].subject, 'Test Template Task Child 1')
|
||||||
self.assertEqual(getdate(tasks[1].exp_end_date), calculate_end_date(project, 1, 3))
|
self.assertEqual(getdate(tasks[1].exp_end_date), calculate_end_date(project, 1, 3))
|
||||||
|
|||||||
@ -156,6 +156,13 @@ def make_custom_fields(update=True):
|
|||||||
fetch_if_empty=1),
|
fetch_if_empty=1),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
delivery_note_gst_category = [
|
||||||
|
dict(fieldname='gst_category', label='GST Category',
|
||||||
|
fieldtype='Select', insert_after='gst_vehicle_type', print_hide=1,
|
||||||
|
options='\nRegistered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nConsumer\nDeemed Export\nUIN Holders',
|
||||||
|
fetch_from='customer.gst_category', fetch_if_empty=1),
|
||||||
|
]
|
||||||
|
|
||||||
invoice_gst_fields = [
|
invoice_gst_fields = [
|
||||||
dict(fieldname='invoice_copy', label='Invoice Copy',
|
dict(fieldname='invoice_copy', label='Invoice Copy',
|
||||||
fieldtype='Select', insert_after='export_type', print_hide=1, allow_on_submit=1,
|
fieldtype='Select', insert_after='export_type', print_hide=1, allow_on_submit=1,
|
||||||
@ -280,7 +287,7 @@ def make_custom_fields(update=True):
|
|||||||
'allow_on_submit': 1,
|
'allow_on_submit': 1,
|
||||||
'insert_after': 'customer_name_in_arabic',
|
'insert_after': 'customer_name_in_arabic',
|
||||||
'translatable': 0,
|
'translatable': 0,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
si_ewaybill_fields = [
|
si_ewaybill_fields = [
|
||||||
@ -438,7 +445,7 @@ def make_custom_fields(update=True):
|
|||||||
'Purchase Order': purchase_invoice_gst_fields,
|
'Purchase Order': purchase_invoice_gst_fields,
|
||||||
'Purchase Receipt': purchase_invoice_gst_fields,
|
'Purchase Receipt': purchase_invoice_gst_fields,
|
||||||
'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields + si_einvoice_fields,
|
'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields + si_einvoice_fields,
|
||||||
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields,
|
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields + delivery_note_gst_category,
|
||||||
'Sales Order': sales_invoice_gst_fields,
|
'Sales Order': sales_invoice_gst_fields,
|
||||||
'Tax Category': inter_state_gst_field,
|
'Tax Category': inter_state_gst_field,
|
||||||
'Item': [
|
'Item': [
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
|
||||||
// For license information, please see license.txt
|
|
||||||
|
|
||||||
frappe.ui.form.on('Lead Source', {
|
|
||||||
refresh: function(frm) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -1,131 +0,0 @@
|
|||||||
{
|
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 1,
|
|
||||||
"autoname": "field:source_name",
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2016-09-16 01:47:47.382372",
|
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "source_name",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"label": "Source Name",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "details",
|
|
||||||
"fieldtype": "Text Editor",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"label": "Details",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2020-09-16 02:03:01.441622",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Selling",
|
|
||||||
"name": "Lead Source",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [
|
|
||||||
{
|
|
||||||
"amend": 0,
|
|
||||||
"apply_user_permissions": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
|
||||||
"delete": 1,
|
|
||||||
"email": 1,
|
|
||||||
"export": 1,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Sales Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"amend": 0,
|
|
||||||
"apply_user_permissions": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
|
||||||
"delete": 0,
|
|
||||||
"email": 1,
|
|
||||||
"export": 1,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Sales User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"quick_entry": 1,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_seen": 0
|
|
||||||
}
|
|
||||||
@ -279,11 +279,6 @@ erpnext.PointOfSale.Controller = class {
|
|||||||
const item_row = frappe.model.get_doc(cdt, cdn);
|
const item_row = frappe.model.get_doc(cdt, cdn);
|
||||||
if (item_row && item_row[fieldname] != value) {
|
if (item_row && item_row[fieldname] != value) {
|
||||||
|
|
||||||
if (fieldname === 'qty' && flt(value) == 0) {
|
|
||||||
this.remove_item_from_cart();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { item_code, batch_no, uom } = this.item_details.current_item;
|
const { item_code, batch_no, uom } = this.item_details.current_item;
|
||||||
const event = {
|
const event = {
|
||||||
field: fieldname,
|
field: fieldname,
|
||||||
|
|||||||
@ -27,7 +27,7 @@ def delete_company_transactions(company_name):
|
|||||||
if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
|
if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
|
||||||
"Party Account", "Employee", "Sales Taxes and Charges Template",
|
"Party Account", "Employee", "Sales Taxes and Charges Template",
|
||||||
"Purchase Taxes and Charges Template", "POS Profile", "BOM",
|
"Purchase Taxes and Charges Template", "POS Profile", "BOM",
|
||||||
"Company", "Bank Account", "Item Tax Template", "Mode Of Payment",
|
"Company", "Bank Account", "Item Tax Template", "Mode Of Payment", "Mode of Payment Account",
|
||||||
"Item Default", "Customer", "Supplier", "GST Account"):
|
"Item Default", "Customer", "Supplier", "GST Account"):
|
||||||
delete_for_doctype(doctype, company_name)
|
delete_for_doctype(doctype, company_name)
|
||||||
|
|
||||||
|
|||||||
@ -494,7 +494,8 @@ def make_item_variant():
|
|||||||
|
|
||||||
test_records = frappe.get_test_records('Item')
|
test_records = frappe.get_test_records('Item')
|
||||||
|
|
||||||
def create_item(item_code, is_stock_item=None, valuation_rate=0, warehouse=None, is_customer_provided_item=None, customer=None, is_purchase_item=None, opening_stock=None):
|
def create_item(item_code, is_stock_item=None, valuation_rate=0, warehouse=None, is_customer_provided_item=None,
|
||||||
|
customer=None, is_purchase_item=None, opening_stock=None, company=None):
|
||||||
if not frappe.db.exists("Item", item_code):
|
if not frappe.db.exists("Item", item_code):
|
||||||
item = frappe.new_doc("Item")
|
item = frappe.new_doc("Item")
|
||||||
item.item_code = item_code
|
item.item_code = item_code
|
||||||
@ -509,7 +510,7 @@ def create_item(item_code, is_stock_item=None, valuation_rate=0, warehouse=None,
|
|||||||
item.customer = customer or ''
|
item.customer = customer or ''
|
||||||
item.append("item_defaults", {
|
item.append("item_defaults", {
|
||||||
"default_warehouse": warehouse or '_Test Warehouse - _TC',
|
"default_warehouse": warehouse or '_Test Warehouse - _TC',
|
||||||
"company": "_Test Company"
|
"company": company or "_Test Company"
|
||||||
})
|
})
|
||||||
item.save()
|
item.save()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -379,7 +379,6 @@ def create_stock_entry(pick_list):
|
|||||||
else:
|
else:
|
||||||
stock_entry = update_stock_entry_items_with_no_reference(pick_list, stock_entry)
|
stock_entry = update_stock_entry_items_with_no_reference(pick_list, stock_entry)
|
||||||
|
|
||||||
stock_entry.set_incoming_rate()
|
|
||||||
stock_entry.set_actual_qty()
|
stock_entry.set_actual_qty()
|
||||||
stock_entry.calculate_rate_and_amount()
|
stock_entry.calculate_rate_and_amount()
|
||||||
|
|
||||||
|
|||||||
@ -124,7 +124,7 @@ def repost_entries():
|
|||||||
return
|
return
|
||||||
|
|
||||||
for d in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
|
for d in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
|
||||||
check_if_stock_and_account_balance_synced(today(), d.company)
|
check_if_stock_and_account_balance_synced(today(), d.name)
|
||||||
|
|
||||||
def get_repost_item_valuation_entries():
|
def get_repost_item_valuation_entries():
|
||||||
date = add_to_date(today(), hours=-12)
|
date = add_to_date(today(), hours=-12)
|
||||||
|
|||||||
@ -179,11 +179,15 @@ class TestStockEntry(unittest.TestCase):
|
|||||||
def test_material_transfer_gl_entry(self):
|
def test_material_transfer_gl_entry(self):
|
||||||
company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
|
company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
|
||||||
|
|
||||||
mtn = make_stock_entry(item_code="_Test Item", source="Stores - TCP1",
|
item_code = 'Hand Sanitizer - 001'
|
||||||
|
create_item(item_code =item_code, is_stock_item = 1,
|
||||||
|
is_purchase_item=1, opening_stock=1000, valuation_rate=10, company=company, warehouse="Stores - TCP1")
|
||||||
|
|
||||||
|
mtn = make_stock_entry(item_code=item_code, source="Stores - TCP1",
|
||||||
target="Finished Goods - TCP1", qty=45, company=company)
|
target="Finished Goods - TCP1", qty=45, company=company)
|
||||||
|
|
||||||
self.check_stock_ledger_entries("Stock Entry", mtn.name,
|
self.check_stock_ledger_entries("Stock Entry", mtn.name,
|
||||||
[["_Test Item", "Stores - TCP1", -45.0], ["_Test Item", "Finished Goods - TCP1", 45.0]])
|
[[item_code, "Stores - TCP1", -45.0], [item_code, "Finished Goods - TCP1", 45.0]])
|
||||||
|
|
||||||
source_warehouse_account = get_inventory_account(mtn.company, mtn.get("items")[0].s_warehouse)
|
source_warehouse_account = get_inventory_account(mtn.company, mtn.get("items")[0].s_warehouse)
|
||||||
|
|
||||||
|
|||||||
@ -48,44 +48,62 @@ frappe.ui.form.on("Issue", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function (frm) {
|
refresh: function(frm) {
|
||||||
if (frm.doc.status !== "Closed") {
|
|
||||||
if (frm.doc.service_level_agreement && frm.doc.agreement_status === "Ongoing") {
|
|
||||||
frappe.call({
|
|
||||||
"method": "frappe.client.get",
|
|
||||||
args: {
|
|
||||||
doctype: "Service Level Agreement",
|
|
||||||
name: frm.doc.service_level_agreement
|
|
||||||
},
|
|
||||||
callback: function(data) {
|
|
||||||
let statuses = data.message.pause_sla_on;
|
|
||||||
const hold_statuses = [];
|
|
||||||
$.each(statuses, (_i, entry) => {
|
|
||||||
hold_statuses.push(entry.status);
|
|
||||||
});
|
|
||||||
if (hold_statuses.includes(frm.doc.status)) {
|
|
||||||
frm.dashboard.clear_headline();
|
|
||||||
let message = {"indicator": "orange", "msg": __("SLA is on hold since {0}", [moment(frm.doc.on_hold_since).fromNow(true)])};
|
|
||||||
frm.dashboard.set_headline_alert(
|
|
||||||
'<div class="row">' +
|
|
||||||
'<div class="col-xs-12">' +
|
|
||||||
'<span class="indicator whitespace-nowrap '+ message.indicator +'"><span>'+ message.msg +'</span></span> ' +
|
|
||||||
'</div>' +
|
|
||||||
'</div>'
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
set_time_to_resolve_and_response(frm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
frm.add_custom_button(__("Close"), function () {
|
// alert messages
|
||||||
|
if (frm.doc.status !== "Closed" && frm.doc.service_level_agreement
|
||||||
|
&& frm.doc.agreement_status === "Ongoing") {
|
||||||
|
frappe.call({
|
||||||
|
"method": "frappe.client.get",
|
||||||
|
args: {
|
||||||
|
doctype: "Service Level Agreement",
|
||||||
|
name: frm.doc.service_level_agreement
|
||||||
|
},
|
||||||
|
callback: function(data) {
|
||||||
|
let statuses = data.message.pause_sla_on;
|
||||||
|
const hold_statuses = [];
|
||||||
|
$.each(statuses, (_i, entry) => {
|
||||||
|
hold_statuses.push(entry.status);
|
||||||
|
});
|
||||||
|
if (hold_statuses.includes(frm.doc.status)) {
|
||||||
|
frm.dashboard.clear_headline();
|
||||||
|
let message = { "indicator": "orange", "msg": __("SLA is on hold since {0}", [moment(frm.doc.on_hold_since).fromNow(true)]) };
|
||||||
|
frm.dashboard.set_headline_alert(
|
||||||
|
'<div class="row">' +
|
||||||
|
'<div class="col-xs-12">' +
|
||||||
|
'<span class="indicator whitespace-nowrap ' + message.indicator + '"><span>' + message.msg + '</span></span> ' +
|
||||||
|
'</div>' +
|
||||||
|
'</div>'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
set_time_to_resolve_and_response(frm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (frm.doc.service_level_agreement) {
|
||||||
|
frm.dashboard.clear_headline();
|
||||||
|
|
||||||
|
let agreement_status = (frm.doc.agreement_status == "Fulfilled") ?
|
||||||
|
{ "indicator": "green", "msg": "Service Level Agreement has been fulfilled" } :
|
||||||
|
{ "indicator": "red", "msg": "Service Level Agreement Failed" };
|
||||||
|
|
||||||
|
frm.dashboard.set_headline_alert(
|
||||||
|
'<div class="row">' +
|
||||||
|
'<div class="col-xs-12">' +
|
||||||
|
'<span class="indicator whitespace-nowrap ' + agreement_status.indicator + '"><span class="hidden-xs">' + agreement_status.msg + '</span></span> ' +
|
||||||
|
'</div>' +
|
||||||
|
'</div>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// buttons
|
||||||
|
if (frm.doc.status !== "Closed") {
|
||||||
|
frm.add_custom_button(__("Close"), function() {
|
||||||
frm.set_value("status", "Closed");
|
frm.set_value("status", "Closed");
|
||||||
frm.save();
|
frm.save();
|
||||||
});
|
});
|
||||||
|
|
||||||
frm.add_custom_button(__("Task"), function () {
|
frm.add_custom_button(__("Task"), function() {
|
||||||
frappe.model.open_mapped_doc({
|
frappe.model.open_mapped_doc({
|
||||||
method: "erpnext.support.doctype.issue.issue.make_task",
|
method: "erpnext.support.doctype.issue.issue.make_task",
|
||||||
frm: frm
|
frm: frm
|
||||||
@ -93,23 +111,7 @@ frappe.ui.form.on("Issue", {
|
|||||||
}, __("Create"));
|
}, __("Create"));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (frm.doc.service_level_agreement) {
|
frm.add_custom_button(__("Reopen"), function() {
|
||||||
frm.dashboard.clear_headline();
|
|
||||||
|
|
||||||
let agreement_status = (frm.doc.agreement_status == "Fulfilled") ?
|
|
||||||
{"indicator": "green", "msg": "Service Level Agreement has been fulfilled"} :
|
|
||||||
{"indicator": "red", "msg": "Service Level Agreement Failed"};
|
|
||||||
|
|
||||||
frm.dashboard.set_headline_alert(
|
|
||||||
'<div class="row">' +
|
|
||||||
'<div class="col-xs-12">' +
|
|
||||||
'<span class="indicator whitespace-nowrap '+ agreement_status.indicator +'"><span class="hidden-xs">'+ agreement_status.msg +'</span></span> ' +
|
|
||||||
'</div>' +
|
|
||||||
'</div>'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
frm.add_custom_button(__("Reopen"), function () {
|
|
||||||
frm.set_value("status", "Open");
|
frm.set_value("status", "Open");
|
||||||
frm.save();
|
frm.save();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import json
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe import utils
|
from frappe import utils
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import now_datetime, getdate, get_weekdays, add_to_date, get_time, get_datetime, time_diff_in_seconds
|
from frappe.utils import cint, now_datetime, getdate, get_weekdays, add_to_date, get_time, get_datetime, time_diff_in_seconds
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
from frappe.utils.user import is_website_user
|
from frappe.utils.user import is_website_user
|
||||||
@ -128,8 +128,8 @@ class Issue(Document):
|
|||||||
|
|
||||||
def update_agreement_status(self):
|
def update_agreement_status(self):
|
||||||
if self.service_level_agreement and self.agreement_status == "Ongoing":
|
if self.service_level_agreement and self.agreement_status == "Ongoing":
|
||||||
if frappe.db.get_value("Issue", self.name, "response_by_variance") < 0 or \
|
if cint(frappe.db.get_value("Issue", self.name, "response_by_variance")) < 0 or \
|
||||||
frappe.db.get_value("Issue", self.name, "resolution_by_variance") < 0:
|
cint(frappe.db.get_value("Issue", self.name, "resolution_by_variance")) < 0:
|
||||||
|
|
||||||
self.agreement_status = "Failed"
|
self.agreement_status = "Failed"
|
||||||
else:
|
else:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user