Merge branch 'develop' into UX

This commit is contained in:
Marica 2021-04-12 10:51:24 +05:30 committed by GitHub
commit 99522252c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 342 additions and 273 deletions

View File

@ -328,6 +328,21 @@ class TestPricingRule(unittest.TestCase):
self.assertEquals(item.discount_amount, 110)
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):
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
test_record = {
@ -560,6 +575,7 @@ def make_pricing_rule(**args):
"margin_rate_or_amount": args.margin_rate_or_amount or 0.0,
"condition": args.condition or '',
"priority": 1,
"discount_amount": args.discount_amount or 0.0,
"apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0
})

View File

@ -127,7 +127,6 @@
"write_off_cost_center",
"advances_section",
"allocate_advances_automatically",
"adjust_advance_taxes",
"get_advances",
"advances",
"payment_schedule_section",
@ -1326,13 +1325,6 @@
"label": "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",
"description": "Unrealized Profit / Loss account for intra-company transfers",
@ -1378,7 +1370,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
"modified": "2021-03-09 21:12:30.422084",
"modified": "2021-03-30 21:45:58.334107",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@ -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."""))
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:
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"))
def update_reference_in_journal_entry(d, jv_obj):

View File

@ -659,6 +659,7 @@ class AccountsController(TransactionBase):
'dr_or_cr': dr_or_cr,
'unadjusted_amount': flt(d.advance_amount),
'allocated_amount': flt(d.allocated_amount),
'precision': d.precision('advance_amount'),
'exchange_rate': (self.conversion_rate
if self.party_account_currency != self.company_currency else 1),
'grand_total': (self.base_grand_total

View File

@ -406,8 +406,7 @@ class StockController(AccountsController):
def set_rate_of_stock_uom(self):
if self.doctype in ["Purchase Receipt", "Purchase Invoice", "Purchase Order", "Sales Invoice", "Sales Order", "Delivery Note", "Quotation"]:
for d in self.get("items"):
if d.conversion_factor:
d.stock_uom_rate = d.rate / d.conversion_factor
d.stock_uom_rate = d.rate / (d.conversion_factor or 1)
def validate_internal_transfer(self):
if self.doctype in ('Sales Invoice', 'Delivery Note', 'Purchase Invoice', 'Purchase Receipt') \

View 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) {
// }
});

View 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"
}

View File

@ -1,9 +1,9 @@
# -*- 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
from __future__ import unicode_literals
import frappe
# import frappe
from frappe.model.document import Document
class LeadSource(Document):

View File

@ -1,12 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
# import frappe
import unittest
# test_records = frappe.get_test_records('Lead Source')
class TestLeadSource(unittest.TestCase):
pass

View File

@ -23,6 +23,7 @@
"rate_of_interest",
"is_secured_loan",
"disbursement_date",
"closure_date",
"disbursed_amount",
"column_break_11",
"maximum_loan_amount",
@ -348,12 +349,18 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"read_only": 1
},
{
"fieldname": "closure_date",
"fieldtype": "Date",
"label": "Closure Date",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2020-11-24 12:27:23.208240",
"modified": "2021-04-10 09:28:21.946972",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan",

View File

@ -523,33 +523,7 @@ class TestLoan(unittest.TestCase):
self.assertEqual(flt(repayment_entry.total_interest_paid, 0), flt(interest_amount, 0))
def test_penalty(self):
pledge = [{
"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()
loan, amounts = create_loan_scenario_for_penalty(self)
# 30 days - grace period
penalty_days = 30 - 4
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',
{'process_loan_interest_accrual': process, 'loan': loan.name}, 'penalty_amount')
self.assertEquals(loan.loan_amount, 1000000)
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):
pledge = [{
"loan_security": "Test Security 1",
@ -651,6 +645,32 @@ class TestLoan(unittest.TestCase):
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
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():
if not frappe.db.exists("Account", "Loans and Advances (Assets) - _TC"):

View File

@ -20,6 +20,10 @@
"cost_center",
"customer_details_section",
"bank_account",
"disbursement_references_section",
"reference_date",
"column_break_17",
"reference_number",
"amended_from"
],
"fields": [
@ -126,12 +130,31 @@
{
"fieldname": "column_break_8",
"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,
"is_submittable": 1,
"links": [],
"modified": "2020-11-06 10:04:30.882322",
"modified": "2021-04-10 10:03:41.502210",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Disbursement",

View File

@ -239,14 +239,16 @@
{
"fieldname": "total_penalty_paid",
"fieldtype": "Currency",
"hidden": 1,
"label": "Total Penalty Paid",
"options": "Company:company:default_currency"
"options": "Company:company:default_currency",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2021-04-05 13:45:19.137896",
"modified": "2021-04-10 10:00:31.859076",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Repayment",

View File

@ -75,7 +75,7 @@ class LoanRepayment(AccountsController):
"docstatus": 1, "against_loan": self.against_loan}, 'posting_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):
precision = cint(frappe.db.get_default("currency_precision")) or 2
@ -83,10 +83,6 @@ class LoanRepayment(AccountsController):
if not self.amount_paid:
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):
precision = cint(frappe.db.get_default("currency_precision")) or 2
if self.total_interest_paid > self.interest_payable:
@ -231,6 +227,14 @@ class LoanRepayment(AccountsController):
gle_map = []
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:
gle_map.append(
self.get_gl_dict({
@ -271,7 +275,7 @@ class LoanRepayment(AccountsController):
"debit_in_account_currency": self.amount_paid,
"against_voucher_type": "Loan",
"against_voucher": self.against_loan,
"remarks": _("Repayment against Loan: ") + self.against_loan,
"remarks": remarks,
"cost_center": self.cost_center,
"posting_date": getdate(self.posting_date)
})
@ -287,7 +291,7 @@ class LoanRepayment(AccountsController):
"credit_in_account_currency": self.amount_paid,
"against_voucher_type": "Loan",
"against_voucher": self.against_loan,
"remarks": _("Repayment against Loan: ") + self.against_loan,
"remarks": remarks,
"cost_center": self.cost_center,
"posting_date": getdate(self.posting_date)
})
@ -338,6 +342,18 @@ def get_accrued_interest_entries(against_loan, posting_date=None):
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
# 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)
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 = {}
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
due_date = add_days(entry.posting_date, 1)
no_of_late_days = date_diff(posting_date,
add_days(due_date, loan_type_details.grace_period_in_days)) + 1
due_date_after_grace_period = add_days(due_date, loan_type_details.grace_period_in_days)
# 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':
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["payable_principal_amount"] = flt(payable_principal_amount, 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["pending_accrual_entries"] = pending_accrual_entries
amounts["unaccrued_interest"] = flt(unaccrued_interest, precision)

View File

@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import get_datetime, flt
from frappe.utils import get_datetime, flt, getdate
import json
from six import iteritems
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
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()
def get_pledged_security_qty(loan):

View File

@ -763,4 +763,5 @@ erpnext.patches.v13_0.setup_gratuity_rule_for_india_and_uae
erpnext.patches.v13_0.setup_uae_vat_fields
execute:frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext')
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

View 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)

View File

@ -18,6 +18,7 @@ def execute():
for old_dt, new_dt in doctypes.items():
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.reload_doc('healthcare', 'doctype', frappe.scrub(new_dt))
frappe.delete_doc_if_exists('DocType', old_dt)
@ -36,6 +37,18 @@ def execute():
SET parentfield = %(parentfield)s
""".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
frappe.reload_doc('healthcare', 'doctype', 'lab_test')
if frappe.db.has_column('Lab Test', 'special_toggle'):

