Merge branch 'develop' of https://github.com/frappe/erpnext into stock_entry_conversion_factor

This commit is contained in:
Deepesh Garg 2020-10-08 16:23:34 +05:30
commit 8242da6310
143 changed files with 102636 additions and 15697 deletions

View File

@ -117,7 +117,9 @@ class Account(NestedSet):
for d in frappe.db.get_values('Account', filters=filters, fieldname=["company", "name"], as_dict=True): for d in frappe.db.get_values('Account', filters=filters, fieldname=["company", "name"], as_dict=True):
parent_acc_name_map[d["company"]] = d["name"] parent_acc_name_map[d["company"]] = d["name"]
if not parent_acc_name_map: return if not parent_acc_name_map: return
self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name) self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name)
def validate_group_or_ledger(self): def validate_group_or_ledger(self):
@ -289,10 +291,30 @@ def validate_account_number(name, account_number, company):
.format(account_number, account_with_same_number)) .format(account_number, account_with_same_number))
@frappe.whitelist() @frappe.whitelist()
def update_account_number(name, account_name, account_number=None): def update_account_number(name, account_name, account_number=None, from_descendant=False):
account = frappe.db.get_value("Account", name, "company", as_dict=True) account = frappe.db.get_value("Account", name, "company", as_dict=True)
if not account: return if not account: return
old_acc_name, old_acc_number = frappe.db.get_value('Account', name, \
["account_name", "account_number"])
# check if account exists in parent company
ancestors = get_ancestors_of("Company", account.company)
allow_independent_account_creation = frappe.get_value("Company", account.company, "allow_account_creation_against_child_company")
if ancestors and not allow_independent_account_creation:
for ancestor in ancestors:
if frappe.db.get_value("Account", {'account_name': old_acc_name, 'company': ancestor}, 'name'):
# same account in parent company exists
allow_child_account_creation = _("Allow Account Creation Against Child Company")
message = _("Account {0} exists in parent company {1}.").format(frappe.bold(old_acc_name), frappe.bold(ancestor))
message += "<br>" + _("Renaming it is only allowed via parent company {0}, \
to avoid mismatch.").format(frappe.bold(ancestor)) + "<br><br>"
message += _("To overrule this, enable '{0}' in company {1}").format(allow_child_account_creation, frappe.bold(account.company))
frappe.throw(message, title=_("Rename Not Allowed"))
validate_account_number(name, account_number, account.company) validate_account_number(name, account_number, account.company)
if account_number: if account_number:
frappe.db.set_value("Account", name, "account_number", account_number.strip()) frappe.db.set_value("Account", name, "account_number", account_number.strip())
@ -300,6 +322,12 @@ def update_account_number(name, account_name, account_number=None):
frappe.db.set_value("Account", name, "account_number", "") frappe.db.set_value("Account", name, "account_number", "")
frappe.db.set_value("Account", name, "account_name", account_name.strip()) frappe.db.set_value("Account", name, "account_name", account_name.strip())
if not from_descendant:
# Update and rename in child company accounts as well
descendants = get_descendants_of('Company', account.company)
if descendants:
sync_update_account_number_in_child(descendants, old_acc_name, account_name, account_number, old_acc_number)
new_name = get_account_autoname(account_number, account_name, account.company) new_name = get_account_autoname(account_number, account_name, account.company)
if name != new_name: if name != new_name:
frappe.rename_doc("Account", name, new_name, force=1) frappe.rename_doc("Account", name, new_name, force=1)
@ -330,3 +358,14 @@ def get_root_company(company):
# return the topmost company in the hierarchy # return the topmost company in the hierarchy
ancestors = get_ancestors_of('Company', company, "lft asc") ancestors = get_ancestors_of('Company', company, "lft asc")
return [ancestors[0]] if ancestors else [] return [ancestors[0]] if ancestors else []
def sync_update_account_number_in_child(descendants, old_acc_name, account_name, account_number=None, old_acc_number=None):
filters = {
"company": ["in", descendants],
"account_name": old_acc_name,
}
if old_acc_number:
filters["account_number"] = old_acc_number
for d in frappe.db.get_values('Account', filters=filters, fieldname=["company", "name"], as_dict=True):
update_account_number(d["name"], account_name, account_number, from_descendant=True)

View File

@ -5,8 +5,7 @@ from __future__ import unicode_literals
import unittest import unittest
import frappe import frappe
from erpnext.stock import get_warehouse_account, get_company_default_inventory_account from erpnext.stock import get_warehouse_account, get_company_default_inventory_account
from erpnext.accounts.doctype.account.account import update_account_number from erpnext.accounts.doctype.account.account import update_account_number, merge_account
from erpnext.accounts.doctype.account.account import merge_account
class TestAccount(unittest.TestCase): class TestAccount(unittest.TestCase):
def test_rename_account(self): def test_rename_account(self):
@ -99,7 +98,8 @@ class TestAccount(unittest.TestCase):
"Softwares - _TC", doc.is_group, doc.root_type, doc.company) "Softwares - _TC", doc.is_group, doc.root_type, doc.company)
def test_account_sync(self): def test_account_sync(self):
del frappe.local.flags["ignore_root_company_validation"] frappe.local.flags.pop("ignore_root_company_validation", None)
acc = frappe.new_doc("Account") acc = frappe.new_doc("Account")
acc.account_name = "Test Sync Account" acc.account_name = "Test Sync Account"
acc.parent_account = "Temporary Accounts - _TC3" acc.parent_account = "Temporary Accounts - _TC3"
@ -111,6 +111,55 @@ class TestAccount(unittest.TestCase):
self.assertEqual(acc_tc_4, "Test Sync Account - _TC4") self.assertEqual(acc_tc_4, "Test Sync Account - _TC4")
self.assertEqual(acc_tc_5, "Test Sync Account - _TC5") self.assertEqual(acc_tc_5, "Test Sync Account - _TC5")
def test_account_rename_sync(self):
frappe.local.flags.pop("ignore_root_company_validation", None)
acc = frappe.new_doc("Account")
acc.account_name = "Test Rename Account"
acc.parent_account = "Temporary Accounts - _TC3"
acc.company = "_Test Company 3"
acc.insert()
# Rename account in parent company
update_account_number(acc.name, "Test Rename Sync Account", "1234")
# Check if renamed in children
self.assertTrue(frappe.db.exists("Account", {'account_name': "Test Rename Sync Account", "company": "_Test Company 4", "account_number": "1234"}))
self.assertTrue(frappe.db.exists("Account", {'account_name': "Test Rename Sync Account", "company": "_Test Company 5", "account_number": "1234"}))
frappe.delete_doc("Account", "1234 - Test Rename Sync Account - _TC3")
frappe.delete_doc("Account", "1234 - Test Rename Sync Account - _TC4")
frappe.delete_doc("Account", "1234 - Test Rename Sync Account - _TC5")
def test_child_company_account_rename_sync(self):
frappe.local.flags.pop("ignore_root_company_validation", None)
acc = frappe.new_doc("Account")
acc.account_name = "Test Group Account"
acc.parent_account = "Temporary Accounts - _TC3"
acc.is_group = 1
acc.company = "_Test Company 3"
acc.insert()
self.assertTrue(frappe.db.exists("Account", {'account_name': "Test Group Account", "company": "_Test Company 4"}))
self.assertTrue(frappe.db.exists("Account", {'account_name': "Test Group Account", "company": "_Test Company 5"}))
# Try renaming child company account
acc_tc_5 = frappe.db.get_value('Account', {'account_name': "Test Group Account", "company": "_Test Company 5"})
self.assertRaises(frappe.ValidationError, update_account_number, acc_tc_5, "Test Modified Account")
# Rename child company account with allow_account_creation_against_child_company enabled
frappe.db.set_value("Company", "_Test Company 5", "allow_account_creation_against_child_company", 1)
update_account_number(acc_tc_5, "Test Modified Account")
self.assertTrue(frappe.db.exists("Account", {'name': "Test Modified Account - _TC5", "company": "_Test Company 5"}))
frappe.db.set_value("Company", "_Test Company 5", "allow_account_creation_against_child_company", 0)
to_delete = ["Test Group Account - _TC3", "Test Group Account - _TC4", "Test Modified Account - _TC5"]
for doc in to_delete:
frappe.delete_doc("Account", doc)
def _make_test_records(verbose): def _make_test_records(verbose):
from frappe.test_runner import make_test_objects from frappe.test_runner import make_test_objects

View File

@ -104,7 +104,7 @@
"default": "1", "default": "1",
"fieldname": "unlink_advance_payment_on_cancelation_of_order", "fieldname": "unlink_advance_payment_on_cancelation_of_order",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Unlink Advance Payment on Cancelation of Order" "label": "Unlink Advance Payment on Cancellation of Order"
}, },
{ {
"default": "1", "default": "1",
@ -223,9 +223,10 @@
], ],
"icon": "icon-cog", "icon": "icon-cog",
"idx": 1, "idx": 1,
"index_web_pages_for_search": 1,
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2020-08-03 20:13:26.043092", "modified": "2020-10-07 14:58:50.325577",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Accounts Settings", "name": "Accounts Settings",

View File

@ -12,9 +12,10 @@ frappe.ui.form.on('Payment Entry', {
setup: function(frm) { setup: function(frm) {
frm.set_query("paid_from", function() { frm.set_query("paid_from", function() {
frm.events.validate_company(frm);
var account_types = in_list(["Pay", "Internal Transfer"], frm.doc.payment_type) ? var account_types = in_list(["Pay", "Internal Transfer"], frm.doc.payment_type) ?
["Bank", "Cash"] : [frappe.boot.party_account_types[frm.doc.party_type]]; ["Bank", "Cash"] : [frappe.boot.party_account_types[frm.doc.party_type]];
return { return {
filters: { filters: {
"account_type": ["in", account_types], "account_type": ["in", account_types],
@ -23,13 +24,16 @@ frappe.ui.form.on('Payment Entry', {
} }
} }
}); });
frm.set_query("party_type", function() { frm.set_query("party_type", function() {
frm.events.validate_company(frm);
return{ return{
filters: { filters: {
"name": ["in", Object.keys(frappe.boot.party_account_types)], "name": ["in", Object.keys(frappe.boot.party_account_types)],
} }
} }
}); });
frm.set_query("party_bank_account", function() { frm.set_query("party_bank_account", function() {
return { return {
filters: { filters: {
@ -39,6 +43,7 @@ frappe.ui.form.on('Payment Entry', {
} }
} }
}); });
frm.set_query("bank_account", function() { frm.set_query("bank_account", function() {
return { return {
filters: { filters: {
@ -47,6 +52,7 @@ frappe.ui.form.on('Payment Entry', {
} }
} }
}); });
frm.set_query("contact_person", function() { frm.set_query("contact_person", function() {
if (frm.doc.party) { if (frm.doc.party) {
return { return {
@ -58,10 +64,12 @@ frappe.ui.form.on('Payment Entry', {
}; };
} }
}); });
frm.set_query("paid_to", function() { frm.set_query("paid_to", function() {
frm.events.validate_company(frm);
var account_types = in_list(["Receive", "Internal Transfer"], frm.doc.payment_type) ? var account_types = in_list(["Receive", "Internal Transfer"], frm.doc.payment_type) ?
["Bank", "Cash"] : [frappe.boot.party_account_types[frm.doc.party_type]]; ["Bank", "Cash"] : [frappe.boot.party_account_types[frm.doc.party_type]];
return { return {
filters: { filters: {
"account_type": ["in", account_types], "account_type": ["in", account_types],
@ -150,6 +158,12 @@ frappe.ui.form.on('Payment Entry', {
frm.events.show_general_ledger(frm); frm.events.show_general_ledger(frm);
}, },
validate_company: (frm) => {
if (!frm.doc.company){
frappe.throw({message:__("Please select a Company first."), title: __("Mandatory")});
}
},
company: function(frm) { company: function(frm) {
frm.events.hide_unhide_fields(frm); frm.events.hide_unhide_fields(frm);
frm.events.set_dynamic_labels(frm); frm.events.set_dynamic_labels(frm);

View File

@ -285,6 +285,71 @@ class TestPOSInvoice(unittest.TestCase):
after_redeem_lp_details = get_loyalty_program_details_with_points(inv.customer, company=inv.company, loyalty_program=inv.loyalty_program) after_redeem_lp_details = get_loyalty_program_details_with_points(inv.customer, company=inv.company, loyalty_program=inv.loyalty_program)
self.assertEqual(after_redeem_lp_details.loyalty_points, 9) self.assertEqual(after_redeem_lp_details.loyalty_points, 9)
def test_merging_into_sales_invoice_with_discount(self):
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import merge_pos_invoices
frappe.db.sql("delete from `tabPOS Invoice`")
test_user, pos_profile = init_user_and_profile()
pos_inv = create_pos_invoice(rate=300, additional_discount_percentage=10, do_not_submit=1)
pos_inv.append('payments', {
'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 300
})
pos_inv.submit()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append('payments', {
'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 3200
})
pos_inv2.submit()
merge_pos_invoices()
pos_inv.load_from_db()
sales_invoice = frappe.get_doc("Sales Invoice", pos_inv.consolidated_invoice)
self.assertEqual(sales_invoice.grand_total, 3500)
def test_merging_into_sales_invoice_with_discount_and_inclusive_tax(self):
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import merge_pos_invoices
frappe.db.sql("delete from `tabPOS Invoice`")
test_user, pos_profile = init_user_and_profile()
pos_inv = create_pos_invoice(rate=300, do_not_submit=1)
pos_inv.append('payments', {
'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 300
})
pos_inv.append('taxes', {
"charge_type": "On Net Total",
"account_head": "_Test Account Service Tax - _TC",
"cost_center": "_Test Cost Center - _TC",
"description": "Service Tax",
"rate": 14,
'included_in_print_rate': 1
})
pos_inv.submit()
pos_inv2 = create_pos_invoice(rate=300, qty=2, do_not_submit=1)
pos_inv2.additional_discount_percentage = 10
pos_inv2.append('payments', {
'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 540
})
pos_inv2.append('taxes', {
"charge_type": "On Net Total",
"account_head": "_Test Account Service Tax - _TC",
"cost_center": "_Test Cost Center - _TC",
"description": "Service Tax",
"rate": 14,
'included_in_print_rate': 1
})
pos_inv2.submit()
merge_pos_invoices()
pos_inv.load_from_db()
sales_invoice = frappe.get_doc("Sales Invoice", pos_inv.consolidated_invoice)
self.assertEqual(sales_invoice.rounded_total, 840)
def create_pos_invoice(**args): def create_pos_invoice(**args):
args = frappe._dict(args) args = frappe._dict(args)
@ -294,6 +359,7 @@ def create_pos_invoice(**args):
pos_profile.save() pos_profile.save()
pos_inv = frappe.new_doc("POS Invoice") pos_inv = frappe.new_doc("POS Invoice")
pos_inv.update(args)
pos_inv.update_stock = 1 pos_inv.update_stock = 1
pos_inv.is_pos = 1 pos_inv.is_pos = 1
pos_inv.pos_profile = args.pos_profile or pos_profile.name pos_inv.pos_profile = args.pos_profile or pos_profile.name

View File

@ -96,17 +96,28 @@ class POSInvoiceMergeLog(Document):
loyalty_amount_sum += doc.loyalty_amount loyalty_amount_sum += doc.loyalty_amount
for item in doc.get('items'): for item in doc.get('items'):
items.append(item) found = False
for i in items:
if (i.item_code == item.item_code and not i.serial_no and not i.batch_no and
i.uom == item.uom and i.net_rate == item.net_rate):
found = True
i.qty = i.qty + item.qty
if not found:
item.rate = item.net_rate
items.append(item)
for tax in doc.get('taxes'): for tax in doc.get('taxes'):
found = False found = False
for t in taxes: for t in taxes:
if t.account_head == tax.account_head and t.cost_center == tax.cost_center and t.rate == tax.rate: if t.account_head == tax.account_head and t.cost_center == tax.cost_center:
t.tax_amount = flt(t.tax_amount) + flt(tax.tax_amount) t.tax_amount = flt(t.tax_amount) + flt(tax.tax_amount_after_discount_amount)
t.base_tax_amount = flt(t.base_tax_amount) + flt(tax.base_tax_amount) t.base_tax_amount = flt(t.base_tax_amount) + flt(tax.base_tax_amount_after_discount_amount)
found = True found = True
if not found: if not found:
tax.charge_type = 'Actual' tax.charge_type = 'Actual'
tax.included_in_print_rate = 0
tax.tax_amount = tax.tax_amount_after_discount_amount
tax.base_tax_amount = tax.base_tax_amount_after_discount_amount
taxes.append(tax) taxes.append(tax)
for payment in doc.get('payments'): for payment in doc.get('payments'):
@ -127,6 +138,8 @@ class POSInvoiceMergeLog(Document):
invoice.set('items', items) invoice.set('items', items)
invoice.set('payments', payments) invoice.set('payments', payments)
invoice.set('taxes', taxes) invoice.set('taxes', taxes)
invoice.additional_discount_percentage = 0
invoice.discount_amount = 0.0
return invoice return invoice

View File

@ -6,6 +6,8 @@ from __future__ import unicode_literals
import frappe import frappe
import unittest import unittest
from erpnext.accounts.doctype.tax_rule.tax_rule import IncorrectCustomerGroup, IncorrectSupplierType, ConflictingTaxRule, get_tax_template from erpnext.accounts.doctype.tax_rule.tax_rule import IncorrectCustomerGroup, IncorrectSupplierType, ConflictingTaxRule, get_tax_template
from erpnext.crm.doctype.opportunity.test_opportunity import make_opportunity
from erpnext.crm.doctype.opportunity.opportunity import make_quotation
test_records = frappe.get_test_records('Tax Rule') test_records = frappe.get_test_records('Tax Rule')
@ -144,6 +146,23 @@ class TestTaxRule(unittest.TestCase):
self.assertEqual(get_tax_template("2015-01-01", {"customer":"_Test Customer", "billing_city": "Test City 1"}), self.assertEqual(get_tax_template("2015-01-01", {"customer":"_Test Customer", "billing_city": "Test City 1"}),
"_Test Sales Taxes and Charges Template 1 - _TC") "_Test Sales Taxes and Charges Template 1 - _TC")
def test_taxes_fetch_via_tax_rule(self):
make_tax_rule(customer= "_Test Customer", billing_city = "_Test City",
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", save=1)
# create opportunity for customer
opportunity = make_opportunity(with_items=1)
# make quotation from opportunity
quotation = make_quotation(opportunity.name)
quotation.save()
self.assertEqual(quotation.taxes_and_charges, "_Test Sales Taxes and Charges Template - _TC")
# Check if accounts heads and rate fetched are also fetched from tax template or not
self.assertTrue(len(quotation.taxes) > 0)
def make_tax_rule(**args): def make_tax_rule(**args):
args = frappe._dict(args) args = frappe._dict(args)

View File

@ -320,7 +320,6 @@ def make_reverse_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
entry['remarks'] = "On cancellation of " + entry['voucher_no'] entry['remarks'] = "On cancellation of " + entry['voucher_no']
entry['is_cancelled'] = 1 entry['is_cancelled'] = 1
entry['posting_date'] = today()
if entry['debit'] or entry['credit']: if entry['debit'] or entry['credit']:
make_entry(entry, adv_adj, "Yes") make_entry(entry, adv_adj, "Yes")

View File

@ -268,9 +268,9 @@ class GrossProfitGenerator(object):
def get_last_purchase_rate(self, item_code, row): def get_last_purchase_rate(self, item_code, row):
condition = '' condition = ''
if row.project: if row.project:
condition += " AND a.project='%s'" % (row.project) condition += " AND a.project=%s" % (frappe.db.escape(row.project))
elif row.cost_center: elif row.cost_center:
condition += " AND a.cost_center='%s'" % (row.cost_center) condition += " AND a.cost_center=%s" % (frappe.db.escape(row.cost_center))
if self.filters.to_date: if self.filters.to_date:
condition += " AND modified='%s'" % (self.filters.to_date) condition += " AND modified='%s'" % (self.filters.to_date)

View File

@ -32,12 +32,12 @@ def execute(filters=None):
chart = get_chart_data(filters, columns, income, expense, net_profit_loss) chart = get_chart_data(filters, columns, income, expense, net_profit_loss)
default_currency = frappe.get_cached_value('Company', filters.company, "default_currency") currency = filters.presentation_currency or frappe.get_cached_value('Company', filters.company, "default_currency")
report_summary = get_report_summary(period_list, filters.periodicity, income, expense, net_profit_loss, default_currency) report_summary = get_report_summary(period_list, filters.periodicity, income, expense, net_profit_loss, currency)
return columns, data, None, chart, report_summary return columns, data, None, chart, report_summary
def get_report_summary(period_list, periodicity, income, expense, net_profit_loss, default_currency, consolidated=False): def get_report_summary(period_list, periodicity, income, expense, net_profit_loss, currency, consolidated=False):
net_income, net_expense, net_profit = 0.0, 0.0, 0.0 net_income, net_expense, net_profit = 0.0, 0.0, 0.0
for period in period_list: for period in period_list:
@ -64,19 +64,19 @@ def get_report_summary(period_list, periodicity, income, expense, net_profit_los
"indicator": "Green" if net_profit > 0 else "Red", "indicator": "Green" if net_profit > 0 else "Red",
"label": profit_label, "label": profit_label,
"datatype": "Currency", "datatype": "Currency",
"currency": net_profit_loss.get("currency") if net_profit_loss else default_currency "currency": currency
}, },
{ {
"value": net_income, "value": net_income,
"label": income_label, "label": income_label,
"datatype": "Currency", "datatype": "Currency",
"currency": income[-1].get('currency') if income else default_currency "currency": currency
}, },
{ {
"value": net_expense, "value": net_expense,
"label": expense_label, "label": expense_label,
"datatype": "Currency", "datatype": "Currency",
"currency": expense[-1].get('currency') if expense else default_currency "currency": currency
} }
] ]
@ -143,4 +143,4 @@ def get_chart_data(filters, columns, income, expense, net_profit_loss):
chart["fieldtype"] = "Currency" chart["fieldtype"] = "Currency"
return chart return chart

View File

@ -72,6 +72,12 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"fieldtype": "Link", "fieldtype": "Link",
"options": "Finance Book", "options": "Finance Book",
}, },
{
"fieldname": "presentation_currency",
"label": __("Currency"),
"fieldtype": "Select",
"options": erpnext.get_presentation_currency_list()
},
{ {
"fieldname": "with_period_closing_entry", "fieldname": "with_period_closing_entry",
"label": __("Period Closing Entry"), "label": __("Period Closing Entry"),

View File

@ -56,7 +56,7 @@ def get_data(filters):
accounts = frappe.db.sql("""select name, account_number, parent_account, account_name, root_type, report_type, lft, rgt accounts = frappe.db.sql("""select name, account_number, parent_account, account_name, root_type, report_type, lft, rgt
from `tabAccount` where company=%s order by lft""", filters.company, as_dict=True) from `tabAccount` where company=%s order by lft""", filters.company, as_dict=True)
company_currency = erpnext.get_company_currency(filters.company) company_currency = filters.presentation_currency or erpnext.get_company_currency(filters.company)
if not accounts: if not accounts:
return None return None

View File

@ -683,6 +683,7 @@ def get_outstanding_invoices(party_type, party, account, condition=None, filters
where where
party_type = %(party_type)s and party = %(party)s party_type = %(party_type)s and party = %(party)s
and account = %(account)s and {dr_or_cr} > 0 and account = %(account)s and {dr_or_cr} > 0
and is_cancelled=0
{condition} {condition}
and ((voucher_type = 'Journal Entry' and ((voucher_type = 'Journal Entry'
and (against_voucher = '' or against_voucher is null)) and (against_voucher = '' or against_voucher is null))
@ -705,6 +706,7 @@ def get_outstanding_invoices(party_type, party, account, condition=None, filters
and account = %(account)s and account = %(account)s
and {payment_dr_or_cr} > 0 and {payment_dr_or_cr} > 0
and against_voucher is not null and against_voucher != '' and against_voucher is not null and against_voucher != ''
and is_cancelled=0
group by against_voucher_type, against_voucher group by against_voucher_type, against_voucher
""".format(payment_dr_or_cr=payment_dr_or_cr), { """.format(payment_dr_or_cr=payment_dr_or_cr), {
"party_type": party_type, "party_type": party_type,

View File

@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe, erpnext, math, json import frappe, erpnext, math, json
from frappe import _ from frappe import _
from six import string_types from six import string_types
from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff, month_diff, add_days, get_last_day from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff, month_diff, add_days, get_last_day, get_datetime
from frappe.model.document import Document from frappe.model.document import Document
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
from erpnext.assets.doctype.asset.depreciation \ from erpnext.assets.doctype.asset.depreciation \
@ -140,6 +140,10 @@ class Asset(AccountsController):
def make_asset_movement(self): def make_asset_movement(self):
reference_doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice' reference_doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice'
reference_docname = self.purchase_receipt or self.purchase_invoice reference_docname = self.purchase_receipt or self.purchase_invoice
transaction_date = getdate(self.purchase_date)
if reference_docname:
posting_date, posting_time = frappe.db.get_value(reference_doctype, reference_docname, ["posting_date", "posting_time"])
transaction_date = get_datetime("{} {}".format(posting_date, posting_time))
assets = [{ assets = [{
'asset': self.name, 'asset': self.name,
'asset_name': self.asset_name, 'asset_name': self.asset_name,
@ -151,7 +155,7 @@ class Asset(AccountsController):
'assets': assets, 'assets': assets,
'purpose': 'Receipt', 'purpose': 'Receipt',
'company': self.company, 'company': self.company,
'transaction_date': getdate(self.purchase_date), 'transaction_date': transaction_date,
'reference_doctype': reference_doctype, 'reference_doctype': reference_doctype,
'reference_name': reference_docname 'reference_name': reference_docname
}).insert() }).insert()

View File

@ -1084,7 +1084,7 @@
"idx": 105, "idx": 105,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-09-14 14:36:12.418690", "modified": "2020-10-07 14:31:57.661221",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order", "name": "Purchase Order",
@ -1130,11 +1130,11 @@
"write": 1 "write": 1
} }
], ],
"search_fields": "status, transaction_date, supplier,grand_total", "search_fields": "status, transaction_date, supplier, grand_total",
"show_name_in_global_search": 1, "show_name_in_global_search": 1,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"timeline_field": "supplier", "timeline_field": "supplier",
"title_field": "supplier", "title_field": "supplier_name",
"track_changes": 1 "track_changes": 1
} }

View File

@ -178,6 +178,7 @@ def make_all_scorecards(docname):
period_card = make_supplier_scorecard(docname, None) period_card = make_supplier_scorecard(docname, None)
period_card.start_date = start_date period_card.start_date = start_date
period_card.end_date = end_date period_card.end_date = end_date
period_card.insert(ignore_permissions=True)
period_card.submit() period_card.submit()
scp_count = scp_count + 1 scp_count = scp_count + 1
if start_date < first_start_date: if start_date < first_start_date:

View File

@ -106,7 +106,7 @@ def make_supplier_scorecard(source_name, target_doc=None):
"doctype": "Supplier Scorecard Scoring Criteria", "doctype": "Supplier Scorecard Scoring Criteria",
"postprocess": update_criteria_fields, "postprocess": update_criteria_fields,
} }
}, target_doc, post_process) }, target_doc, post_process, ignore_permissions=True)
return doc return doc

View File

@ -1242,7 +1242,7 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
try: try:
doc.check_permission(perm_type) doc.check_permission(perm_type)
except frappe.PermissionError: except frappe.PermissionError:
actions = { 'create': 'add', 'write': 'update', 'cancel': 'remove' } actions = { 'create': 'add', 'write': 'update'}
frappe.throw(_("You do not have permissions to {} items in a {}.") frappe.throw(_("You do not have permissions to {} items in a {}.")
.format(actions[perm_type], parent_doctype), title=_("Insufficient Permissions")) .format(actions[perm_type], parent_doctype), title=_("Insufficient Permissions"))
@ -1264,7 +1264,10 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
transitions.append(transition.as_dict()) transitions.append(transition.as_dict())
if not transitions: if not transitions:
frappe.throw(_("You do not have workflow access to update this document."), title=_("Insufficient Workflow Permissions")) frappe.throw(
_("You are not allowed to update as per the conditions set in {} Workflow.").format(get_link_to_form("Workflow", workflow)),
title=_("Insufficient Permissions")
)
def get_new_child_item(item_row): def get_new_child_item(item_row):
new_child_function = set_sales_order_defaults if parent_doctype == "Sales Order" else set_purchase_order_defaults new_child_function = set_sales_order_defaults if parent_doctype == "Sales Order" else set_purchase_order_defaults
@ -1282,7 +1285,7 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
sales_doctypes = ['Sales Order', 'Sales Invoice', 'Delivery Note', 'Quotation'] sales_doctypes = ['Sales Order', 'Sales Invoice', 'Delivery Note', 'Quotation']
parent = frappe.get_doc(parent_doctype, parent_doctype_name) parent = frappe.get_doc(parent_doctype, parent_doctype_name)
check_doc_permissions(parent, 'cancel') check_doc_permissions(parent, 'write')
validate_and_delete_children(parent, data) validate_and_delete_children(parent, data)
for d in data: for d in data:

View File

@ -368,13 +368,17 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
searchfields = meta.get_search_fields() searchfields = meta.get_search_fields()
search_columns = '' search_columns = ''
search_cond = ''
if searchfields: if searchfields:
search_columns = ", " + ", ".join(searchfields) search_columns = ", " + ", ".join(searchfields)
search_cond = " or " + " or ".join([field + " like %(txt)s" for field in searchfields])
if args.get('warehouse'): if args.get('warehouse'):
searchfields = ['batch.' + field for field in searchfields] searchfields = ['batch.' + field for field in searchfields]
if searchfields: if searchfields:
search_columns = ", " + ", ".join(searchfields) search_columns = ", " + ", ".join(searchfields)
search_cond = " or " + " or ".join([field + " like %(txt)s" for field in searchfields])
batch_nos = frappe.db.sql("""select sle.batch_no, round(sum(sle.actual_qty),2), sle.stock_uom, batch_nos = frappe.db.sql("""select sle.batch_no, round(sum(sle.actual_qty),2), sle.stock_uom,
concat('MFG-',batch.manufacturing_date), concat('EXP-',batch.expiry_date) concat('MFG-',batch.manufacturing_date), concat('EXP-',batch.expiry_date)
@ -387,7 +391,8 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
and sle.warehouse = %(warehouse)s and sle.warehouse = %(warehouse)s
and (sle.batch_no like %(txt)s and (sle.batch_no like %(txt)s
or batch.expiry_date like %(txt)s or batch.expiry_date like %(txt)s
or batch.manufacturing_date like %(txt)s) or batch.manufacturing_date like %(txt)s
{search_cond})
and batch.docstatus < 2 and batch.docstatus < 2
{cond} {cond}
{match_conditions} {match_conditions}
@ -397,7 +402,8 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
search_columns = search_columns, search_columns = search_columns,
cond=cond, cond=cond,
match_conditions=get_match_cond(doctype), match_conditions=get_match_cond(doctype),
having_clause = having_clause having_clause = having_clause,
search_cond = search_cond
), args) ), args)
return batch_nos return batch_nos
@ -409,12 +415,15 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
and item = %(item_code)s and item = %(item_code)s
and (name like %(txt)s and (name like %(txt)s
or expiry_date like %(txt)s or expiry_date like %(txt)s
or manufacturing_date like %(txt)s) or manufacturing_date like %(txt)s
{search_cond})
and docstatus < 2 and docstatus < 2
{0} {0}
{match_conditions} {match_conditions}
order by expiry_date, name desc order by expiry_date, name desc
limit %(start)s, %(page_len)s""".format(cond, search_columns = search_columns, match_conditions=get_match_cond(doctype)), args) limit %(start)s, %(page_len)s""".format(cond, search_columns = search_columns,
search_cond = search_cond, match_conditions=get_match_cond(doctype)), args)
@frappe.whitelist() @frappe.whitelist()

View File

@ -10,6 +10,7 @@ from erpnext.stock.utils import get_incoming_rate
from erpnext.stock.get_item_details import get_conversion_factor from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.stock.doctype.item.item import set_item_default from erpnext.stock.doctype.item.item import set_item_default
from frappe.contacts.doctype.address.address import get_address_display from frappe.contacts.doctype.address.address import get_address_display
from erpnext.controllers.accounts_controller import get_taxes_and_charges
from erpnext.controllers.stock_controller import StockController from erpnext.controllers.stock_controller import StockController
@ -53,10 +54,10 @@ class SellingController(StockController):
super(SellingController, self).set_missing_values(for_validate) super(SellingController, self).set_missing_values(for_validate)
# set contact and address details for customer, if they are not mentioned # set contact and address details for customer, if they are not mentioned
self.set_missing_lead_customer_details() self.set_missing_lead_customer_details(for_validate=for_validate)
self.set_price_list_and_item_details(for_validate=for_validate) self.set_price_list_and_item_details(for_validate=for_validate)
def set_missing_lead_customer_details(self): def set_missing_lead_customer_details(self, for_validate=False):
customer, lead = None, None customer, lead = None, None
if getattr(self, "customer", None): if getattr(self, "customer", None):
customer = self.customer customer = self.customer
@ -94,6 +95,11 @@ class SellingController(StockController):
posting_date=self.get('transaction_date') or self.get('posting_date'), posting_date=self.get('transaction_date') or self.get('posting_date'),
company=self.company)) company=self.company))
if self.get('taxes_and_charges') and not self.get('taxes') and not for_validate:
taxes = get_taxes_and_charges('Sales Taxes and Charges Template', self.taxes_and_charges)
for tax in taxes:
self.append('taxes', tax)
def set_price_list_and_item_details(self, for_validate=False): def set_price_list_and_item_details(self, for_validate=False):
self.set_price_list_currency("Selling") self.set_price_list_currency("Selling")
self.set_missing_item_details(for_validate=for_validate) self.set_missing_item_details(for_validate=for_validate)

View File

@ -25,7 +25,7 @@ def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_p
if not filters: filters = [] if not filters: filters = []
if doctype in ['Supplier Quotation', 'Purchase Invoice']: if doctype in ['Supplier Quotation', 'Purchase Invoice', 'Quotation']:
filters.append((doctype, 'docstatus', '<', 2)) filters.append((doctype, 'docstatus', '<', 2))
else: else:
filters.append((doctype, 'docstatus', '=', 1)) filters.append((doctype, 'docstatus', '=', 1))

View File

@ -8,7 +8,7 @@
{ {
"hidden": 0, "hidden": 0,
"label": "Reports", "label": "Reports",
"links": "[\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Details\",\n \"name\": \"Lead Details\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"icon\": \"fa fa-bar-chart\",\n \"label\": \"Sales Funnel\",\n \"name\": \"sales-funnel\",\n \"onboard\": 1,\n \"type\": \"page\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Prospects Engaged But Not Converted\",\n \"name\": \"Prospects Engaged But Not Converted\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Opportunity\"\n ],\n \"doctype\": \"Opportunity\",\n \"is_query_report\": true,\n \"label\": \"Minutes to First Response for Opportunity\",\n \"name\": \"Minutes to First Response for Opportunity\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Inactive Customers\",\n \"name\": \"Inactive Customers\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Campaign Efficiency\",\n \"name\": \"Campaign Efficiency\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Owner Efficiency\",\n \"name\": \"Lead Owner Efficiency\",\n \"type\": \"report\"\n }\n]" "links": "[\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Details\",\n \"name\": \"Lead Details\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"icon\": \"fa fa-bar-chart\",\n \"label\": \"Sales Funnel\",\n \"name\": \"sales-funnel\",\n \"onboard\": 1,\n \"type\": \"page\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Prospects Engaged But Not Converted\",\n \"name\": \"Prospects Engaged But Not Converted\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Opportunity\"\n ],\n \"doctype\": \"Opportunity\",\n \"is_query_report\": true,\n \"label\": \"First Response Time for Opportunity\",\n \"name\": \"First Response Time for Opportunity\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Inactive Customers\",\n \"name\": \"Inactive Customers\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Campaign Efficiency\",\n \"name\": \"Campaign Efficiency\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Owner Efficiency\",\n \"name\": \"Lead Owner Efficiency\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,
@ -42,7 +42,7 @@
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "CRM", "label": "CRM",
"modified": "2020-05-28 13:33:52.906750", "modified": "2020-08-11 18:55:18.238900",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "CRM", "module": "CRM",
"name": "CRM", "name": "CRM",

View File

@ -27,9 +27,6 @@ class Lead(SellingController):
def after_insert(self): def after_insert(self):
self.update_links() self.update_links()
# after the address and contact are created, flush the field values
# to avoid inconsistent reporting in case the documents are changed
self.flush_address_and_contact_fields()
def validate(self): def validate(self):
self.set_lead_name() self.set_lead_name()
@ -210,14 +207,6 @@ class Lead(SellingController):
}) })
self.contact_doc.save() self.contact_doc.save()
def flush_address_and_contact_fields(self):
fields = ['address_type', 'address_line1', 'address_line2', 'address_title',
'city', 'county', 'country', 'fax', 'pincode', 'state']
for field in fields:
self.set(field, None)
@frappe.whitelist() @frappe.whitelist()
def make_customer(source_name, target_doc=None): def make_customer(source_name, target_doc=None):
return _make_customer(source_name, target_doc) return _make_customer(source_name, target_doc)
@ -376,3 +365,8 @@ def get_lead_with_phone_number(number):
lead = leads[0].name if leads else None lead = leads[0].name if leads else None
return lead return lead
def daily_open_lead():
leads = frappe.get_all("Lead", filters = [["contact_date", "Between", [nowdate(), nowdate()]]])
for lead in leads:
frappe.db.set_value("Lead", lead.name, "status", "Open")

View File

@ -24,7 +24,7 @@
"converted_by", "converted_by",
"sales_stage", "sales_stage",
"order_lost_reason", "order_lost_reason",
"mins_to_first_response", "first_response_time",
"expected_closing", "expected_closing",
"next_contact", "next_contact",
"contact_by", "contact_by",
@ -152,13 +152,6 @@
"no_copy": 1, "no_copy": 1,
"read_only": 1 "read_only": 1
}, },
{
"bold": 1,
"fieldname": "mins_to_first_response",
"fieldtype": "Float",
"label": "Mins to first response",
"read_only": 1
},
{ {
"fieldname": "expected_closing", "fieldname": "expected_closing",
"fieldtype": "Date", "fieldtype": "Date",
@ -419,12 +412,19 @@
"fieldtype": "Link", "fieldtype": "Link",
"label": "Converted By", "label": "Converted By",
"options": "User" "options": "User"
},
{
"bold": 1,
"fieldname": "first_response_time",
"fieldtype": "Duration",
"label": "First Response Time",
"read_only": 1
} }
], ],
"icon": "fa fa-info-sign", "icon": "fa fa-info-sign",
"idx": 195, "idx": 195,
"links": [], "links": [],
"modified": "2020-08-11 17:34:35.066961", "modified": "2020-08-12 17:34:35.066961",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "CRM", "module": "CRM",
"name": "Opportunity", "name": "Opportunity",

View File

@ -1,33 +1,44 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Minutes to First Response for Opportunity"] = { frappe.query_reports["First Response Time for Opportunity"] = {
"filters": [ "filters": [
{ {
"fieldname": "from_date", "fieldname": "from_date",
"label": __("From Date"), "label": __("From Date"),
"fieldtype": "Date", "fieldtype": "Date",
'reqd': 1, "reqd": 1,
"default": frappe.datetime.add_days(frappe.datetime.nowdate(), -30) "default": frappe.datetime.add_days(frappe.datetime.nowdate(), -30)
}, },
{ {
"fieldname": "to_date", "fieldname": "to_date",
"label": __("To Date"), "label": __("To Date"),
"fieldtype": "Date", "fieldtype": "Date",
'reqd': 1, "reqd": 1,
"default": frappe.datetime.nowdate() "default": frappe.datetime.nowdate()
}, },
], ],
get_chart_data: function (columns, result) { get_chart_data: function (_columns, result) {
return { return {
data: { data: {
labels: result.map(d => d[0]), labels: result.map(d => d[0]),
datasets: [{ datasets: [{
name: 'Mins to first response', name: "First Response Time",
values: result.map(d => d[1]) values: result.map(d => d[1])
}] }]
}, },
type: 'line', type: "line",
tooltipOptions: {
formatTooltipY: d => {
let duration_options = {
hide_days: 0,
hide_seconds: 0
};
value = frappe.utils.get_formatted_duration(d, duration_options);
return value;
}
}
} }
} }
} };

View File

@ -0,0 +1,28 @@
{
"add_total_row": 0,
"creation": "2020-08-10 18:34:19.083872",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Test 2",
"modified": "2020-08-10 18:34:19.083872",
"modified_by": "Administrator",
"module": "CRM",
"name": "First Response Time for Opportunity",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Opportunity",
"report_name": "First Response Time for Opportunity",
"report_type": "Script Report",
"roles": [
{
"role": "Sales User"
},
{
"role": "Sales Manager"
}
]
}

View File

@ -0,0 +1,35 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
def execute(filters=None):
columns = [
{
'fieldname': 'creation_date',
'label': 'Date',
'fieldtype': 'Date',
'width': 300
},
{
'fieldname': 'first_response_time',
'fieldtype': 'Duration',
'label': 'First Response Time',
'width': 300
},
]
data = frappe.db.sql('''
SELECT
date(creation) as creation_date,
avg(first_response_time) as avg_response_time
FROM tabOpportunity
WHERE
date(creation) between %s and %s
and first_response_time > 0
GROUP BY creation_date
ORDER BY creation_date desc
''', (filters.from_date, filters.to_date))
return columns, data

View File

@ -1,26 +0,0 @@
{
"add_total_row": 0,
"apply_user_permissions": 0,
"creation": "2016-06-17 11:28:25.867258",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 2,
"is_standard": "Yes",
"modified": "2017-02-24 20:06:08.801109",
"modified_by": "Administrator",
"module": "CRM",
"name": "Minutes to First Response for Opportunity",
"owner": "Administrator",
"ref_doctype": "Opportunity",
"report_name": "Minutes to First Response for Opportunity",
"report_type": "Script Report",
"roles": [
{
"role": "Sales User"
},
{
"role": "Sales Manager"
}
]
}

View File

@ -1,28 +0,0 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
def execute(filters=None):
columns = [
{
'fieldname': 'creation_date',
'label': 'Date',
'fieldtype': 'Date'
},
{
'fieldname': 'mins',
'fieldtype': 'Float',
'label': 'Mins to First Response'
},
]
data = frappe.db.sql('''select date(creation) as creation_date,
avg(mins_to_first_response) as mins
from tabOpportunity
where date(creation) between %s and %s
and mins_to_first_response > 0
group by creation_date order by creation_date desc''', (filters.from_date, filters.to_date))
return columns, data

View File

@ -13,7 +13,7 @@
"fields": [ "fields": [
{ {
"fieldname": "question", "fieldname": "question",
"fieldtype": "Small Text", "fieldtype": "Text Editor",
"in_list_view": 1, "in_list_view": 1,
"label": "Question", "label": "Question",
"reqd": 1 "reqd": 1
@ -34,7 +34,7 @@
"read_only": 1 "read_only": 1
} }
], ],
"modified": "2019-05-30 18:39:21.880974", "modified": "2020-09-24 18:39:21.880974",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Education", "module": "Education",
"name": "Question", "name": "Question",
@ -77,4 +77,4 @@
"quick_entry": 1, "quick_entry": 1,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC" "sort_order": "DESC"
} }

View File

@ -20,14 +20,14 @@
{ {
"fetch_from": "question_link.question", "fetch_from": "question_link.question",
"fieldname": "question", "fieldname": "question",
"fieldtype": "Data", "fieldtype": "Text Editor",
"in_list_view": 1, "in_list_view": 1,
"label": "Question", "label": "Question",
"read_only": 1 "read_only": 1
} }
], ],
"istable": 1, "istable": 1,
"modified": "2019-06-12 12:24:02.312577", "modified": "2020-09-24 12:24:02.312577",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Education", "module": "Education",
"name": "Quiz Question", "name": "Quiz Question",
@ -37,4 +37,4 @@
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1 "track_changes": 1
} }

View File

@ -8,6 +8,7 @@
"allow_print": 0, "allow_print": 0,
"amount": 0.0, "amount": 0.0,
"amount_based_on_field": 0, "amount_based_on_field": 0,
"apply_document_permissions": 0,
"creation": "2016-09-22 13:10:10.792735", "creation": "2016-09-22 13:10:10.792735",
"doc_type": "Student Applicant", "doc_type": "Student Applicant",
"docstatus": 0, "docstatus": 0,
@ -16,7 +17,7 @@
"is_standard": 1, "is_standard": 1,
"login_required": 1, "login_required": 1,
"max_attachment_size": 0, "max_attachment_size": 0,
"modified": "2020-06-11 22:53:45.875310", "modified": "2020-10-07 23:13:07.814941",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Education", "module": "Education",
"name": "student-applicant", "name": "student-applicant",
@ -157,7 +158,7 @@
}, },
{ {
"allow_read_on_all_link_options": 0, "allow_read_on_all_link_options": 0,
"default": "INDIAN", "default": "",
"fieldname": "nationality", "fieldname": "nationality",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,

View File

@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
import json import json
from frappe.utils import getdate, get_time from frappe.utils import getdate, get_time, flt
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
from frappe import _ from frappe import _
import datetime import datetime
@ -45,7 +45,7 @@ class PatientAppointment(Document):
def validate_overlaps(self): def validate_overlaps(self):
end_time = datetime.datetime.combine(getdate(self.appointment_date), get_time(self.appointment_time)) \ end_time = datetime.datetime.combine(getdate(self.appointment_date), get_time(self.appointment_time)) \
+ datetime.timedelta(minutes=float(self.duration)) + datetime.timedelta(minutes=flt(self.duration))
overlaps = frappe.db.sql(""" overlaps = frappe.db.sql("""
select select

View File

@ -23,7 +23,6 @@ web_include_css = "assets/css/erpnext-web.css"
doctype_js = { doctype_js = {
"Communication": "public/js/communication.js", "Communication": "public/js/communication.js",
"Event": "public/js/event.js", "Event": "public/js/event.js",
"Website Theme": "public/js/website_theme.js",
"Newsletter": "public/js/newsletter.js" "Newsletter": "public/js/newsletter.js"
} }
@ -336,7 +335,8 @@ scheduler_events = {
"erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation", "erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation",
"erpnext.hr.utils.generate_leave_encashment", "erpnext.hr.utils.generate_leave_encashment",
"erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall.create_process_loan_security_shortfall", "erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall.create_process_loan_security_shortfall",
"erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.process_loan_interest_accrual_for_term_loans" "erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.process_loan_interest_accrual_for_term_loans",
"erpnext.crm.doctype.lead.lead.daily_open_lead"
], ],
"monthly_long": [ "monthly_long": [
"erpnext.accounts.deferred_revenue.process_deferred_accounting", "erpnext.accounts.deferred_revenue.process_deferred_accounting",

View File

@ -10,13 +10,13 @@ frappe.ui.form.on('Appraisal', {
}; };
}, },
onload: function(frm) { onload: function(frm) {
if(!frm.doc.status) { if(!frm.doc.status) {
frm.set_value('status', 'Draft'); frm.set_value('status', 'Draft');
} }
}, },
kra_template: function(frm) { kra_template: function(frm) {
frm.doc.goals = []; frm.doc.goals = [];
erpnext.utils.map_current_doc({ erpnext.utils.map_current_doc({
method: "erpnext.hr.doctype.appraisal.appraisal.fetch_appraisal_template", method: "erpnext.hr.doctype.appraisal.appraisal.fetch_appraisal_template",
@ -24,31 +24,56 @@ frappe.ui.form.on('Appraisal', {
frm: frm frm: frm
}); });
}, },
calculate_total: function(frm) { calculate_total: function(frm) {
let goals = frm.doc.goals || []; let goals = frm.doc.goals || [];
let total =0; let total = 0;
for(let i = 0; i<goals.length; i++){
if (goals == []) {
frm.set_value('total_score', 0);
return;
}
for (let i = 0; i<goals.length; i++) {
total = flt(total)+flt(goals[i].score_earned) total = flt(total)+flt(goals[i].score_earned)
} }
frm.set_value('total_score', total); if (!isNaN(total)) {
frm.set_value('total_score', total);
frm.refresh_field('calculate_total');
}
},
set_score_earned: function(frm) {
let goals = frm.doc.goals || [];
for (let i = 0; i<goals.length; i++) {
var d = locals[goals[i].doctype][goals[i].name];
if (d.score && d.per_weightage) {
d.score_earned = flt(d.per_weightage*d.score, precision("score_earned", d))/100;
}
else {
d.score_earned = 0;
}
refresh_field('score_earned', d.name, 'goals');
}
frm.trigger('calculate_total');
} }
}); });
frappe.ui.form.on('Appraisal Goal', { frappe.ui.form.on('Appraisal Goal', {
score: function(frm, cdt, cdn) { score: function(frm, cdt, cdn) {
var d = locals[cdt][cdn]; var d = locals[cdt][cdn];
if (d.score) { if (flt(d.score) > 5) {
if (flt(d.score) > 5) { frappe.msgprint(__("Score must be less than or equal to 5"));
frappe.msgprint(__("Score must be less than or equal to 5")); d.score = 0;
d.score = 0; refresh_field('score', d.name, 'goals');
refresh_field('score', d.name, 'goals');
}
d.score_earned = flt(d.per_weightage*d.score, precision("score_earned", d))/100;
} else {
d.score_earned = 0;
} }
refresh_field('score_earned', d.name, 'goals'); else {
frm.trigger('calculate_total'); frm.trigger('set_score_earned');
}
},
per_weightage: function(frm) {
frm.trigger('set_score_earned');
},
goals_remove: function(frm) {
frm.trigger('set_score_earned');
} }
}); });

View File

@ -1,775 +1,254 @@
{ {
"allow_copy": 0, "actions": [],
"allow_events_in_timeline": 0, "autoname": "naming_series:",
"allow_guest_to_view": 0, "creation": "2013-01-10 16:34:12",
"allow_import": 0, "doctype": "DocType",
"allow_rename": 0, "document_type": "Setup",
"autoname": "naming_series:", "engine": "InnoDB",
"beta": 0, "field_order": [
"creation": "2013-01-10 16:34:12", "employee_details",
"custom": 0, "naming_series",
"docstatus": 0, "kra_template",
"doctype": "DocType", "employee",
"document_type": "Setup", "employee_name",
"editable_grid": 0, "column_break0",
"status",
"start_date",
"end_date",
"department",
"section_break0",
"goals",
"total_score",
"section_break1",
"remarks",
"other_details",
"company",
"column_break_17",
"amended_from"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "fieldname": "employee_details",
"allow_in_quick_entry": 0, "fieldtype": "Section Break",
"allow_on_submit": 0, "oldfieldtype": "Section Break"
"bold": 0, },
"collapsible": 0,
"columns": 0,
"fieldname": "employee_details",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "",
"length": 0,
"no_copy": 0,
"oldfieldtype": "Section Break",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "naming_series",
"allow_in_quick_entry": 0, "fieldtype": "Select",
"allow_on_submit": 0, "label": "Series",
"bold": 0, "no_copy": 1,
"collapsible": 0, "options": "HR-APR-.YY.-.MM.",
"columns": 0, "print_hide": 1,
"default": "", "reqd": 1,
"fieldname": "naming_series", "set_only_once": 1
"fieldtype": "Select", },
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Series",
"length": 0,
"no_copy": 1,
"options": "HR-APR-.YY.-.MM.",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 1,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "kra_template",
"allow_in_quick_entry": 0, "fieldtype": "Link",
"allow_on_submit": 0, "in_standard_filter": 1,
"bold": 0, "label": "Appraisal Template",
"collapsible": 0, "oldfieldname": "kra_template",
"columns": 0, "oldfieldtype": "Link",
"description": "", "options": "Appraisal Template",
"fieldname": "kra_template", "reqd": 1
"fieldtype": "Link", },
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Appraisal Template",
"length": 0,
"no_copy": 0,
"oldfieldname": "kra_template",
"oldfieldtype": "Link",
"options": "Appraisal Template",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "depends_on": "kra_template",
"allow_in_quick_entry": 0, "fieldname": "employee",
"allow_on_submit": 0, "fieldtype": "Link",
"bold": 0, "in_global_search": 1,
"collapsible": 0, "in_standard_filter": 1,
"columns": 0, "label": "For Employee",
"depends_on": "kra_template", "oldfieldname": "employee",
"description": "", "oldfieldtype": "Link",
"fieldname": "employee", "options": "Employee",
"fieldtype": "Link", "reqd": 1,
"hidden": 0, "search_index": 1
"ignore_user_permissions": 0, },
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "For Employee",
"length": 0,
"no_copy": 0,
"oldfieldname": "employee",
"oldfieldtype": "Link",
"options": "Employee",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "depends_on": "kra_template",
"allow_in_quick_entry": 0, "fieldname": "employee_name",
"allow_on_submit": 0, "fieldtype": "Data",
"bold": 0, "in_global_search": 1,
"collapsible": 0, "label": "For Employee Name",
"columns": 0, "oldfieldname": "employee_name",
"depends_on": "kra_template", "oldfieldtype": "Data",
"fieldname": "employee_name", "read_only": 1
"fieldtype": "Data", },
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "For Employee Name",
"length": 0,
"no_copy": 0,
"oldfieldname": "employee_name",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "depends_on": "kra_template",
"allow_in_quick_entry": 0, "fieldname": "column_break0",
"allow_on_submit": 0, "fieldtype": "Column Break",
"bold": 0, "oldfieldtype": "Column Break",
"collapsible": 0,
"columns": 0,
"depends_on": "kra_template",
"fieldname": "column_break0",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"oldfieldtype": "Column Break",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "50%" "width": "50%"
}, },
{ {
"allow_bulk_edit": 0, "default": "Draft",
"allow_in_quick_entry": 0, "depends_on": "kra_template",
"allow_on_submit": 0, "fieldname": "status",
"bold": 0, "fieldtype": "Select",
"collapsible": 0, "in_standard_filter": 1,
"columns": 0, "label": "Status",
"default": "Draft", "no_copy": 1,
"depends_on": "kra_template", "oldfieldname": "status",
"fieldname": "status", "oldfieldtype": "Select",
"fieldtype": "Select", "options": "\nDraft\nSubmitted\nCompleted\nCancelled",
"hidden": 0, "read_only": 1,
"ignore_user_permissions": 0, "reqd": 1,
"ignore_xss_filter": 0, "search_index": 1
"in_filter": 0, },
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Status",
"length": 0,
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
"options": "\nDraft\nSubmitted\nCompleted\nCancelled",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "depends_on": "kra_template",
"allow_in_quick_entry": 0, "fieldname": "start_date",
"allow_on_submit": 0, "fieldtype": "Date",
"bold": 0, "in_list_view": 1,
"collapsible": 0, "label": "Start Date",
"columns": 0, "oldfieldname": "start_date",
"depends_on": "kra_template", "oldfieldtype": "Date",
"fieldname": "start_date", "reqd": 1
"fieldtype": "Date", },
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Start Date",
"length": 0,
"no_copy": 0,
"oldfieldname": "start_date",
"oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "depends_on": "kra_template",
"allow_in_quick_entry": 0, "fieldname": "end_date",
"allow_on_submit": 0, "fieldtype": "Date",
"bold": 0, "label": "End Date",
"collapsible": 0, "oldfieldname": "end_date",
"columns": 0, "oldfieldtype": "Date",
"depends_on": "kra_template", "reqd": 1
"fieldname": "end_date", },
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "End Date",
"length": 0,
"no_copy": 0,
"oldfieldname": "end_date",
"oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fetch_from": "employee.department",
"allow_in_quick_entry": 0, "fieldname": "department",
"allow_on_submit": 0, "fieldtype": "Link",
"bold": 0, "label": "Department",
"collapsible": 0, "options": "Department",
"columns": 0, "read_only": 1
"fetch_from": "employee.department", },
"fieldname": "department",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Department",
"length": 0,
"no_copy": 0,
"options": "Department",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "depends_on": "kra_template",
"allow_in_quick_entry": 0, "fieldname": "section_break0",
"allow_on_submit": 0, "fieldtype": "Section Break",
"bold": 0, "label": "Goals",
"collapsible": 0, "oldfieldtype": "Section Break",
"columns": 0, "options": "Simple"
"depends_on": "kra_template", },
"fieldname": "section_break0",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Goals",
"length": 0,
"no_copy": 0,
"oldfieldtype": "Section Break",
"options": "Simple",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "goals",
"allow_in_quick_entry": 0, "fieldtype": "Table",
"allow_on_submit": 0, "label": "Goals",
"bold": 0, "oldfieldname": "appraisal_details",
"collapsible": 0, "oldfieldtype": "Table",
"columns": 0, "options": "Appraisal Goal"
"fieldname": "goals", },
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Goals",
"length": 0,
"no_copy": 0,
"oldfieldname": "appraisal_details",
"oldfieldtype": "Table",
"options": "Appraisal Goal",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "total_score",
"allow_in_quick_entry": 0, "fieldtype": "Float",
"allow_on_submit": 0, "in_list_view": 1,
"bold": 0, "label": "Total Score (Out of 5)",
"collapsible": 0, "no_copy": 1,
"columns": 0, "oldfieldname": "total_score",
"fieldname": "calculate_total_score", "oldfieldtype": "Currency",
"fieldtype": "Button", "read_only": 1
"hidden": 0, },
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Calculate Total Score",
"length": 0,
"no_copy": 0,
"oldfieldtype": "Button",
"options": "calculate_total",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "depends_on": "kra_template",
"allow_in_quick_entry": 0, "fieldname": "section_break1",
"allow_on_submit": 0, "fieldtype": "Section Break"
"bold": 0, },
"collapsible": 0,
"columns": 0,
"fieldname": "total_score",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Total Score (Out of 5)",
"length": 0,
"no_copy": 1,
"oldfieldname": "total_score",
"oldfieldtype": "Currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "description": "Any other remarks, noteworthy effort that should go in the records.",
"allow_in_quick_entry": 0, "fieldname": "remarks",
"allow_on_submit": 0, "fieldtype": "Text",
"bold": 0, "label": "Remarks"
"collapsible": 0, },
"columns": 0,
"depends_on": "kra_template",
"fieldname": "section_break1",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "depends_on": "kra_template",
"allow_in_quick_entry": 0, "fieldname": "other_details",
"allow_on_submit": 0, "fieldtype": "Section Break"
"bold": 0, },
"collapsible": 0,
"columns": 0,
"description": "Any other remarks, noteworthy effort that should go in the records.",
"fieldname": "remarks",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Remarks",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "company",
"allow_in_quick_entry": 0, "fieldtype": "Link",
"allow_on_submit": 0, "label": "Company",
"bold": 0, "oldfieldname": "company",
"collapsible": 0, "oldfieldtype": "Link",
"columns": 0, "options": "Company",
"depends_on": "kra_template", "remember_last_selected_value": 1,
"fieldname": "other_details", "reqd": 1
"fieldtype": "Section Break", },
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "column_break_17",
"allow_in_quick_entry": 0, "fieldtype": "Column Break"
"allow_on_submit": 0, },
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"oldfieldname": "company",
"oldfieldtype": "Link",
"options": "Company",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 1,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "amended_from",
"allow_in_quick_entry": 0, "fieldtype": "Link",
"allow_on_submit": 0, "hidden": 1,
"bold": 0, "ignore_user_permissions": 1,
"collapsible": 0, "label": "Amended From",
"columns": 0, "no_copy": 1,
"fieldname": "column_break_17", "oldfieldname": "amended_from",
"fieldtype": "Column Break", "oldfieldtype": "Data",
"hidden": 0, "options": "Appraisal",
"ignore_user_permissions": 0, "print_hide": 1,
"ignore_xss_filter": 0, "read_only": 1,
"in_filter": 0, "report_hide": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Amended From",
"length": 0,
"no_copy": 1,
"oldfieldname": "amended_from",
"oldfieldtype": "Data",
"options": "Appraisal",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "150px" "width": "150px"
} }
], ],
"has_web_view": 0, "icon": "fa fa-thumbs-up",
"hide_heading": 0, "idx": 1,
"hide_toolbar": 0, "index_web_pages_for_search": 1,
"icon": "fa fa-thumbs-up", "is_submittable": 1,
"idx": 1, "links": [],
"image_view": 0, "modified": "2020-10-03 21:48:33.297065",
"in_create": 0, "modified_by": "Administrator",
"is_submittable": 1, "module": "HR",
"issingle": 0, "name": "Appraisal",
"istable": 0, "owner": "Administrator",
"max_attachments": 0,
"modified": "2020-09-18 17:26:09.703215",
"modified_by": "Administrator",
"module": "HR",
"name": "Appraisal",
"owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0, "create": 1,
"cancel": 0, "email": 1,
"create": 1, "print": 1,
"delete": 0, "read": 1,
"email": 1, "report": 1,
"export": 0, "role": "Employee",
"if_owner": 0, "share": 1,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Employee",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1 "write": 1
}, },
{ {
"amend": 1, "amend": 1,
"cancel": 1, "cancel": 1,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 0, "print": 1,
"if_owner": 0, "read": 1,
"import": 0, "report": 1,
"permlevel": 0, "role": "System Manager",
"print": 1, "share": 1,
"read": 1, "submit": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1 "write": 1
}, },
{ {
"amend": 1, "amend": 1,
"cancel": 1, "cancel": 1,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 0, "print": 1,
"if_owner": 0, "read": 1,
"import": 0, "report": 1,
"permlevel": 0, "role": "HR User",
"print": 1, "share": 1,
"read": 1, "submit": 1,
"report": 1,
"role": "HR User",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1 "write": 1
} }
], ],
"quick_entry": 0, "search_fields": "status, employee, employee_name",
"read_only": 0, "sort_field": "modified",
"read_only_onload": 0, "sort_order": "DESC",
"search_fields": "status, employee, employee_name", "timeline_field": "employee",
"show_name_in_global_search": 0, "title_field": "employee_name"
"sort_field": "modified",
"sort_order": "DESC",
"timeline_field": "employee",
"title_field": "employee_name",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
} }

View File

@ -50,7 +50,7 @@ class Appraisal(Document):
total_w += flt(d.per_weightage) total_w += flt(d.per_weightage)
if int(total_w) != 100: if int(total_w) != 100:
frappe.throw(_("Total weightage assigned should be 100%. It is {0}").format(str(total_w) + "%")) frappe.throw(_("Total weightage assigned should be 100%.<br>It is {0}").format(str(total_w) + "%"))
if frappe.db.get_value("Employee", self.employee, "user_id") != \ if frappe.db.get_value("Employee", self.employee, "user_id") != \
frappe.session.user and total == 0: frappe.session.user and total == 0:

View File

@ -56,6 +56,9 @@ class Employee(NestedSet):
if existing_user_id: if existing_user_id:
remove_user_permission( remove_user_permission(
"Employee", self.name, existing_user_id) "Employee", self.name, existing_user_id)
def after_rename(self, old, new, merge):
self.db_set("employee", new)
def set_employee_name(self): def set_employee_name(self):
self.employee_name = ' '.join(filter(lambda x: x, [self.first_name, self.middle_name, self.last_name])) self.employee_name = ' '.join(filter(lambda x: x, [self.first_name, self.middle_name, self.last_name]))

View File

@ -224,7 +224,8 @@ def trigger_razorpay_subscription(*args, **kwargs):
member.subscription_activated = 1 member.subscription_activated = 1
member.save(ignore_permissions=True) member.save(ignore_permissions=True)
except Exception as e: except Exception as e:
log = frappe.log_error(e, "Error creating membership entry") message = "{0}\n\n{1}\n\n{2}: {3}".format(e, frappe.get_traceback(), __("Payment ID"), payment.id)
log = frappe.log_error(message, _("Error creating membership entry for {0}").format(member.name))
notify_failure(log) notify_failure(log)
return { 'status': 'Failed', 'reason': e} return { 'status': 'Failed', 'reason': e}
@ -250,4 +251,4 @@ def get_plan_from_razorpay_id(plan_id):
try: try:
return plan[0]['name'] return plan[0]['name']
except: except:
return None return None

View File

@ -726,5 +726,6 @@ erpnext.patches.v12_0.rename_lost_reason_detail
erpnext.patches.v13_0.drop_razorpay_payload_column erpnext.patches.v13_0.drop_razorpay_payload_column
erpnext.patches.v13_0.update_start_end_date_for_old_shift_assignment erpnext.patches.v13_0.update_start_end_date_for_old_shift_assignment
erpnext.patches.v13_0.setting_custom_roles_for_some_regional_reports erpnext.patches.v13_0.setting_custom_roles_for_some_regional_reports
erpnext.patches.v13_0.rename_issue_doctype_fields
erpnext.patches.v13_0.change_default_pos_print_format erpnext.patches.v13_0.change_default_pos_print_format
erpnext.patches.v13_0.set_youtube_video_id erpnext.patches.v13_0.set_youtube_video_id

View File

@ -0,0 +1,65 @@
# Copyright (c) 2020, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.utils.rename_field import rename_field
def execute():
if frappe.db.exists('DocType', 'Issue'):
issues = frappe.db.get_all('Issue', fields=['name', 'response_by_variance', 'resolution_by_variance', 'mins_to_first_response'],
order_by='creation desc')
frappe.reload_doc('support', 'doctype', 'issue')
# rename fields
rename_map = {
'agreement_fulfilled': 'agreement_status',
'mins_to_first_response': 'first_response_time'
}
for old, new in rename_map.items():
rename_field('Issue', old, new)
# change fieldtype to duration
count = 0
for entry in issues:
response_by_variance = convert_to_seconds(entry.response_by_variance, 'Hours')
resolution_by_variance = convert_to_seconds(entry.resolution_by_variance, 'Hours')
mins_to_first_response = convert_to_seconds(entry.mins_to_first_response, 'Minutes')
frappe.db.set_value('Issue', entry.name, {
'response_by_variance': response_by_variance,
'resolution_by_variance': resolution_by_variance,
'first_response_time': mins_to_first_response
})
# commit after every 100 updates
count += 1
if count%100 == 0:
frappe.db.commit()
if frappe.db.exists('DocType', 'Opportunity'):
opportunities = frappe.db.get_all('Opportunity', fields=['name', 'mins_to_first_response'], order_by='creation desc')
frappe.reload_doc('crm', 'doctype', 'opportunity')
rename_field('Opportunity', 'mins_to_first_response', 'first_response_time')
# change fieldtype to duration
count = 0
for entry in opportunities:
mins_to_first_response = convert_to_seconds(entry.mins_to_first_response, 'Minutes')
frappe.db.set_value('Opportunity', entry.name, 'first_response_time', mins_to_first_response)
# commit after every 100 updates
count += 1
if count%100 == 0:
frappe.db.commit()
# renamed reports from "Minutes to First Response for Issues" to "First Response Time for Issues". Same for Opportunity
for report in ['Minutes to First Response for Issues', 'Minutes to First Response for Opportunity']:
if frappe.db.exists('Report', report):
frappe.delete_doc('Report', report)
def convert_to_seconds(value, unit):
seconds = 0
if unit == 'Hours':
seconds = value * 3600
if unit == 'Minutes':
seconds = value * 60
return seconds

View File

@ -120,7 +120,7 @@ frappe.ui.form.on('Salary Structure', {
var get_payment_mode_account = function(frm, mode_of_payment, callback) { var get_payment_mode_account = function(frm, mode_of_payment, callback) {
if(!frm.doc.company) { if(!frm.doc.company) {
frappe.throw(__("Please select the Company first")); frappe.throw({message:__("Please select a Company first."), title: __("Mandatory")});
} }
if(!mode_of_payment) { if(!mode_of_payment) {

View File

@ -140,7 +140,7 @@ class Question {
make_question() { make_question() {
let question_wrapper = document.createElement('h5'); let question_wrapper = document.createElement('h5');
question_wrapper.classList.add('mt-3'); question_wrapper.classList.add('mt-3');
question_wrapper.innerText = this.question; question_wrapper.innerHTML = this.question;
this.wrapper.appendChild(question_wrapper); this.wrapper.appendChild(question_wrapper);
} }

View File

@ -480,7 +480,7 @@ erpnext.utils.update_child_items = function(opts) {
callback: r => { callback: r => {
if(!r.exc) { if(!r.exc) {
if (this.doc.conversion_factor == r.message.conversion_factor) return; if (this.doc.conversion_factor == r.message.conversion_factor) return;
const docname = this.doc.docname; const docname = this.doc.docname;
dialog.fields_dict.trans_items.df.data.some(doc => { dialog.fields_dict.trans_items.df.data.some(doc => {
if (doc.docname == docname) { if (doc.docname == docname) {
@ -677,6 +677,7 @@ erpnext.utils.map_current_doc = function(opts) {
date_field: opts.date_field || undefined, date_field: opts.date_field || undefined,
setters: opts.setters, setters: opts.setters,
get_query: opts.get_query, get_query: opts.get_query,
add_filters_group: 1,
action: function(selections, args) { action: function(selections, args) {
let values = selections; let values = selections;
if(values.length === 0){ if(values.length === 0){

View File

@ -1,14 +0,0 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
frappe.ui.form.on('Website Theme', {
validate(frm) {
let theme_scss = frm.doc.theme_scss;
if (theme_scss && (theme_scss.includes('frappe/public/scss/website')
&& !theme_scss.includes('erpnext/public/scss/website'))
) {
frm.set_value('theme_scss',
`${frm.doc.theme_scss}\n@import "erpnext/public/scss/website";`);
}
}
});

View File

@ -23,7 +23,7 @@
{ {
"hidden": 0, "hidden": 0,
"label": "Other Reports", "label": "Other Reports",
"links": "[\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Details\",\n \"name\": \"Lead Details\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Address\"\n ],\n \"doctype\": \"Address\",\n \"is_query_report\": true,\n \"label\": \"Customer Addresses And Contacts\",\n \"name\": \"Address And Contacts\",\n \"route_options\": {\n \"party_type\": \"Customer\"\n },\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Item\",\n \"is_query_report\": true,\n \"label\": \"Available Stock for Packing Items\",\n \"name\": \"Available Stock for Packing Items\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Pending SO Items For Purchase Request\",\n \"name\": \"Pending SO Items For Purchase Request\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Delivery Note\"\n ],\n \"doctype\": \"Delivery Note\",\n \"is_query_report\": true,\n \"label\": \"Delivery Note Trends\",\n \"name\": \"Delivery Note Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Invoice Trends\",\n \"name\": \"Sales Invoice Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customer Credit Balance\",\n \"name\": \"Customer Credit Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customers Without Any Sales Transactions\",\n \"name\": \"Customers Without Any Sales Transactions\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Sales Partners Commission\",\n \"name\": \"Sales Partners Commission\",\n \"type\": \"report\"\n }\n]" "links": "[\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Details\",\n \"name\": \"Lead Details\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Address\"\n ],\n \"doctype\": \"Address\",\n \"is_query_report\": true,\n \"label\": \"Customer Addresses And Contacts\",\n \"name\": \"Address And Contacts\",\n \"route_options\": {\n \"party_type\": \"Customer\"\n },\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Item\",\n \"is_query_report\": true,\n \"label\": \"Available Stock for Packing Items\",\n \"name\": \"Available Stock for Packing Items\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Pending SO Items For Purchase Request\",\n \"name\": \"Pending SO Items For Purchase Request\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Delivery Note\"\n ],\n \"doctype\": \"Delivery Note\",\n \"is_query_report\": true,\n \"label\": \"Delivery Note Trends\",\n \"name\": \"Delivery Note Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Invoice Trends\",\n \"name\": \"Sales Invoice Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customer Credit Balance\",\n \"name\": \"Customer Credit Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customers Without Any Sales Transactions\",\n \"name\": \"Customers Without Any Sales Transactions\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Sales Partners Commission\",\n \"name\": \"Sales Partners Commission\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Territory Target Variance Based On Item Group\",\n \"name\": \"Territory Target Variance Based On Item Group\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Sales Person Target Variance Based On Item Group\",\n \"name\": \"Sales Person Target Variance Based On Item Group\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Sales Partner Target Variance Based On Item Group\",\n \"name\": \"Sales Partner Target Variance based on Item Group\",\n \"type\": \"report\"\n }\n \n]"
} }
], ],
"category": "Modules", "category": "Modules",
@ -44,7 +44,7 @@
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "Selling", "label": "Selling",
"modified": "2020-08-15 10:12:53.131621", "modified": "2020-10-08 10:23:09.984377",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Selling", "module": "Selling",
"name": "Selling", "name": "Selling",

View File

@ -108,6 +108,10 @@ class TestQuotation(unittest.TestCase):
sales_order.transaction_date = nowdate() sales_order.transaction_date = nowdate()
sales_order.insert() sales_order.insert()
# Remove any unknown taxes if applied
sales_order.set('taxes', [])
sales_order.save()
self.assertEqual(sales_order.payment_schedule[0].payment_amount, 8906.00) self.assertEqual(sales_order.payment_schedule[0].payment_amount, 8906.00)
self.assertEqual(sales_order.payment_schedule[0].due_date, getdate(quotation.transaction_date)) self.assertEqual(sales_order.payment_schedule[0].due_date, getdate(quotation.transaction_date))
self.assertEqual(sales_order.payment_schedule[1].payment_amount, 8906.00) self.assertEqual(sales_order.payment_schedule[1].payment_amount, 8906.00)

View File

@ -181,7 +181,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
} }
// project // project
if(flt(doc.per_delivered, 2) < 100 && (order_is_a_sale || order_is_a_custom_sale) && allow_delivery) { if(flt(doc.per_delivered, 2) < 100) {
this.frm.add_custom_button(__('Project'), () => this.make_project(), __('Create')); this.frm.add_custom_button(__('Project'), () => this.make_project(), __('Create'));
} }

View File

@ -1460,7 +1460,7 @@
"idx": 105, "idx": 105,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-07-31 14:13:17.962015", "modified": "2020-10-07 14:30:01.782617",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Selling", "module": "Selling",
"name": "Sales Order", "name": "Sales Order",
@ -1534,7 +1534,7 @@
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"timeline_field": "customer", "timeline_field": "customer",
"title_field": "customer", "title_field": "customer_name",
"track_changes": 1, "track_changes": 1,
"track_seen": 1 "track_seen": 1
} }

View File

@ -89,6 +89,8 @@ class TestSalesOrder(unittest.TestCase):
self.assertEqual(len(si.get("items")), 1) self.assertEqual(len(si.get("items")), 1)
si.insert() si.insert()
si.set('taxes', [])
si.save()
self.assertEqual(si.payment_schedule[0].payment_amount, 500.0) self.assertEqual(si.payment_schedule[0].payment_amount, 500.0)
self.assertEqual(si.payment_schedule[0].due_date, so.transaction_date) self.assertEqual(si.payment_schedule[0].due_date, so.transaction_date)

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import cstr from frappe.utils import cstr, cint
from frappe import msgprint, throw, _ from frappe import msgprint, throw, _
from frappe.model.document import Document from frappe.model.document import Document
@ -159,7 +159,7 @@ class NamingSeries(Document):
prefix = self.parse_naming_series() prefix = self.parse_naming_series()
self.insert_series(prefix) self.insert_series(prefix)
frappe.db.sql("update `tabSeries` set current = %s where name = %s", frappe.db.sql("update `tabSeries` set current = %s where name = %s",
(self.current_value, prefix)) (cint(self.current_value), prefix))
msgprint(_("Series Updated Successfully")) msgprint(_("Series Updated Successfully"))
else: else:
msgprint(_("Please select prefix first")) msgprint(_("Please select prefix first"))

View File

@ -96,7 +96,9 @@ def place_order():
def request_for_quotation(): def request_for_quotation():
quotation = _get_cart_quotation() quotation = _get_cart_quotation()
quotation.flags.ignore_permissions = True quotation.flags.ignore_permissions = True
quotation.submit() quotation.save()
if not get_shopping_cart_settings().save_quotations_as_draft:
quotation.submit()
return quotation.name return quotation.name
@frappe.whitelist() @frappe.whitelist()

View File

@ -27,6 +27,7 @@
"enable_checkout", "enable_checkout",
"payment_success_url", "payment_success_url",
"column_break_11", "column_break_11",
"save_quotations_as_draft",
"payment_gateway_account" "payment_gateway_account"
], ],
"fields": [ "fields": [
@ -166,13 +167,20 @@
"fieldname": "enable_variants", "fieldname": "enable_variants",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Enable Variants" "label": "Enable Variants"
},
{
"default": "0",
"depends_on": "eval: doc.enable_checkout == 0",
"fieldname": "save_quotations_as_draft",
"fieldtype": "Check",
"label": "Save Quotations as Draft"
} }
], ],
"icon": "fa fa-shopping-cart", "icon": "fa fa-shopping-cart",
"idx": 1, "idx": 1,
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2020-08-02 18:21:43.873303", "modified": "2020-09-24 16:28:07.192525",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Shopping Cart", "module": "Shopping Cart",
"name": "Shopping Cart Settings", "name": "Shopping Cart Settings",

View File

@ -26,19 +26,19 @@ frappe.ui.form.on("Item", {
refresh: function(frm) { refresh: function(frm) {
if (frm.doc.is_stock_item) { if (frm.doc.is_stock_item) {
frm.add_custom_button(__("Balance"), function() { frm.add_custom_button(__("Stock Balance"), function() {
frappe.route_options = { frappe.route_options = {
"item_code": frm.doc.name "item_code": frm.doc.name
} }
frappe.set_route("query-report", "Stock Balance"); frappe.set_route("query-report", "Stock Balance");
}, __("View")); }, __("View"));
frm.add_custom_button(__("Ledger"), function() { frm.add_custom_button(__("Stock Ledger"), function() {
frappe.route_options = { frappe.route_options = {
"item_code": frm.doc.name "item_code": frm.doc.name
} }
frappe.set_route("query-report", "Stock Ledger"); frappe.set_route("query-report", "Stock Ledger");
}, __("View")); }, __("View"));
frm.add_custom_button(__("Projected"), function() { frm.add_custom_button(__("Stock Projected Qty"), function() {
frappe.route_options = { frappe.route_options = {
"item_code": frm.doc.name "item_code": frm.doc.name
} }

View File

@ -1,357 +1,97 @@
{ {
"allow_copy": 0, "actions": [],
"allow_events_in_timeline": 0, "allow_import": 1,
"allow_guest_to_view": 0, "allow_rename": 1,
"allow_import": 1, "autoname": "field:attribute_name",
"allow_rename": 1, "creation": "2014-09-26 03:49:54.899170",
"autoname": "field:attribute_name", "doctype": "DocType",
"beta": 0, "document_type": "Setup",
"creation": "2014-09-26 03:49:54.899170", "engine": "InnoDB",
"custom": 0, "field_order": [
"docstatus": 0, "attribute_name",
"doctype": "DocType", "numeric_values",
"document_type": "Setup", "section_break_4",
"editable_grid": 0, "from_range",
"increment",
"column_break_8",
"to_range",
"section_break_5",
"item_attribute_values"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "fieldname": "attribute_name",
"allow_in_quick_entry": 0, "fieldtype": "Data",
"allow_on_submit": 0, "in_list_view": 1,
"bold": 0, "label": "Attribute Name",
"collapsible": 0, "reqd": 1,
"columns": 0,
"fieldname": "attribute_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Attribute Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 1 "unique": 1
}, },
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_in_quick_entry": 0, "fieldname": "numeric_values",
"allow_on_submit": 0, "fieldtype": "Check",
"bold": 0, "label": "Numeric Values"
"collapsible": 0, },
"columns": 0,
"default": "0",
"fieldname": "numeric_values",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Numeric Values",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "depends_on": "numeric_values",
"allow_in_quick_entry": 0, "fieldname": "section_break_4",
"allow_on_submit": 0, "fieldtype": "Section Break"
"bold": 0, },
"collapsible": 0,
"columns": 0,
"depends_on": "numeric_values",
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_in_quick_entry": 0, "fieldname": "from_range",
"allow_on_submit": 0, "fieldtype": "Float",
"bold": 0, "label": "From Range"
"collapsible": 0, },
"columns": 0,
"depends_on": "",
"fieldname": "from_range",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "From Range",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_in_quick_entry": 0, "fieldname": "increment",
"allow_on_submit": 0, "fieldtype": "Float",
"bold": 0, "label": "Increment"
"collapsible": 0, },
"columns": 0,
"depends_on": "",
"fieldname": "increment",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Increment",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "column_break_8",
"allow_in_quick_entry": 0, "fieldtype": "Column Break"
"allow_on_submit": 0, },
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_8",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_in_quick_entry": 0, "fieldname": "to_range",
"allow_on_submit": 0, "fieldtype": "Float",
"bold": 0, "label": "To Range"
"collapsible": 0, },
"columns": 0,
"depends_on": "",
"fieldname": "to_range",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "To Range",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "depends_on": "eval: !doc.numeric_values",
"allow_in_quick_entry": 0, "fieldname": "section_break_5",
"allow_on_submit": 0, "fieldtype": "Section Break"
"bold": 0, },
"collapsible": 0,
"columns": 0,
"depends_on": "eval: !doc.numeric_values",
"fieldname": "section_break_5",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "item_attribute_values",
"allow_in_quick_entry": 0, "fieldtype": "Table",
"allow_on_submit": 0, "label": "Item Attribute Values",
"bold": 0, "options": "Item Attribute Value"
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "item_attribute_values",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item Attribute Values",
"length": 0,
"no_copy": 0,
"options": "Item Attribute Value",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
} }
], ],
"has_web_view": 0, "icon": "fa fa-edit",
"hide_heading": 0, "index_web_pages_for_search": 1,
"hide_toolbar": 0, "links": [],
"icon": "fa fa-edit", "modified": "2020-10-02 12:03:02.359202",
"idx": 0, "modified_by": "Administrator",
"image_view": 0, "module": "Stock",
"in_create": 0, "name": "Item Attribute",
"is_submittable": 0, "owner": "Administrator",
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-01-01 13:17:46.524806",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item Attribute",
"name_case": "",
"owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0, "create": 1,
"cancel": 0, "delete": 1,
"create": 1, "read": 1,
"delete": 1, "report": 1,
"email": 0, "role": "Item Manager",
"export": 0, "share": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 1,
"role": "Item Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1 "write": 1
} }
], ],
"quick_entry": 0, "sort_field": "modified",
"read_only": 0, "sort_order": "DESC",
"read_only_onload": 0, "track_changes": 1
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
} }

View File

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
from frappe import _ from frappe import _
from frappe.utils import flt
from erpnext.controllers.item_variant import (validate_is_incremental, from erpnext.controllers.item_variant import (validate_is_incremental,
validate_item_attribute_value, InvalidItemAttributeValueError) validate_item_attribute_value, InvalidItemAttributeValueError)
@ -42,7 +43,7 @@ class ItemAttribute(Document):
if self.from_range is None or self.to_range is None: if self.from_range is None or self.to_range is None:
frappe.throw(_("Please specify from/to range")) frappe.throw(_("Please specify from/to range"))
elif self.from_range >= self.to_range: elif flt(self.from_range) >= flt(self.to_range):
frappe.throw(_("From Range has to be less than To Range")) frappe.throw(_("From Range has to be less than To Range"))
if not self.increment: if not self.increment:

View File

@ -156,6 +156,7 @@ frappe.ui.form.on('Stock Entry', {
mr_item.item_code = item.item_code; mr_item.item_code = item.item_code;
mr_item.item_name = item.item_name; mr_item.item_name = item.item_name;
mr_item.uom = item.uom; mr_item.uom = item.uom;
mr_item.stock_uom = item.stock_uom;
mr_item.conversion_factor = item.conversion_factor; mr_item.conversion_factor = item.conversion_factor;
mr_item.item_group = item.item_group; mr_item.item_group = item.item_group;
mr_item.description = item.description; mr_item.description = item.description;

View File

@ -28,7 +28,7 @@
{ {
"hidden": 0, "hidden": 0,
"label": "Reports", "label": "Reports",
"links": "[\n {\n \"dependencies\": [\n \"Issue\"\n ],\n \"doctype\": \"Issue\",\n \"is_query_report\": true,\n \"label\": \"Minutes to First Response for Issues\",\n \"name\": \"Minutes to First Response for Issues\",\n \"type\": \"report\"\n }\n]" "links": "[\n {\n \"dependencies\": [\n \"Issue\"\n ],\n \"doctype\": \"Issue\",\n \"is_query_report\": true,\n \"label\": \"First Response Time for Issues\",\n \"name\": \"First Response Time for Issues\",\n \"type\": \"report\"\n }\n]"
} }
], ],
"category": "Modules", "category": "Modules",
@ -43,7 +43,7 @@
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "Support", "label": "Support",
"modified": "2020-06-04 11:54:56.124219", "modified": "2020-08-11 15:49:34.307341",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Support", "module": "Support",
"name": "Support", "name": "Support",

View File

@ -2,10 +2,14 @@ frappe.ui.form.on("Issue", {
onload: function(frm) { onload: function(frm) {
frm.email_field = "raised_by"; frm.email_field = "raised_by";
frappe.db.get_value("Support Settings", {name: "Support Settings"}, "allow_resetting_service_level_agreement", (r) => { frappe.db.get_value("Support Settings", {name: "Support Settings"},
if (!r.allow_resetting_service_level_agreement) { ["allow_resetting_service_level_agreement", "track_service_level_agreement"], (r) => {
frm.set_df_property("reset_service_level_agreement", "hidden", 1) ; if (r && r.track_service_level_agreement == "0") {
} frm.set_df_property("service_level_section", "hidden", 1);
}
if (r && r.allow_resetting_service_level_agreement == "0") {
frm.set_df_property("reset_service_level_agreement", "hidden", 1);
}
}); });
if (frm.doc.service_level_agreement) { if (frm.doc.service_level_agreement) {
@ -38,7 +42,7 @@ frappe.ui.form.on("Issue", {
}, },
refresh: function (frm) { refresh: function (frm) {
if (frm.doc.status !== "Closed" && frm.doc.agreement_fulfilled === "Ongoing") { if (frm.doc.status !== "Closed" && frm.doc.agreement_status === "Ongoing") {
if (frm.doc.service_level_agreement) { if (frm.doc.service_level_agreement) {
frappe.call({ frappe.call({
'method': 'frappe.client.get', 'method': 'frappe.client.get',
@ -85,14 +89,14 @@ frappe.ui.form.on("Issue", {
if (frm.doc.service_level_agreement) { if (frm.doc.service_level_agreement) {
frm.dashboard.clear_headline(); frm.dashboard.clear_headline();
let agreement_fulfilled = (frm.doc.agreement_fulfilled == "Fulfilled") ? let agreement_status = (frm.doc.agreement_status == "Fulfilled") ?
{"indicator": "green", "msg": "Service Level Agreement has been fulfilled"} : {"indicator": "green", "msg": "Service Level Agreement has been fulfilled"} :
{"indicator": "red", "msg": "Service Level Agreement Failed"}; {"indicator": "red", "msg": "Service Level Agreement Failed"};
frm.dashboard.set_headline_alert( frm.dashboard.set_headline_alert(
'<div class="row">' + '<div class="row">' +
'<div class="col-xs-12">' + '<div class="col-xs-12">' +
'<span class="indicator whitespace-nowrap '+ agreement_fulfilled.indicator +'"><span class="hidden-xs">'+ agreement_fulfilled.msg +'</span></span> ' + '<span class="indicator whitespace-nowrap '+ agreement_status.indicator +'"><span class="hidden-xs">'+ agreement_status.msg +'</span></span> ' +
'</div>' + '</div>' +
'</div>' '</div>'
); );
@ -198,13 +202,13 @@ function set_time_to_resolve_and_response(frm) {
frm.dashboard.clear_headline(); frm.dashboard.clear_headline();
var time_to_respond = get_status(frm.doc.response_by_variance); var time_to_respond = get_status(frm.doc.response_by_variance);
if (!frm.doc.first_responded_on && frm.doc.agreement_fulfilled === "Ongoing") { if (!frm.doc.first_responded_on && frm.doc.agreement_status === "Ongoing") {
time_to_respond = get_time_left(frm.doc.response_by, frm.doc.agreement_fulfilled); time_to_respond = get_time_left(frm.doc.response_by, frm.doc.agreement_status);
} }
var time_to_resolve = get_status(frm.doc.resolution_by_variance); var time_to_resolve = get_status(frm.doc.resolution_by_variance);
if (!frm.doc.resolution_date && frm.doc.agreement_fulfilled === "Ongoing") { if (!frm.doc.resolution_date && frm.doc.agreement_status === "Ongoing") {
time_to_resolve = get_time_left(frm.doc.resolution_by, frm.doc.agreement_fulfilled); time_to_resolve = get_time_left(frm.doc.resolution_by, frm.doc.agreement_status);
} }
frm.dashboard.set_headline_alert( frm.dashboard.set_headline_alert(
@ -219,10 +223,10 @@ function set_time_to_resolve_and_response(frm) {
); );
} }
function get_time_left(timestamp, agreement_fulfilled) { function get_time_left(timestamp, agreement_status) {
const diff = moment(timestamp).diff(moment()); const diff = moment(timestamp).diff(moment());
const diff_display = diff >= 44500 ? moment.duration(diff).humanize() : "Failed"; const diff_display = diff >= 44500 ? moment.duration(diff).humanize() : "Failed";
let indicator = (diff_display == 'Failed' && agreement_fulfilled != "Fulfilled") ? "red" : "green"; let indicator = (diff_display == 'Failed' && agreement_status != "Fulfilled") ? "red" : "green";
return {"diff_display": diff_display, "indicator": indicator}; return {"diff_display": diff_display, "indicator": indicator};
} }

View File

@ -27,17 +27,25 @@
"response_by_variance", "response_by_variance",
"reset_service_level_agreement", "reset_service_level_agreement",
"cb", "cb",
"agreement_fulfilled", "agreement_status",
"resolution_by", "resolution_by",
"resolution_by_variance", "resolution_by_variance",
"service_level_agreement_creation", "service_level_agreement_creation",
"on_hold_since", "on_hold_since",
"total_hold_time", "total_hold_time",
"response", "response",
"mins_to_first_response", "first_response_time",
"first_responded_on", "first_responded_on",
"column_break_26", "column_break_26",
"avg_response_time", "avg_response_time",
"section_break_19",
"resolution_details",
"column_break1",
"opening_date",
"opening_time",
"resolution_date",
"resolution_time",
"user_resolution_time",
"additional_info", "additional_info",
"lead", "lead",
"contact", "contact",
@ -46,23 +54,14 @@
"customer_name", "customer_name",
"project", "project",
"company", "company",
"section_break_19",
"resolution_details",
"column_break1",
"opening_date",
"opening_time",
"resolution_date",
"content_type",
"attachment",
"via_customer_portal", "via_customer_portal",
"resolution_time", "attachment",
"user_resolution_time" "content_type"
], ],
"fields": [ "fields": [
{ {
"fieldname": "subject_section", "fieldname": "subject_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Subject",
"options": "fa fa-flag" "options": "fa fa-flag"
}, },
{ {
@ -158,7 +157,7 @@
"collapsible": 1, "collapsible": 1,
"fieldname": "service_level_section", "fieldname": "service_level_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Service Level" "label": "Service Level Agreement Details"
}, },
{ {
"fieldname": "service_level_agreement", "fieldname": "service_level_agreement",
@ -191,14 +190,7 @@
"collapsible": 1, "collapsible": 1,
"fieldname": "response", "fieldname": "response",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Response" "label": "Response Details"
},
{
"bold": 1,
"fieldname": "mins_to_first_response",
"fieldtype": "Float",
"label": "Mins to First Response",
"read_only": 1
}, },
{ {
"fieldname": "first_responded_on", "fieldname": "first_responded_on",
@ -261,7 +253,7 @@
"collapsible": 1, "collapsible": 1,
"fieldname": "section_break_19", "fieldname": "section_break_19",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Resolution" "label": "Resolution Details"
}, },
{ {
"depends_on": "eval:!doc.__islocal", "depends_on": "eval:!doc.__islocal",
@ -326,28 +318,19 @@
"fieldtype": "Check", "fieldtype": "Check",
"label": "Via Customer Portal" "label": "Via Customer Portal"
}, },
{
"default": "Ongoing",
"depends_on": "eval: doc.service_level_agreement",
"fieldname": "agreement_fulfilled",
"fieldtype": "Select",
"label": "Service Level Agreement Fulfilled",
"options": "Ongoing\nFulfilled\nFailed",
"read_only": 1
},
{ {
"depends_on": "eval: doc.service_level_agreement && doc.status != 'Replied';", "depends_on": "eval: doc.service_level_agreement && doc.status != 'Replied';",
"description": "in hours",
"fieldname": "response_by_variance", "fieldname": "response_by_variance",
"fieldtype": "Float", "fieldtype": "Duration",
"hide_seconds": 1,
"label": "Response By Variance", "label": "Response By Variance",
"read_only": 1 "read_only": 1
}, },
{ {
"depends_on": "eval: doc.service_level_agreement && doc.status != 'Replied';", "depends_on": "eval: doc.service_level_agreement && doc.status != 'Replied';",
"description": "in hours",
"fieldname": "resolution_by_variance", "fieldname": "resolution_by_variance",
"fieldtype": "Float", "fieldtype": "Duration",
"hide_seconds": 1,
"label": "Resolution By Variance", "label": "Resolution By Variance",
"read_only": 1 "read_only": 1
}, },
@ -406,12 +389,28 @@
"fieldtype": "Duration", "fieldtype": "Duration",
"label": "Total Hold Time", "label": "Total Hold Time",
"read_only": 1 "read_only": 1
},
{
"default": "Ongoing",
"depends_on": "eval: doc.service_level_agreement",
"fieldname": "agreement_status",
"fieldtype": "Select",
"label": "Service Level Agreement Status",
"options": "Ongoing\nFulfilled\nFailed",
"read_only": 1
},
{
"bold": 1,
"fieldname": "first_response_time",
"fieldtype": "Duration",
"label": "First Response Time",
"read_only": 1
} }
], ],
"icon": "fa fa-ticket", "icon": "fa fa-ticket",
"idx": 7, "idx": 7,
"links": [], "links": [],
"modified": "2020-06-10 12:47:37.146914", "modified": "2020-08-11 18:49:07.574769",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Support", "module": "Support",
"name": "Issue", "name": "Issue",

View File

@ -61,7 +61,7 @@ class Issue(Document):
if self.status in ["Closed", "Resolved"] and status not in ["Resolved", "Closed"]: if self.status in ["Closed", "Resolved"] and status not in ["Resolved", "Closed"]:
self.resolution_date = frappe.flags.current_time or now_datetime() self.resolution_date = frappe.flags.current_time or now_datetime()
if frappe.db.get_value("Issue", self.name, "agreement_fulfilled") == "Ongoing": if frappe.db.get_value("Issue", self.name, "agreement_status") == "Ongoing":
set_service_level_agreement_variance(issue=self.name) set_service_level_agreement_variance(issue=self.name)
self.update_agreement_status() self.update_agreement_status()
set_resolution_time(issue=self) set_resolution_time(issue=self)
@ -72,7 +72,7 @@ class Issue(Document):
self.resolution_date = None self.resolution_date = None
self.reset_issue_metrics() self.reset_issue_metrics()
# enable SLA and variance on Reopen # enable SLA and variance on Reopen
self.agreement_fulfilled = "Ongoing" self.agreement_status = "Ongoing"
set_service_level_agreement_variance(issue=self.name) set_service_level_agreement_variance(issue=self.name)
self.handle_hold_time(status) self.handle_hold_time(status)
@ -113,39 +113,39 @@ class Issue(Document):
if not self.first_responded_on: if not self.first_responded_on:
response_by = get_expected_time_for(parameter="response", service_level=priority, start_date_time=start_date_time) response_by = get_expected_time_for(parameter="response", service_level=priority, start_date_time=start_date_time)
response_by = add_to_date(response_by, seconds=round(last_hold_time)) response_by = add_to_date(response_by, seconds=round(last_hold_time))
response_by_variance = round(time_diff_in_hours(response_by, now_time)) response_by_variance = round(time_diff_in_seconds(response_by, now_time))
update_values['response_by'] = response_by update_values['response_by'] = response_by
update_values['response_by_variance'] = response_by_variance + (last_hold_time // 3600) update_values['response_by_variance'] = response_by_variance + last_hold_time
resolution_by = get_expected_time_for(parameter="resolution", service_level=priority, start_date_time=start_date_time) resolution_by = get_expected_time_for(parameter="resolution", service_level=priority, start_date_time=start_date_time)
resolution_by = add_to_date(resolution_by, seconds=round(last_hold_time)) resolution_by = add_to_date(resolution_by, seconds=round(last_hold_time))
resolution_by_variance = round(time_diff_in_hours(resolution_by, now_time)) resolution_by_variance = round(time_diff_in_seconds(resolution_by, now_time))
update_values['resolution_by'] = resolution_by update_values['resolution_by'] = resolution_by
update_values['resolution_by_variance'] = resolution_by_variance + (last_hold_time // 3600) update_values['resolution_by_variance'] = resolution_by_variance + last_hold_time
update_values['on_hold_since'] = None update_values['on_hold_since'] = None
self.db_set(update_values) self.db_set(update_values)
def update_agreement_status(self): def update_agreement_status(self):
if self.service_level_agreement and self.agreement_fulfilled == "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 frappe.db.get_value("Issue", self.name, "response_by_variance") < 0 or \
frappe.db.get_value("Issue", self.name, "resolution_by_variance") < 0: frappe.db.get_value("Issue", self.name, "resolution_by_variance") < 0:
self.agreement_fulfilled = "Failed" self.agreement_status = "Failed"
else: else:
self.agreement_fulfilled = "Fulfilled" self.agreement_status = "Fulfilled"
def update_agreement_fulfilled_on_custom_status(self): def update_agreement_status_on_custom_status(self):
""" """
Update Agreement Fulfilled status using Custom Scripts for Custom Issue Status Update Agreement Fulfilled status using Custom Scripts for Custom Issue Status
""" """
if not self.first_responded_on: # first_responded_on set when first reply is sent to customer if not self.first_responded_on: # first_responded_on set when first reply is sent to customer
self.response_by_variance = round(time_diff_in_hours(self.response_by, now_datetime()), 2) self.response_by_variance = round(time_diff_in_seconds(self.response_by, now_datetime()), 2)
if not self.resolution_date: # resolution_date set when issue has been closed if not self.resolution_date: # resolution_date set when issue has been closed
self.resolution_by_variance = round(time_diff_in_hours(self.resolution_by, now_datetime()), 2) self.resolution_by_variance = round(time_diff_in_seconds(self.resolution_by, now_datetime()), 2)
self.agreement_fulfilled = "Fulfilled" if self.response_by_variance > 0 and self.resolution_by_variance > 0 else "Failed" self.agreement_status = "Fulfilled" if self.response_by_variance > 0 and self.resolution_by_variance > 0 else "Failed"
def create_communication(self): def create_communication(self):
communication = frappe.new_doc("Communication") communication = frappe.new_doc("Communication")
@ -172,7 +172,7 @@ class Issue(Document):
replicated_issue = deepcopy(self) replicated_issue = deepcopy(self)
replicated_issue.subject = subject replicated_issue.subject = subject
replicated_issue.issue_split_from = self.name replicated_issue.issue_split_from = self.name
replicated_issue.mins_to_first_response = 0 replicated_issue.first_response_time = 0
replicated_issue.first_responded_on = None replicated_issue.first_responded_on = None
replicated_issue.creation = now_datetime() replicated_issue.creation = now_datetime()
@ -180,7 +180,7 @@ class Issue(Document):
if replicated_issue.service_level_agreement: if replicated_issue.service_level_agreement:
replicated_issue.service_level_agreement_creation = now_datetime() replicated_issue.service_level_agreement_creation = now_datetime()
replicated_issue.service_level_agreement = None replicated_issue.service_level_agreement = None
replicated_issue.agreement_fulfilled = "Ongoing" replicated_issue.agreement_status = "Ongoing"
replicated_issue.response_by = None replicated_issue.response_by = None
replicated_issue.response_by_variance = None replicated_issue.response_by_variance = None
replicated_issue.resolution_by = None replicated_issue.resolution_by = None
@ -241,8 +241,8 @@ class Issue(Document):
self.response_by = get_expected_time_for(parameter="response", service_level=priority, start_date_time=start_date_time) self.response_by = get_expected_time_for(parameter="response", service_level=priority, start_date_time=start_date_time)
self.resolution_by = get_expected_time_for(parameter="resolution", service_level=priority, start_date_time=start_date_time) self.resolution_by = get_expected_time_for(parameter="resolution", service_level=priority, start_date_time=start_date_time)
self.response_by_variance = round(time_diff_in_hours(self.response_by, now_datetime())) self.response_by_variance = round(time_diff_in_seconds(self.response_by, now_datetime()))
self.resolution_by_variance = round(time_diff_in_hours(self.resolution_by, now_datetime())) self.resolution_by_variance = round(time_diff_in_seconds(self.resolution_by, now_datetime()))
def change_service_level_agreement_and_priority(self): def change_service_level_agreement_and_priority(self):
if self.service_level_agreement and frappe.db.exists("Issue", self.name) and \ if self.service_level_agreement and frappe.db.exists("Issue", self.name) and \
@ -271,7 +271,7 @@ class Issue(Document):
self.service_level_agreement_creation = now_datetime() self.service_level_agreement_creation = now_datetime()
self.set_response_and_resolution_time(priority=self.priority, service_level_agreement=self.service_level_agreement) self.set_response_and_resolution_time(priority=self.priority, service_level_agreement=self.service_level_agreement)
self.agreement_fulfilled = "Ongoing" self.agreement_status = "Ongoing"
self.save() self.save()
def reset_issue_metrics(self): def reset_issue_metrics(self):
@ -347,7 +347,7 @@ def get_expected_time_for(parameter, service_level, start_date_time):
def set_service_level_agreement_variance(issue=None): def set_service_level_agreement_variance(issue=None):
current_time = frappe.flags.current_time or now_datetime() current_time = frappe.flags.current_time or now_datetime()
filters = {"status": "Open", "agreement_fulfilled": "Ongoing"} filters = {"status": "Open", "agreement_status": "Ongoing"}
if issue: if issue:
filters = {"name": issue} filters = {"name": issue}
@ -358,13 +358,13 @@ def set_service_level_agreement_variance(issue=None):
variance = round(time_diff_in_hours(doc.response_by, current_time), 2) variance = round(time_diff_in_hours(doc.response_by, current_time), 2)
frappe.db.set_value(dt="Issue", dn=doc.name, field="response_by_variance", val=variance, update_modified=False) frappe.db.set_value(dt="Issue", dn=doc.name, field="response_by_variance", val=variance, update_modified=False)
if variance < 0: if variance < 0:
frappe.db.set_value(dt="Issue", dn=doc.name, field="agreement_fulfilled", val="Failed", update_modified=False) frappe.db.set_value(dt="Issue", dn=doc.name, field="agreement_status", val="Failed", update_modified=False)
if not doc.resolution_date: # resolution_date set when issue has been closed if not doc.resolution_date: # resolution_date set when issue has been closed
variance = round(time_diff_in_hours(doc.resolution_by, current_time), 2) variance = round(time_diff_in_hours(doc.resolution_by, current_time), 2)
frappe.db.set_value(dt="Issue", dn=doc.name, field="resolution_by_variance", val=variance, update_modified=False) frappe.db.set_value(dt="Issue", dn=doc.name, field="resolution_by_variance", val=variance, update_modified=False)
if variance < 0: if variance < 0:
frappe.db.set_value(dt="Issue", dn=doc.name, field="agreement_fulfilled", val="Failed", update_modified=False) frappe.db.set_value(dt="Issue", dn=doc.name, field="agreement_status", val="Failed", update_modified=False)
def set_resolution_time(issue): def set_resolution_time(issue):

View File

@ -73,7 +73,7 @@ class TestIssue(unittest.TestCase):
issue.status = 'Closed' issue.status = 'Closed'
issue.save() issue.save()
self.assertEqual(issue.agreement_fulfilled, 'Fulfilled') self.assertEqual(issue.agreement_status, 'Fulfilled')
def test_issue_metrics(self): def test_issue_metrics(self):
creation = datetime.datetime(2020, 3, 4, 4, 0) creation = datetime.datetime(2020, 3, 4, 4, 0)

View File

@ -0,0 +1,44 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["First Response Time for Issues"] = {
"filters": [
{
"fieldname": "from_date",
"label": __("From Date"),
"fieldtype": "Date",
"reqd": 1,
"default": frappe.datetime.add_days(frappe.datetime.nowdate(), -30)
},
{
"fieldname": "to_date",
"label": __("To Date"),
"fieldtype": "Date",
"reqd": 1,
"default":frappe.datetime.nowdate()
}
],
get_chart_data: function(_columns, result) {
return {
data: {
labels: result.map(d => d[0]),
datasets: [{
name: 'First Response Time',
values: result.map(d => d[1])
}]
},
type: "line",
tooltipOptions: {
formatTooltipY: d => {
let duration_options = {
hide_days: 0,
hide_seconds: 0
};
value = frappe.utils.get_formatted_duration(d, duration_options);
return value;
}
}
}
}
};

View File

@ -0,0 +1,26 @@
{
"add_total_row": 0,
"creation": "2020-08-10 18:12:42.391224",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Test 2",
"modified": "2020-08-10 18:12:42.391224",
"modified_by": "Administrator",
"module": "Support",
"name": "First Response Time for Issues",
"owner": "Administrator",
"prepared_report": 0,
"query": "select date(creation) as creation_date, avg(mins_to_first_response) from tabIssue where creation > '2016-05-01' group by date(creation) order by creation_date;",
"ref_doctype": "Issue",
"report_name": "First Response Time for Issues",
"report_type": "Script Report",
"roles": [
{
"role": "Support Team"
}
]
}

View File

@ -0,0 +1,35 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
def execute(filters=None):
columns = [
{
'fieldname': 'creation_date',
'label': 'Date',
'fieldtype': 'Date',
'width': 300
},
{
'fieldname': 'first_response_time',
'fieldtype': 'Duration',
'label': 'First Response Time',
'width': 300
},
]
data = frappe.db.sql('''
SELECT
date(creation) as creation_date,
avg(first_response_time) as avg_response_time
FROM tabIssue
WHERE
date(creation) between %s and %s
and first_response_time > 0
GROUP BY creation_date
ORDER BY creation_date desc
''', (filters.from_date, filters.to_date))
return columns, data

View File

@ -1,30 +0,0 @@
frappe.query_reports["Minutes to First Response for Issues"] = {
"filters": [
{
"fieldname":"from_date",
"label": __("From Date"),
"fieldtype": "Date",
'reqd': 1,
"default": frappe.datetime.add_days(frappe.datetime.nowdate(), -30)
},
{
"fieldname":"to_date",
"label": __("To Date"),
"fieldtype": "Date",
'reqd': 1,
"default":frappe.datetime.nowdate()
},
],
get_chart_data: function(columns, result) {
return {
data: {
labels: result.map(d => d[0]),
datasets: [{
name: 'Mins to first response',
values: result.map(d => d[1])
}]
},
type: 'line',
}
}
}

View File

@ -1,24 +0,0 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2016-06-14 17:44:26.034112",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 2,
"is_standard": "Yes",
"modified": "2017-02-24 20:06:18.391100",
"modified_by": "Administrator",
"module": "Support",
"name": "Minutes to First Response for Issues",
"owner": "Administrator",
"query": "select date(creation) as creation_date, avg(mins_to_first_response) from tabIssue where creation > '2016-05-01' group by date(creation) order by creation_date;",
"ref_doctype": "Issue",
"report_name": "Minutes to First Response for Issues",
"report_type": "Script Report",
"roles": [
{
"role": "Support Team"
}
]
}

View File

@ -1,28 +0,0 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
def execute(filters=None):
columns = [
{
'fieldname': 'creation_date',
'label': 'Date',
'fieldtype': 'Date'
},
{
'fieldname': 'mins',
'fieldtype': 'Float',
'label': 'Mins to First Response'
},
]
data = frappe.db.sql('''select date(creation) as creation_date,
avg(mins_to_first_response) as mins
from tabIssue
where date(creation) between %s and %s
and mins_to_first_response > 0
group by creation_date order by creation_date desc''', (filters.from_date, filters.to_date))
return columns, data

View File

@ -10,7 +10,10 @@
{{ product_info.price.formatted_price_sales_uom }} {{ product_info.price.formatted_price_sales_uom }}
<small class="text-muted">({{ product_info.price.formatted_price }} / {{ product_info.uom }})</small> <small class="text-muted">({{ product_info.price.formatted_price }} / {{ product_info.uom }})</small>
</h4> </h4>
{% else %}
{{ _("Unit of Measurement") }} : {{ product_info.uom }}
{% endif %} {% endif %}
{% if cart_settings.show_stock_availability %} {% if cart_settings.show_stock_availability %}
<div> <div>
{% if product_info.in_stock == 0 %} {% if product_info.in_stock == 0 %}

View File

@ -14,7 +14,11 @@
</div> </div>
</div> </div>
<div class="col-sm-3 text-right bold"> <div class="col-sm-3 text-right bold">
{{ doc.get_formatted("grand_total") }} {% if doc.doctype == "Quotation" and not doc.docstatus %}
{{ _("Pending") }}
{% else %}
{{ doc.get_formatted("grand_total") }}
{% endif %}
</div> </div>
</div> </div>
<a class="transaction-item-link" href="/{{ pathname }}/{{ doc.name }}">Link</a> <a class="transaction-item-link" href="/{{ pathname }}/{{ doc.name }}">Link</a>

View File

@ -12,22 +12,21 @@
{% endblock %} {% endblock %}
{% block header_actions %} {% block header_actions %}
<div class="dropdown"> <div class="dropdown">
<button class="btn btn-outline-secondary dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> <button class="btn btn-outline-secondary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span>{{ _('Actions') }}</span> <span>{{ _('Actions') }}</span>
<b class="caret"></b> <b class="caret"></b>
</button> </button>
<ul class="dropdown-menu dropdown-menu-right" role="menu"> <ul class="dropdown-menu dropdown-menu-right" role="menu">
{% if doc.doctype == 'Purchase Order' %} {% if doc.doctype == 'Purchase Order' %}
<a class="dropdown-item" href="/api/method/erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice_from_portal?purchase_order_name={{ doc.name }}" data-action="make_purchase_invoice">{{ _("Make Purchase Invoice") }}</a> <a class="dropdown-item" href="/api/method/erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice_from_portal?purchase_order_name={{ doc.name }}" data-action="make_purchase_invoice">{{ _("Make Purchase Invoice") }}</a>
{% endif %} {% endif %}
<a class="dropdown-item" href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}&format={{ print_format }}' <a class="dropdown-item" href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}&format={{ print_format }}'
target="_blank" rel="noopener noreferrer"> target="_blank" rel="noopener noreferrer">
{{ _("Print") }} {{ _("Print") }}
</a> </a>
</ul> </ul>
</div> </div>
{% endblock %} {% endblock %}
{% block page_content %} {% block page_content %}
@ -35,7 +34,11 @@
<div class="row transaction-subheading"> <div class="row transaction-subheading">
<div class="col-6"> <div class="col-6">
<span class="indicator {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "darkgrey") }}"> <span class="indicator {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "darkgrey") }}">
{{ _(doc.get('indicator_title')) or _(doc.status) or _("Submitted") }} {% if doc.doctype == "Quotation" and not doc.docstatus %}
{{ _("Pending") }}
{% else %}
{{ _(doc.get('indicator_title')) or _(doc.status) or _("Submitted") }}
{% endif %}
</span> </span>
</div> </div>
<div class="col-6 text-muted text-right small"> <div class="col-6 text-muted text-right small">
@ -95,7 +98,6 @@
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
<!-- taxes --> <!-- taxes -->
<div class="order-taxes d-flex justify-content-end"> <div class="order-taxes d-flex justify-content-end">
<table> <table>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -25,4 +25,3 @@ All Lead (Open),Alle Bly (Open),
Default Selling Cost Center,Standard Selling Cost center, Default Selling Cost Center,Standard Selling Cost center,
"Attach .csv file with two columns, one for the old name and one for the new name","Vedhæfte .csv fil med to kolonner, en for det gamle navn og et til det nye navn", "Attach .csv file with two columns, one for the old name and one for the new name","Vedhæfte .csv fil med to kolonner, en for det gamle navn og et til det nye navn",
Lead Details,Bly Detaljer, Lead Details,Bly Detaljer,
Lead Id,Bly Id,

1 'Opening' 'Åbning'
25 Default Selling Cost Center Standard Selling Cost center
26 Attach .csv file with two columns, one for the old name and one for the new name Vedhæfte .csv fil med to kolonner, en for det gamle navn og et til det nye navn
27 Lead Details Bly Detaljer
Lead Id Bly Id

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
BOM does not contain any stock item,BOM no contiene ningún ítem de stock, BOM does not contain any stock item,BOM no contiene ningún ítem de stock,
Checkout,Finalizando pedido, Checkout,Finalizando pedido,
Cheques and Deposits incorrectly cleared,Los cheques y depósitos resueltos de forma incorrecta, Cheques and Deposits incorrectly cleared,Los cheques y depósitos resueltos de forma incorrecta,
Child Item should not be a Product Bundle. Please remove item `{0}` and save,Artículo hijo no debe ser un paquete de productos. Por favor remover el artículo `` {0} y guardar,
Get Items from Product Bundle,Obtener Ítems de Paquete de Productos, Get Items from Product Bundle,Obtener Ítems de Paquete de Productos,
Gross Profit / Loss,Ganancia / Pérdida Bruta, Gross Profit / Loss,Ganancia / Pérdida Bruta,
Guardian1 Mobile No,Número de Móvil de Guardián 1, Guardian1 Mobile No,Número de Móvil de Guardián 1,

1 BOM does not contain any stock item BOM no contiene ningún ítem de stock
2 Checkout Finalizando pedido
3 Cheques and Deposits incorrectly cleared Los cheques y depósitos resueltos de forma incorrecta
Child Item should not be a Product Bundle. Please remove item `{0}` and save Artículo hijo no debe ser un paquete de productos. Por favor remover el artículo `` {0} y guardar
4 Get Items from Product Bundle Obtener Ítems de Paquete de Productos
5 Gross Profit / Loss Ganancia / Pérdida Bruta
6 Guardian1 Mobile No Número de Móvil de Guardián 1

View File

@ -1,3 +1,4 @@
Barcode {0} is not a valid {1} code,El código de barras {0} no es un código válido {1}, Barcode {0} is not a valid {1} code,El código de barras {0} no es un código válido {1},
Clear filters,Limpiar Filtros, Clear filters,Limpiar Filtros,
{0} does not have a Healthcare Practitioner Schedule. Add it in Healthcare Practitioner master,{0} no tiene agenda del profesional médico . Añádelo al médico correspondiente., {0} does not have a Healthcare Practitioner Schedule. Add it in Healthcare Practitioner master,{0} no tiene agenda del profesional médico . Añádelo al médico correspondiente.,
Disabled,Deshabilitado,

1 Barcode {0} is not a valid {1} code El código de barras {0} no es un código válido {1}
2 Clear filters Limpiar Filtros
3 {0} does not have a Healthcare Practitioner Schedule. Add it in Healthcare Practitioner master {0} no tiene agenda del profesional médico . Añádelo al médico correspondiente.
4 Disabled Deshabilitado

View File

@ -1,7 +1,6 @@
Cannot change Variant properties after stock transaction. You will have to make a new Item to do this.,No se pueden cambiar las propiedades de Variantes después de la transacción de inventario. Deberá crear un nuevo artículo para hacer esto., Cannot change Variant properties after stock transaction. You will have to make a new Item to do this.,No se pueden cambiar las propiedades de Variantes después de la transacción de inventario. Deberá crear un nuevo artículo para hacer esto.,
Cash Flow Statement,Estado de Flujo de Efectivo, Cash Flow Statement,Estado de Flujo de Efectivo,
Chart of Cost Centers,Gráfico de Centro de costos, Chart of Cost Centers,Gráfico de Centro de costos,
"Company, Payment Account, From Date and To Date is mandatory","Empresa, cuenta de pago, fecha de inicio y fecha final son obligatorios",
Financial Statements,Estados Financieros, Financial Statements,Estados Financieros,
Gain/Loss on Asset Disposal,Ganancia/Pérdida por la venta de activos, Gain/Loss on Asset Disposal,Ganancia/Pérdida por la venta de activos,
Gross Purchase Amount is mandatory,El Importe Bruto de Compra es obligatorio, Gross Purchase Amount is mandatory,El Importe Bruto de Compra es obligatorio,

1 Cannot change Variant properties after stock transaction. You will have to make a new Item to do this. No se pueden cambiar las propiedades de Variantes después de la transacción de inventario. Deberá crear un nuevo artículo para hacer esto.
2 Cash Flow Statement Estado de Flujo de Efectivo
3 Chart of Cost Centers Gráfico de Centro de costos
Company, Payment Account, From Date and To Date is mandatory Empresa, cuenta de pago, fecha de inicio y fecha final son obligatorios
4 Financial Statements Estados Financieros
5 Gain/Loss on Asset Disposal Ganancia/Pérdida por la venta de activos
6 Gross Purchase Amount is mandatory El Importe Bruto de Compra es obligatorio

View File

@ -129,7 +129,6 @@ Enable / disable currencies.,Habilitar / Deshabilitar el tipo de monedas,
Expected Delivery Date,Fecha Esperada de Envio, Expected Delivery Date,Fecha Esperada de Envio,
Expected End Date,Fecha de finalización prevista, Expected End Date,Fecha de finalización prevista,
Expense Account,Cuenta de gastos, Expense Account,Cuenta de gastos,
Expense or Difference account is mandatory for Item {0} as it impacts overall stock value,"Cuenta de Gastos o Diferencia es obligatorio para el elemento {0} , ya que impacta el valor del stock",
Expenses Included In Valuation,Gastos dentro de la valoración, Expenses Included In Valuation,Gastos dentro de la valoración,
Feedback,Comentarios, Feedback,Comentarios,
Fetch exploded BOM (including sub-assemblies),Mezclar Solicitud de Materiales (incluyendo subconjuntos ), Fetch exploded BOM (including sub-assemblies),Mezclar Solicitud de Materiales (incluyendo subconjuntos ),
@ -163,7 +162,6 @@ Item Code required at Row No {0},Código del producto requerido en la fila No. {
Item Description,Descripción del Artículo, Item Description,Descripción del Artículo,
Item Group,Grupo de artículos, Item Group,Grupo de artículos,
Item Tax Row {0} must have account of type Tax or Income or Expense or Chargeable,"Campo de impuesto del producto {0} debe tener un tipo de cuenta de impuestos, ingresos, cargos o gastos", Item Tax Row {0} must have account of type Tax or Income or Expense or Chargeable,"Campo de impuesto del producto {0} debe tener un tipo de cuenta de impuestos, ingresos, cargos o gastos",
Item or Warehouse for row {0} does not match Material Request,Artículo o Bodega para la fila {0} no coincide Solicitud de material,
Item {0} must be a Sub-contracted Item,El elemento {0} debe ser un producto sub-contratado, Item {0} must be a Sub-contracted Item,El elemento {0} debe ser un producto sub-contratado,
Item {0}: Ordered qty {1} cannot be less than minimum order qty {2} (defined in Item).,El elemento {0}: Con la cantidad ordenada {1} no puede ser menor que el pedido mínimo {2} (definido en el producto)., Item {0}: Ordered qty {1} cannot be less than minimum order qty {2} (defined in Item).,El elemento {0}: Con la cantidad ordenada {1} no puede ser menor que el pedido mínimo {2} (definido en el producto).,
Journal Entry,Asientos Contables, Journal Entry,Asientos Contables,
@ -210,8 +208,6 @@ New Customer Revenue,Ingresos de nuevo cliente,
New Customers,Clientes Nuevos, New Customers,Clientes Nuevos,
New Serial No cannot have Warehouse. Warehouse must be set by Stock Entry or Purchase Receipt,El numero de serie no tiene almacén. el almacén debe establecerse por entradas de stock o recibos de compra, New Serial No cannot have Warehouse. Warehouse must be set by Stock Entry or Purchase Receipt,El numero de serie no tiene almacén. el almacén debe establecerse por entradas de stock o recibos de compra,
Next,Próximo, Next,Próximo,
No address added yet.,No se ha añadido ninguna dirección todavía.,
No contacts added yet.,No se han añadido contactos todavía,
Nos,Números, Nos,Números,
Not Started,Sin comenzar, Not Started,Sin comenzar,
Note: This Cost Center is a Group. Cannot make accounting entries against groups.,Nota: Este centro de costos es un grupo. No se pueden crear asientos contables en los grupos., Note: This Cost Center is a Group. Cannot make accounting entries against groups.,Nota: Este centro de costos es un grupo. No se pueden crear asientos contables en los grupos.,
@ -235,8 +231,6 @@ Period Closing Entry,Entradas de cierre de período,
Periodicity,Periodicidad, Periodicity,Periodicidad,
Piecework,Pieza de trabajo, Piecework,Pieza de trabajo,
Plan for maintenance visits.,Plan para las visitas de mantenimiento., Plan for maintenance visits.,Plan para las visitas de mantenimiento.,
Please contact to the user who have Sales Master Manager {0} role,"Por favor, póngase en contacto con el usuario con función de Gerente de Ventas {0}",
Please create Customer from Lead {0},"Por favor, cree Cliente de la Oportunidad {0}",
Please enter 'Is Subcontracted' as Yes or No,"Por favor, introduzca si 'Es Subcontratado' o no", Please enter 'Is Subcontracted' as Yes or No,"Por favor, introduzca si 'Es Subcontratado' o no",
Please enter Item Code to get batch no,"Por favor, ingrese el código del producto para obtener el No. de lote", Please enter Item Code to get batch no,"Por favor, ingrese el código del producto para obtener el No. de lote",
Please enter default currency in Company Master,"Por favor, ingrese la moneda por defecto en la compañía principal", Please enter default currency in Company Master,"Por favor, ingrese la moneda por defecto en la compañía principal",
@ -304,7 +298,6 @@ Root cannot have a parent cost center,Raíz no puede tener un centro de costes d
Round Off,Redondear, Round Off,Redondear,
Row # {0}: ,Fila # {0}:, Row # {0}: ,Fila # {0}:,
Row # {0}: Cannot return more than {1} for Item {2},Fila # {0}: No se puede devolver más de {1} para el artículo {2}, Row # {0}: Cannot return more than {1} for Item {2},Fila # {0}: No se puede devolver más de {1} para el artículo {2},
Row # {0}: Returned Item {1} does not exists in {2} {3},Fila # {0}: El artículo vuelto {1} no existe en {2} {3},
Row #{0}: Please specify Serial No for Item {1},"Fila # {0}: Por favor, especifique No de Serie de artículos {1}", Row #{0}: Please specify Serial No for Item {1},"Fila # {0}: Por favor, especifique No de Serie de artículos {1}",
Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) ,Fila # {0}: Tasa debe ser el mismo que {1}: {2} ({3} / {4}), Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) ,Fila # {0}: Tasa debe ser el mismo que {1}: {2} ({3} / {4}),
Row #{0}: Rejected Qty can not be entered in Purchase Return,Fila # {0}: Rechazado Cantidad no se puede introducir en la Compra de Retorno, Row #{0}: Rejected Qty can not be entered in Purchase Return,Fila # {0}: Rechazado Cantidad no se puede introducir en la Compra de Retorno,
@ -519,9 +512,11 @@ cannot be greater than 100,No puede ser mayor que 100,
{0} {1} not in any active Fiscal Year.,{0} {1} no en algún año fiscal activo., {0} {1} not in any active Fiscal Year.,{0} {1} no en algún año fiscal activo.,
{0} {1}: Cost Center is mandatory for Item {2},{0} {1}: 'Centro de Costos' es obligatorio para el producto {2}, {0} {1}: Cost Center is mandatory for Item {2},{0} {1}: 'Centro de Costos' es obligatorio para el producto {2},
{0}: {1} not found in Invoice Details table,{0}: {1} no se encuentra en el detalle de la factura, {0}: {1} not found in Invoice Details table,{0}: {1} no se encuentra en el detalle de la factura,
Email Settings,Configuración del correo electrónico,
Import,Importación, Import,Importación,
Shop,Tienda, Shop,Tienda,
Subsidiary,Filial, Subsidiary,Filial,
There were errors while sending email. Please try again.,"Hubo errores al enviar el correo electrónico. Por favor, inténtelo de nuevo.",
Print Heading,Título de impresión, Print Heading,Título de impresión,
Add Child,Agregar subcuenta, Add Child,Agregar subcuenta,
Company,Compañía(s), Company,Compañía(s),
@ -714,7 +709,6 @@ Appraisal Template Goal,Objetivo Plantilla de Evaluación,
Leave Application,Solicitud de Vacaciones, Leave Application,Solicitud de Vacaciones,
Leave Block List,Lista de Bloqueo de Vacaciones, Leave Block List,Lista de Bloqueo de Vacaciones,
Days for which Holidays are blocked for this department.,Días para los que Días Feriados se bloquean para este departamento ., Days for which Holidays are blocked for this department.,Días para los que Días Feriados se bloquean para este departamento .,
Leave Approvers,Supervisores de Vacaciones,
Leave Approver,Supervisor de Vacaciones, Leave Approver,Supervisor de Vacaciones,
"System User (login) ID. If set, it will become default for all HR forms.","Usuario del Sistema (login )ID. Si se establece , será por defecto para todas las formas de Recursos Humanos.", "System User (login) ID. If set, it will become default for all HR forms.","Usuario del Sistema (login )ID. Si se establece , será por defecto para todas las formas de Recursos Humanos.",
Contract End Date,Fecha Fin de Contrato, Contract End Date,Fecha Fin de Contrato,
@ -851,7 +845,6 @@ Contribution (%),Contribución (%),
Settings for Selling Module,Ajustes para vender Módulo, Settings for Selling Module,Ajustes para vender Módulo,
Customer Naming By,Naming Cliente Por, Customer Naming By,Naming Cliente Por,
Campaign Naming By,Nombramiento de la Campaña Por, Campaign Naming By,Nombramiento de la Campaña Por,
Sales Order Required,Orden de Ventas Requerida,
Allow user to edit Price List Rate in transactions,Permitir al usuario editar Precio de Lista en las transacciones, Allow user to edit Price List Rate in transactions,Permitir al usuario editar Precio de Lista en las transacciones,
All Sales Partner Contact,Todo Punto de Contacto de Venta, All Sales Partner Contact,Todo Punto de Contacto de Venta,
All Sales Person,Todos Ventas de Ventas, All Sales Person,Todos Ventas de Ventas,
@ -1009,16 +1002,11 @@ Item Prices,Precios de los Artículos,
Item Shortage Report,Reportar carencia de producto, Item Shortage Report,Reportar carencia de producto,
Itemwise Recommended Reorder Level,Nivel recomendado de re-ordenamiento de producto, Itemwise Recommended Reorder Level,Nivel recomendado de re-ordenamiento de producto,
Lead Details,Iniciativas, Lead Details,Iniciativas,
Lead Id,Iniciativa ID,
Material Requests for which Supplier Quotations are not created,Solicitudes de Productos sin Cotizaciones Creadas, Material Requests for which Supplier Quotations are not created,Solicitudes de Productos sin Cotizaciones Creadas,
Monthly Attendance Sheet,Hoja de Asistencia Mensual, Monthly Attendance Sheet,Hoja de Asistencia Mensual,
Ordered Items To Be Delivered,Artículos pedidos para ser entregados,
Qty to Deliver,Cantidad para Ofrecer, Qty to Deliver,Cantidad para Ofrecer,
Profit and Loss Statement,Estado de Pérdidas y Ganancias, Profit and Loss Statement,Estado de Pérdidas y Ganancias,
Purchase Order Items To Be Billed,Ordenes de Compra por Facturar,
Purchase Order Items To Be Received,Productos de la Orden de Compra a ser Recibidos,
Quotation Trends,Tendencias de Cotización, Quotation Trends,Tendencias de Cotización,
Requested Items To Be Ordered,Solicitud de Productos Aprobados,
Requested Items To Be Transferred,Artículos solicitados para ser transferido, Requested Items To Be Transferred,Artículos solicitados para ser transferido,
Sales Partners Commission,Comisiones de Ventas, Sales Partners Commission,Comisiones de Ventas,
Sales Person-wise Transaction Summary,Resumen de Transacción por Vendedor, Sales Person-wise Transaction Summary,Resumen de Transacción por Vendedor,

1 'Based On' and 'Group By' can not be same "Basado en" y "Agrupar por" no pueden ser el mismo
129 Expected Delivery Date Fecha Esperada de Envio
130 Expected End Date Fecha de finalización prevista
131 Expense Account Cuenta de gastos
Expense or Difference account is mandatory for Item {0} as it impacts overall stock value Cuenta de Gastos o Diferencia es obligatorio para el elemento {0} , ya que impacta el valor del stock
132 Expenses Included In Valuation Gastos dentro de la valoración
133 Feedback Comentarios
134 Fetch exploded BOM (including sub-assemblies) Mezclar Solicitud de Materiales (incluyendo subconjuntos )
162 Item Description Descripción del Artículo
163 Item Group Grupo de artículos
164 Item Tax Row {0} must have account of type Tax or Income or Expense or Chargeable Campo de impuesto del producto {0} debe tener un tipo de cuenta de impuestos, ingresos, cargos o gastos
Item or Warehouse for row {0} does not match Material Request Artículo o Bodega para la fila {0} no coincide Solicitud de material
165 Item {0} must be a Sub-contracted Item El elemento {0} debe ser un producto sub-contratado
166 Item {0}: Ordered qty {1} cannot be less than minimum order qty {2} (defined in Item). El elemento {0}: Con la cantidad ordenada {1} no puede ser menor que el pedido mínimo {2} (definido en el producto).
167 Journal Entry Asientos Contables
208 New Customers Clientes Nuevos
209 New Serial No cannot have Warehouse. Warehouse must be set by Stock Entry or Purchase Receipt El numero de serie no tiene almacén. el almacén debe establecerse por entradas de stock o recibos de compra
210 Next Próximo
No address added yet. No se ha añadido ninguna dirección todavía.
No contacts added yet. No se han añadido contactos todavía
211 Nos Números
212 Not Started Sin comenzar
213 Note: This Cost Center is a Group. Cannot make accounting entries against groups. Nota: Este centro de costos es un grupo. No se pueden crear asientos contables en los grupos.
231 Periodicity Periodicidad
232 Piecework Pieza de trabajo
233 Plan for maintenance visits. Plan para las visitas de mantenimiento.
Please contact to the user who have Sales Master Manager {0} role Por favor, póngase en contacto con el usuario con función de Gerente de Ventas {0}
Please create Customer from Lead {0} Por favor, cree Cliente de la Oportunidad {0}
234 Please enter 'Is Subcontracted' as Yes or No Por favor, introduzca si 'Es Subcontratado' o no
235 Please enter Item Code to get batch no Por favor, ingrese el código del producto para obtener el No. de lote
236 Please enter default currency in Company Master Por favor, ingrese la moneda por defecto en la compañía principal
298 Round Off Redondear
299 Row # {0}: Fila # {0}:
300 Row # {0}: Cannot return more than {1} for Item {2} Fila # {0}: No se puede devolver más de {1} para el artículo {2}
Row # {0}: Returned Item {1} does not exists in {2} {3} Fila # {0}: El artículo vuelto {1} no existe en {2} {3}
301 Row #{0}: Please specify Serial No for Item {1} Fila # {0}: Por favor, especifique No de Serie de artículos {1}
302 Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) Fila # {0}: Tasa debe ser el mismo que {1}: {2} ({3} / {4})
303 Row #{0}: Rejected Qty can not be entered in Purchase Return Fila # {0}: Rechazado Cantidad no se puede introducir en la Compra de Retorno
512 {0} {1} not in any active Fiscal Year. {0} {1} no en algún año fiscal activo.
513 {0} {1}: Cost Center is mandatory for Item {2} {0} {1}: 'Centro de Costos' es obligatorio para el producto {2}
514 {0}: {1} not found in Invoice Details table {0}: {1} no se encuentra en el detalle de la factura
515 Email Settings Configuración del correo electrónico
516 Import Importación
517 Shop Tienda
518 Subsidiary Filial
519 There were errors while sending email. Please try again. Hubo errores al enviar el correo electrónico. Por favor, inténtelo de nuevo.
520 Print Heading Título de impresión
521 Add Child Agregar subcuenta
522 Company Compañía(s)
709 Leave Application Solicitud de Vacaciones
710 Leave Block List Lista de Bloqueo de Vacaciones
711 Days for which Holidays are blocked for this department. Días para los que Días Feriados se bloquean para este departamento .
Leave Approvers Supervisores de Vacaciones
712 Leave Approver Supervisor de Vacaciones
713 System User (login) ID. If set, it will become default for all HR forms. Usuario del Sistema (login )ID. Si se establece , será por defecto para todas las formas de Recursos Humanos.
714 Contract End Date Fecha Fin de Contrato
845 Settings for Selling Module Ajustes para vender Módulo
846 Customer Naming By Naming Cliente Por
847 Campaign Naming By Nombramiento de la Campaña Por
Sales Order Required Orden de Ventas Requerida
848 Allow user to edit Price List Rate in transactions Permitir al usuario editar Precio de Lista en las transacciones
849 All Sales Partner Contact Todo Punto de Contacto de Venta
850 All Sales Person Todos Ventas de Ventas
1002 Item Shortage Report Reportar carencia de producto
1003 Itemwise Recommended Reorder Level Nivel recomendado de re-ordenamiento de producto
1004 Lead Details Iniciativas
Lead Id Iniciativa ID
1005 Material Requests for which Supplier Quotations are not created Solicitudes de Productos sin Cotizaciones Creadas
1006 Monthly Attendance Sheet Hoja de Asistencia Mensual
Ordered Items To Be Delivered Artículos pedidos para ser entregados
1007 Qty to Deliver Cantidad para Ofrecer
1008 Profit and Loss Statement Estado de Pérdidas y Ganancias
Purchase Order Items To Be Billed Ordenes de Compra por Facturar
Purchase Order Items To Be Received Productos de la Orden de Compra a ser Recibidos
1009 Quotation Trends Tendencias de Cotización
Requested Items To Be Ordered Solicitud de Productos Aprobados
1010 Requested Items To Be Transferred Artículos solicitados para ser transferido
1011 Sales Partners Commission Comisiones de Ventas
1012 Sales Person-wise Transaction Summary Resumen de Transacción por Vendedor

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
Ordered Qty,Quantité commandée, Ordered Qty,Quantité commandée,
Price List Rate,Taux de la Liste de Prix, Price List Rate,Taux de la Liste de Prix,
{0} {1}: 'Profit and Loss' type account {2} not allowed in Opening Entry,{0} {1}: Le compte {2} de type 'Profit et Perte' n'est pas admis dans une Entrée d'Ouverture, {0} {1}: 'Profit and Loss' type account {2} not allowed in Opening Entry,{0} {1}: Le compte {2} de type 'Profit et Perte' n'est pas admis dans une Entrée d'Ouverture,
{0} {1}: Account {2} cannot be a Group,{0} {1}: Le compte {2} ne peut pas être un Groupe,
{0} {1}: Account {2} does not belong to Company {3},{0} {1}: Le compte {2} ne fait pas partie de la Société {3}, {0} {1}: Account {2} does not belong to Company {3},{0} {1}: Le compte {2} ne fait pas partie de la Société {3},
{0} {1}: Account {2} is inactive,{0} {1}: Le compte {2} est inactif, {0} {1}: Account {2} is inactive,{0} {1}: Le compte {2} est inactif,
{0} {1}: Accounting Entry for {2} can only be made in currency: {3},{0} {1}: L'entrée comptable pour {2} ne peut être faite qu'en devise: {3}, {0} {1}: Accounting Entry for {2} can only be made in currency: {3},{0} {1}: L'entrée comptable pour {2} ne peut être faite qu'en devise: {3},

1 Ordered Qty Quantité commandée
2 Price List Rate Taux de la Liste de Prix
3 {0} {1}: 'Profit and Loss' type account {2} not allowed in Opening Entry {0} {1}: Le compte {2} de type 'Profit et Perte' n'est pas admis dans une Entrée d'Ouverture
{0} {1}: Account {2} cannot be a Group {0} {1}: Le compte {2} ne peut pas être un Groupe
4 {0} {1}: Account {2} does not belong to Company {3} {0} {1}: Le compte {2} ne fait pas partie de la Société {3}
5 {0} {1}: Account {2} is inactive {0} {1}: Le compte {2} est inactif
6 {0} {1}: Accounting Entry for {2} can only be made in currency: {3} {0} {1}: L'entrée comptable pour {2} ne peut être faite qu'en devise: {3}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More