View File

@ -20,9 +20,11 @@ def execute():
frappe.clear_cache()
frappe.flags.warehouse_account_map = {}
company_list = []
data = frappe.db.sql('''
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
`tabStock Ledger Entry`
WHERE
@ -36,6 +38,9 @@ def execute():
total_sle = len(data)
i = 0
for d in data:
if d.company not in company_list:
company_list.append(d.company)
update_entries_after({
"item_code": d.item_code,
"warehouse": d.warehouse,
@ -53,8 +58,10 @@ def execute():
print("Reposting General Ledger Entries...")
for row in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
update_gl_entries_after(posting_date, posting_time, company=row.name)
if data:
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

View File

@ -8,6 +8,7 @@ def execute():
frappe.reload_doc("healthcare", "doctype", "Therapy Session")
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 Standard Document Type")
frappe.reload_doc("healthcare", "doctype", "Patient History Custom Document Type")

View File

@ -5,7 +5,7 @@ from frappe import _
def execute():
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'

View File

@ -33,12 +33,16 @@ class TestProject(unittest.TestCase):
def test_project_template_having_parent_child_tasks(self):
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.delete_doc('Project', project_name)
task1 = task_exists("Test Template Task Parent")
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")
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')
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(getdate(tasks[1].exp_end_date), calculate_end_date(project, 1, 3))

View File

@ -156,6 +156,13 @@ def make_custom_fields(update=True):
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 = [
dict(fieldname='invoice_copy', label='Invoice Copy',
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,
'insert_after': 'customer_name_in_arabic',
'translatable': 0,
}
}
]
si_ewaybill_fields = [
@ -438,7 +445,7 @@ def make_custom_fields(update=True):
'Purchase Order': 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,
'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,
'Tax Category': inter_state_gst_field,
'Item': [

View File

@ -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) {
}
});

View File

@ -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
}

View File

@ -279,11 +279,6 @@ erpnext.PointOfSale.Controller = class {
const item_row = frappe.model.get_doc(cdt, cdn);
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 event = {
field: fieldname,

View File

@ -27,7 +27,7 @@ def delete_company_transactions(company_name):
if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
"Party Account", "Employee", "Sales Taxes and Charges Template",
"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"):
delete_for_doctype(doctype, company_name)

View File

@ -494,7 +494,8 @@ def make_item_variant():
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):
item = frappe.new_doc("Item")
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.append("item_defaults", {
"default_warehouse": warehouse or '_Test Warehouse - _TC',
"company": "_Test Company"
"company": company or "_Test Company"
})
item.save()
else:

View File

@ -379,7 +379,6 @@ def create_stock_entry(pick_list):
else:
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.calculate_rate_and_amount()

View File

@ -124,7 +124,7 @@ def repost_entries():
return
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():
date = add_to_date(today(), hours=-12)

View File

@ -179,11 +179,15 @@ class TestStockEntry(unittest.TestCase):
def test_material_transfer_gl_entry(self):
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)
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)

View File

@ -48,44 +48,62 @@ frappe.ui.form.on("Issue", {
}
},
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);
}
}
});
}
refresh: function(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.save();
});
frm.add_custom_button(__("Task"), function () {
frm.add_custom_button(__("Task"), function() {
frappe.model.open_mapped_doc({
method: "erpnext.support.doctype.issue.issue.make_task",
frm: frm
@ -93,23 +111,7 @@ frappe.ui.form.on("Issue", {
}, __("Create"));
} 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>'
);
}
frm.add_custom_button(__("Reopen"), function () {
frm.add_custom_button(__("Reopen"), function() {
frm.set_value("status", "Open");
frm.save();
});

View File

@ -7,7 +7,7 @@ import json
from frappe import _
from frappe import utils
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 frappe.model.mapper import get_mapped_doc
from frappe.utils.user import is_website_user
@ -128,8 +128,8 @@ class Issue(Document):
def update_agreement_status(self):
if self.service_level_agreement and self.agreement_status == "Ongoing":
if frappe.db.get_value("Issue", self.name, "response_by_variance") < 0 or \
frappe.db.get_value("Issue", self.name, "resolution_by_variance") < 0:
if cint(frappe.db.get_value("Issue", self.name, "response_by_variance")) < 0 or \
cint(frappe.db.get_value("Issue", self.name, "resolution_by_variance")) < 0:
self.agreement_status = "Failed"
else: