Merge branch 'hotfix'

This commit is contained in:
Sahil Khan
2019-04-29 16:35:41 +05:30
84 changed files with 5743 additions and 1091 deletions

View File

@@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides from erpnext.hooks import regional_overrides
from frappe.utils import getdate from frappe.utils import getdate
__version__ = '11.1.22' __version__ = '11.1.23'
def get_default_company(user=None): def get_default_company(user=None):
'''Get default company for user''' '''Get default company for user'''

View File

@@ -1,6 +1,6 @@
{ {
"country_code": "de", "country_code": "de",
"name": "Germany - Kontenplan SKR04", "name": "SKR04 ohne Kontonummern",
"tree": { "tree": {
"Bilanz - Aktiva": { "Bilanz - Aktiva": {
"Anlageverm\u00f6gen": { "Anlageverm\u00f6gen": {
@@ -1384,7 +1384,6 @@
"Diskontertr\u00e4ge": {}, "Diskontertr\u00e4ge": {},
"Diskontertr\u00e4ge aus verbundenen Unternehmen": {}, "Diskontertr\u00e4ge aus verbundenen Unternehmen": {},
"Laufende Ertr\u00e4ge aus Anteilen an Kapitalgesellschaften 100% / 50% steuerfrei": {}, "Laufende Ertr\u00e4ge aus Anteilen an Kapitalgesellschaften 100% / 50% steuerfrei": {},
"Laufende Ertr\u00e4ge aus Anteilen an Kapitalgesellschaften 100% / 50% steuerfrei": {},
"Sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge 2": {}, "Sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge 2": {},
"Sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge aus verbundenen Unternehmen": {}, "Sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge aus verbundenen Unternehmen": {},
"Sonstige Zinsertr\u00e4ge": {}, "Sonstige Zinsertr\u00e4ge": {},

View File

@@ -21,11 +21,39 @@ class BankAccount(Document):
def validate(self): def validate(self):
self.validate_company() self.validate_company()
self.validate_iban()
def validate_company(self): def validate_company(self):
if self.is_company_account and not self.company: if self.is_company_account and not self.company:
frappe.throw(_("Company is manadatory for company account")) frappe.throw(_("Company is manadatory for company account"))
def validate_iban(self):
'''
Algorithm: https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN
'''
# IBAN field is optional
if not self.iban:
return
def encode_char(c):
# Position in the alphabet (A=1, B=2, ...) plus nine
return str(9 + ord(c) - 64)
# remove whitespaces, upper case to get the right number from ord()
iban = ''.join(self.iban.split(' ')).upper()
# Move country code and checksum from the start to the end
flipped = iban[4:] + iban[:4]
# Encode characters as numbers
encoded = [encode_char(c) if ord(c) >= 65 and ord(c) <= 90 else c for c in flipped]
to_check = int(''.join(encoded))
if to_check % 97 != 1:
frappe.throw(_('IBAN is not valid'))
@frappe.whitelist() @frappe.whitelist()
def make_bank_account(doctype, docname): def make_bank_account(doctype, docname):
doc = frappe.new_doc("Bank Account") doc = frappe.new_doc("Bank Account")

View File

@@ -4,9 +4,46 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _
from frappe import ValidationError
import unittest import unittest
# test_records = frappe.get_test_records('Bank Account') # test_records = frappe.get_test_records('Bank Account')
class TestBankAccount(unittest.TestCase): class TestBankAccount(unittest.TestCase):
pass
def test_validate_iban(self):
valid_ibans = [
'GB82 WEST 1234 5698 7654 32',
'DE91 1000 0000 0123 4567 89',
'FR76 3000 6000 0112 3456 7890 189'
]
invalid_ibans = [
# wrong checksum (3rd place)
'GB72 WEST 1234 5698 7654 32',
'DE81 1000 0000 0123 4567 89',
'FR66 3000 6000 0112 3456 7890 189'
]
bank_account = frappe.get_doc({'doctype':'Bank Account'})
try:
bank_account.validate_iban()
except AttributeError:
msg = _('BankAccount.validate_iban() failed for empty IBAN')
self.fail(msg=msg)
for iban in valid_ibans:
bank_account.iban = iban
try:
bank_account.validate_iban()
except ValidationError:
msg = _('BankAccount.validate_iban() failed for valid IBAN {}'.format(iban))
self.fail(msg=msg)
for not_iban in invalid_ibans:
bank_account.iban = not_iban
msg = _('BankAccount.validate_iban() accepted invalid IBAN {}'.format(not_iban))
with self.assertRaises(ValidationError, msg=msg):
bank_account.validate_iban()

View File

@@ -45,15 +45,19 @@ def create_bank_entries(columns, data, bank_account):
fields.update({key: d[int(value)-1]}) fields.update({key: d[int(value)-1]})
bank_transaction = frappe.get_doc({ try:
"doctype": "Bank Transaction" bank_transaction = frappe.get_doc({
}) "doctype": "Bank Transaction"
bank_transaction.update(fields) })
bank_transaction.date = getdate(parse_date(bank_transaction.date)) bank_transaction.update(fields)
bank_transaction.bank_account = bank_account bank_transaction.date = getdate(parse_date(bank_transaction.date))
bank_transaction.insert() bank_transaction.bank_account = bank_account
bank_transaction.submit() bank_transaction.insert()
count = count + 1 bank_transaction.submit()
count = count + 1
except Exception as e:
frappe.throw(e)
frappe.log_error(frappe.get_traceback())
return count return count

View File

@@ -285,6 +285,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
is_paid: function() { is_paid: function() {
hide_fields(this.frm.doc); hide_fields(this.frm.doc);
if(cint(this.frm.doc.is_paid)) { if(cint(this.frm.doc.is_paid)) {
this.frm.set_value("allocate_advances_automatically", 0);
if(!this.frm.doc.company) { if(!this.frm.doc.company) {
this.frm.set_value("is_paid", 0) this.frm.set_value("is_paid", 0)
frappe.msgprint(__("Please specify Company to proceed")); frappe.msgprint(__("Please specify Company to proceed"));

View File

@@ -356,6 +356,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
set_pos_data: function() { set_pos_data: function() {
if(this.frm.doc.is_pos) { if(this.frm.doc.is_pos) {
this.frm.set_value("allocate_advances_automatically", 0);
if(!this.frm.doc.company) { if(!this.frm.doc.company) {
this.frm.set_value("is_pos", 0); this.frm.set_value("is_pos", 0);
frappe.msgprint(__("Please specify Company to proceed")); frappe.msgprint(__("Please specify Company to proceed"));

View File

@@ -33,10 +33,12 @@ def reconcile(bank_transaction, payment_doctype, payment_name):
return 'reconciled' return 'reconciled'
def add_payment_to_transaction(transaction, payment_entry, gl_entry): def add_payment_to_transaction(transaction, payment_entry, gl_entry):
gl_amount, transaction_amount = (gl_entry.credit, transaction.debit) if gl_entry.credit > 0 else (gl_entry.debit, transaction.credit)
allocated_amount = gl_amount if gl_amount <= transaction_amount else transaction_amount
transaction.append("payment_entries", { transaction.append("payment_entries", {
"payment_document": payment_entry.doctype, "payment_document": payment_entry.doctype,
"payment_entry": payment_entry.name, "payment_entry": payment_entry.name,
"allocated_amount": gl_entry.credit if gl_entry.credit > 0 else gl_entry.debit "allocated_amount": allocated_amount
}) })
transaction.save() transaction.save()
@@ -274,7 +276,7 @@ def check_amount_vs_description(amount_matching, description_matching):
result.append(am_match) result.append(am_match)
continue continue
if hasattr(am_match, "reference_no") and hasattr(des_match, "reference_no"): if "reference_no" in am_match and "reference_no" in des_match:
if difflib.SequenceMatcher(lambda x: x == " ", am_match["reference_no"], des_match["reference_no"]).ratio() > 70: if difflib.SequenceMatcher(lambda x: x == " ", am_match["reference_no"], des_match["reference_no"]).ratio() > 70:
if am_match not in result: if am_match not in result:
result.append(am_match) result.append(am_match)

View File

@@ -359,7 +359,8 @@ def set_gl_entries_by_account(
"from_date": from_date, "from_date": from_date,
"to_date": to_date, "to_date": to_date,
"cost_center": filters.cost_center, "cost_center": filters.cost_center,
"project": filters.project "project": filters.project,
"finance_book": filters.get("finance_book")
}, },
as_dict=True) as_dict=True)

View File

@@ -23,6 +23,12 @@ frappe.query_reports["Gross Profit"] = {
"fieldtype": "Date", "fieldtype": "Date",
"default": frappe.defaults.get_user_default("year_end_date") "default": frappe.defaults.get_user_default("year_end_date")
}, },
{
"fieldname":"sales_invoice",
"label": __("Sales Invoice"),
"fieldtype": "Link",
"options": "Sales Invoice"
},
{ {
"fieldname":"group_by", "fieldname":"group_by",
"label": __("Group By"), "label": __("Group By"),

View File

@@ -302,6 +302,12 @@ class GrossProfitGenerator(object):
sales_person_cols = "" sales_person_cols = ""
sales_team_table = "" sales_team_table = ""
if self.filters.get("sales_invoice"):
conditions += " and `tabSales Invoice`.name = %(sales_invoice)s"
if self.filters.get("item_code"):
conditions += " and `tabSales Invoice Item`.item_code = %(item_code)s"
self.si_list = frappe.db.sql(""" self.si_list = frappe.db.sql("""
select select
`tabSales Invoice Item`.parenttype, `tabSales Invoice Item`.parent, `tabSales Invoice Item`.parenttype, `tabSales Invoice Item`.parent,

View File

@@ -135,3 +135,22 @@ def get_appropriate_company(filters):
company = get_default_company() company = get_default_company()
return company return company
@frappe.whitelist()
def get_invoiced_item_gross_margin(sales_invoice=None, item_code=None, company=None):
from erpnext.accounts.report.gross_profit.gross_profit import GrossProfitGenerator
sales_invoice = sales_invoice or frappe.form_dict.get('sales_invoice')
item_code = item_code or frappe.form_dict.get('item_code')
company = company or frappe.get_cached_value("Sales Invoice", sales_invoice, 'company')
filters = {
'sales_invoice': sales_invoice,
'item_code': item_code,
'company': company,
'group_by': 'Invoice'
}
gross_profit_data = GrossProfitGenerator(filters)
return gross_profit_data.grouped_data

View File

@@ -296,6 +296,12 @@ frappe.ui.form.on('Asset', {
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation); frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
}, },
gross_purchase_amount: function(frm) {
frm.doc.finance_books.forEach(d => {
frm.events.set_depreciation_rate(frm, d);
})
},
set_depreciation_rate: function(frm, row) { set_depreciation_rate: function(frm, row) {
if (row.total_number_of_depreciations && row.frequency_of_depreciation) { if (row.total_number_of_depreciations && row.frequency_of_depreciation) {
frappe.call({ frappe.call({

View File

@@ -101,7 +101,7 @@ class Asset(AccountsController):
def set_depreciation_rate(self): def set_depreciation_rate(self):
for d in self.get("finance_books"): for d in self.get("finance_books"):
d.rate_of_depreciation = self.get_depreciation_rate(d) d.rate_of_depreciation = self.get_depreciation_rate(d, on_validate=True)
def make_depreciation_schedule(self): def make_depreciation_schedule(self):
depreciation_method = [d.depreciation_method for d in self.finance_books] depreciation_method = [d.depreciation_method for d in self.finance_books]
@@ -125,7 +125,7 @@ class Asset(AccountsController):
no_of_depreciations * cint(d.frequency_of_depreciation)) no_of_depreciations * cint(d.frequency_of_depreciation))
total_days = date_diff(end_date, self.available_for_use_date) total_days = date_diff(end_date, self.available_for_use_date)
rate_per_day = value_after_depreciation / total_days rate_per_day = (value_after_depreciation - d.get("expected_value_after_useful_life")) / total_days
number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \ number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \
cint(self.number_of_depreciations_booked) cint(self.number_of_depreciations_booked)
@@ -291,8 +291,8 @@ class Asset(AccountsController):
def validate_expected_value_after_useful_life(self): def validate_expected_value_after_useful_life(self):
for row in self.get('finance_books'): for row in self.get('finance_books'):
accumulated_depreciation_after_full_schedule = \ accumulated_depreciation_after_full_schedule = max([d.accumulated_depreciation_amount
max([d.accumulated_depreciation_amount for d in self.get("schedules") if d.finance_book_id == row.idx]) for d in self.get("schedules") if cint(d.finance_book_id) == row.idx])
asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) - asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) -
flt(accumulated_depreciation_after_full_schedule), flt(accumulated_depreciation_after_full_schedule),
@@ -403,7 +403,7 @@ class Asset(AccountsController):
make_gl_entries(gl_entries) make_gl_entries(gl_entries)
self.db_set('booked_fixed_asset', 1) self.db_set('booked_fixed_asset', 1)
def get_depreciation_rate(self, args): def get_depreciation_rate(self, args, on_validate=False):
if isinstance(args, string_types): if isinstance(args, string_types):
args = json.loads(args) args = json.loads(args)
@@ -420,7 +420,10 @@ class Asset(AccountsController):
if args.get("depreciation_method") == 'Double Declining Balance': if args.get("depreciation_method") == 'Double Declining Balance':
return 200.0 / args.get("total_number_of_depreciations") return 200.0 / args.get("total_number_of_depreciations")
if args.get("depreciation_method") == "Written Down Value" and not args.get("rate_of_depreciation"): if args.get("depreciation_method") == "Written Down Value":
if args.get("rate_of_depreciation") and on_validate:
return args.get("rate_of_depreciation")
no_of_years = flt(args.get("total_number_of_depreciations") * flt(args.get("frequency_of_depreciation"))) / 12 no_of_years = flt(args.get("total_number_of_depreciations") * flt(args.get("frequency_of_depreciation"))) / 12
value = flt(args.get("expected_value_after_useful_life")) / flt(self.gross_purchase_amount) value = flt(args.get("expected_value_after_useful_life")) / flt(self.gross_purchase_amount)

View File

@@ -102,9 +102,9 @@ class TestAsset(unittest.TestCase):
asset.save() asset.save()
self.assertEqual(asset.status, "Draft") self.assertEqual(asset.status, "Draft")
expected_schedules = [ expected_schedules = [
["2020-06-06", 163.93, 163.93], ["2020-06-06", 147.54, 147.54],
["2021-04-06", 49836.07, 50000.0], ["2021-04-06", 44852.46, 45000.0],
["2022-02-06", 40000.0, 90000.00] ["2022-02-06", 45000.0, 90000.00]
] ]
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
@@ -130,8 +130,8 @@ class TestAsset(unittest.TestCase):
self.assertEqual(asset.status, "Draft") self.assertEqual(asset.status, "Draft")
asset.save() asset.save()
expected_schedules = [ expected_schedules = [
["2020-06-06", 197.37, 40197.37], ["2020-06-06", 164.47, 40164.47],
["2021-04-06", 49802.63, 90000.00] ["2021-04-06", 49835.53, 90000.00]
] ]
schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount] schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount]
for d in asset.get("schedules")] for d in asset.get("schedules")]
@@ -266,8 +266,8 @@ class TestAsset(unittest.TestCase):
self.assertEqual(asset.get("schedules")[0].journal_entry[:4], "DEPR") self.assertEqual(asset.get("schedules")[0].journal_entry[:4], "DEPR")
expected_gle = ( expected_gle = (
("_Test Accumulated Depreciations - _TC", 0.0, 35699.15), ("_Test Accumulated Depreciations - _TC", 0.0, 32129.24),
("_Test Depreciations - _TC", 35699.15, 0.0) ("_Test Depreciations - _TC", 32129.24, 0.0)
) )
gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry` gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`

View File

@@ -88,7 +88,8 @@ class AccountsController(TransactionBase):
self.validate_paid_amount() self.validate_paid_amount()
if self.doctype in ['Purchase Invoice', 'Sales Invoice']: if self.doctype in ['Purchase Invoice', 'Sales Invoice']:
if cint(self.allocate_advances_automatically): pos_check_field = "is_pos" if self.doctype=="Sales Invoice" else "is_paid"
if cint(self.allocate_advances_automatically) and not cint(self.get(pos_check_field)):
self.set_advances() self.set_advances()
if self.is_return: if self.is_return:

View File

@@ -90,11 +90,11 @@ class Lead(SellingController):
return frappe.db.get_value("Customer", {"lead_name": self.name}) return frappe.db.get_value("Customer", {"lead_name": self.name})
def has_opportunity(self): def has_opportunity(self):
return frappe.db.get_value("Opportunity", {"lead": self.name, "status": ["!=", "Lost"]}) return frappe.db.get_value("Opportunity", {"party_name": self.name, "status": ["!=", "Lost"]})
def has_quotation(self): def has_quotation(self):
return frappe.db.get_value("Quotation", { return frappe.db.get_value("Quotation", {
"lead": self.name, "party_name": self.name,
"docstatus": 1, "docstatus": 1,
"status": ["!=", "Lost"] "status": ["!=", "Lost"]

View File

@@ -9,15 +9,22 @@ frappe.ui.form.on("Opportunity", {
frm.custom_make_buttons = { frm.custom_make_buttons = {
'Quotation': 'Quotation', 'Quotation': 'Quotation',
'Supplier Quotation': 'Supplier Quotation' 'Supplier Quotation': 'Supplier Quotation'
} },
},
customer: function(frm) { frm.set_query("opportunity_from", function() {
frm.trigger('set_contact_link'); return{
erpnext.utils.get_party_details(frm); "filters": {
"name": ["in", ["Customer", "Lead"]],
}
}
});
}, },
lead: function(frm) { party_name: function(frm) {
frm.trigger('set_contact_link'); if (frm.doc.opportunity_from == "Customer") {
frm.trigger('set_contact_link');
erpnext.utils.get_party_details(frm);
}
}, },
with_items: function(frm) { with_items: function(frm) {
@@ -30,15 +37,14 @@ frappe.ui.form.on("Opportunity", {
contact_person: erpnext.utils.get_contact_details, contact_person: erpnext.utils.get_contact_details,
enquiry_from: function(frm) { opportunity_from: function(frm) {
frm.toggle_reqd("lead", frm.doc.enquiry_from==="Lead"); frm.toggle_reqd("party_name", frm.doc.opportunity_from);
frm.toggle_reqd("customer", frm.doc.enquiry_from==="Customer"); frm.trigger("set_dynamic_field_label");
}, },
refresh: function(frm) { refresh: function(frm) {
var doc = frm.doc; var doc = frm.doc;
frm.events.enquiry_from(frm); frm.events.opportunity_from(frm);
frm.trigger('set_contact_link');
frm.trigger('toggle_mandatory'); frm.trigger('toggle_mandatory');
erpnext.toggle_naming_series(); erpnext.toggle_naming_series();
@@ -75,13 +81,20 @@ frappe.ui.form.on("Opportunity", {
}, },
set_contact_link: function(frm) { set_contact_link: function(frm) {
if(frm.doc.customer) { if(frm.doc.opportunity_from == "Customer" && frm.doc.party_name) {
frappe.dynamic_link = {doc: frm.doc, fieldname: 'customer', doctype: 'Customer'} frappe.dynamic_link = {doc: frm.doc, fieldname: 'customer', doctype: 'Customer'}
} else if(frm.doc.lead) { } else if(frm.doc.opportunity_from == "Lead" && frm.doc.party_name) {
frappe.dynamic_link = {doc: frm.doc, fieldname: 'lead', doctype: 'Lead'} frappe.dynamic_link = {doc: frm.doc, fieldname: 'lead', doctype: 'Lead'}
} }
}, },
set_dynamic_field_label: function(frm){
if (frm.doc.opportunity_from) {
frm.set_df_property("party_name", "label", frm.doc.opportunity_from);
}
},
make_supplier_quotation: function(frm) { make_supplier_quotation: function(frm) {
frappe.model.open_mapped_doc({ frappe.model.open_mapped_doc({
method: "erpnext.crm.doctype.opportunity.opportunity.make_supplier_quotation", method: "erpnext.crm.doctype.opportunity.opportunity.make_supplier_quotation",
@@ -97,10 +110,6 @@ frappe.ui.form.on("Opportunity", {
// TODO commonify this code // TODO commonify this code
erpnext.crm.Opportunity = frappe.ui.form.Controller.extend({ erpnext.crm.Opportunity = frappe.ui.form.Controller.extend({
onload: function() { onload: function() {
if(!this.frm.doc.enquiry_from && this.frm.doc.customer)
this.frm.doc.enquiry_from = "Customer";
if(!this.frm.doc.enquiry_from && this.frm.doc.lead)
this.frm.doc.enquiry_from = "Lead";
if(!this.frm.doc.status) if(!this.frm.doc.status)
set_multiple(this.frm.doc.doctype, this.frm.doc.name, { status:'Open' }); set_multiple(this.frm.doc.doctype, this.frm.doc.name, { status:'Open' });
@@ -148,7 +157,7 @@ erpnext.crm.Opportunity = frappe.ui.form.Controller.extend({
$.extend(cur_frm.cscript, new erpnext.crm.Opportunity({frm: cur_frm})); $.extend(cur_frm.cscript, new erpnext.crm.Opportunity({frm: cur_frm}));
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) { cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
if(doc.enquiry_from == 'Lead' && doc.lead) if(doc.opportunity_from == 'Lead' && doc.party_name)
cur_frm.cscript.lead(doc, cdt, cdn); cur_frm.cscript.lead(doc, cdt, cdn);
} }
@@ -171,10 +180,10 @@ cur_frm.cscript.item_code = function(doc, cdt, cdn) {
} }
cur_frm.cscript.lead = function(doc, cdt, cdn) { cur_frm.cscript.lead = function(doc, cdt, cdn) {
cur_frm.toggle_display("contact_info", doc.customer || doc.lead); cur_frm.toggle_display("contact_info", doc.party_name);
erpnext.utils.map_current_doc({ erpnext.utils.map_current_doc({
method: "erpnext.crm.doctype.lead.lead.make_opportunity", method: "erpnext.crm.doctype.lead.lead.make_opportunity",
source_name: cur_frm.doc.lead, source_name: cur_frm.doc.party_name,
frm: cur_frm frm: cur_frm
}); });
} }

View File

@@ -21,6 +21,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "from_section", "fieldname": "from_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -54,6 +55,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "", "default": "",
"fetch_if_empty": 0,
"fieldname": "naming_series", "fieldname": "naming_series",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -88,8 +90,9 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "enquiry_from", "fetch_if_empty": 0,
"fieldtype": "Select", "fieldname": "opportunity_from",
"fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@@ -102,7 +105,7 @@
"no_copy": 0, "no_copy": 0,
"oldfieldname": "enquiry_from", "oldfieldname": "enquiry_from",
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "\nLead\nCustomer", "options": "DocType",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
@@ -122,9 +125,10 @@
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.enquiry_from===\"Customer\"", "depends_on": "",
"fieldname": "customer", "fetch_if_empty": 0,
"fieldtype": "Link", "fieldname": "party_name",
"fieldtype": "Dynamic Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@@ -132,54 +136,19 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "Customer", "label": "Customer/Lead",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"oldfieldname": "customer", "oldfieldname": "customer",
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Customer", "options": "opportunity_from",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 1,
"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": 1,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.enquiry_from===\"Lead\"",
"fieldname": "lead",
"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": "Lead",
"length": 0,
"no_copy": 0,
"oldfieldname": "lead",
"oldfieldtype": "Link",
"options": "Lead",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0, "translatable": 0,
@@ -193,6 +162,8 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_from": "",
"fetch_if_empty": 0,
"fieldname": "customer_name", "fieldname": "customer_name",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -224,6 +195,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break0", "fieldname": "column_break0",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -256,6 +228,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "title", "fieldname": "title",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
@@ -289,6 +262,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "Sales", "default": "Sales",
"fetch_if_empty": 0,
"fieldname": "opportunity_type", "fieldname": "opportunity_type",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -324,6 +298,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "Open", "default": "Open",
"fetch_if_empty": 0,
"fieldname": "status", "fieldname": "status",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -359,6 +334,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.status===\"Lost\"", "depends_on": "eval:doc.status===\"Lost\"",
"fetch_if_empty": 0,
"fieldname": "order_lost_reason", "fieldname": "order_lost_reason",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
@@ -390,6 +366,7 @@
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "mins_to_first_response", "fieldname": "mins_to_first_response",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -423,6 +400,7 @@
"collapsible": 1, "collapsible": 1,
"collapsible_depends_on": "contact_by", "collapsible_depends_on": "contact_by",
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "next_contact", "fieldname": "next_contact",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -456,6 +434,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "contact_by", "fieldname": "contact_by",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -492,6 +471,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "contact_date", "fieldname": "contact_date",
"fieldtype": "Datetime", "fieldtype": "Datetime",
"hidden": 0, "hidden": 0,
@@ -525,6 +505,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break2", "fieldname": "column_break2",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -557,6 +538,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "to_discuss", "fieldname": "to_discuss",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
@@ -590,6 +572,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_14", "fieldname": "section_break_14",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -622,6 +605,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "currency", "fieldname": "currency",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -655,6 +639,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "opportunity_amount", "fieldname": "opportunity_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -687,6 +672,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "with_items", "fieldname": "with_items",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -719,6 +705,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_17", "fieldname": "column_break_17",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -751,6 +738,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "Prospecting", "default": "Prospecting",
"fetch_if_empty": 0,
"fieldname": "sales_stage", "fieldname": "sales_stage",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -785,6 +773,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "100", "default": "100",
"fetch_if_empty": 0,
"fieldname": "probability", "fieldname": "probability",
"fieldtype": "Percent", "fieldtype": "Percent",
"hidden": 0, "hidden": 0,
@@ -818,6 +807,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "with_items", "depends_on": "with_items",
"fetch_if_empty": 0,
"fieldname": "items_section", "fieldname": "items_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -852,6 +842,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "items", "fieldname": "items",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -888,6 +879,7 @@
"collapsible_depends_on": "next_contact_by", "collapsible_depends_on": "next_contact_by",
"columns": 0, "columns": 0,
"depends_on": "eval:doc.lead || doc.customer", "depends_on": "eval:doc.lead || doc.customer",
"fetch_if_empty": 0,
"fieldname": "contact_info", "fieldname": "contact_info",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -921,6 +913,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.customer || doc.lead", "depends_on": "eval:doc.customer || doc.lead",
"fetch_if_empty": 0,
"fieldname": "customer_address", "fieldname": "customer_address",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -953,6 +946,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "address_display", "fieldname": "address_display",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 1, "hidden": 1,
@@ -988,6 +982,7 @@
"columns": 0, "columns": 0,
"depends_on": "customer", "depends_on": "customer",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "territory", "fieldname": "territory",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1022,6 +1017,7 @@
"columns": 0, "columns": 0,
"depends_on": "customer", "depends_on": "customer",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "customer_group", "fieldname": "customer_group",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1056,6 +1052,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break3", "fieldname": "column_break3",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -1087,6 +1084,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.lead || doc.customer", "depends_on": "eval:doc.lead || doc.customer",
"fetch_if_empty": 0,
"fieldname": "contact_person", "fieldname": "contact_person",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1120,6 +1118,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "customer", "depends_on": "customer",
"fetch_if_empty": 0,
"fieldname": "contact_display", "fieldname": "contact_display",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
@@ -1152,6 +1151,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.lead || doc.customer", "depends_on": "eval:doc.lead || doc.customer",
"fetch_if_empty": 0,
"fieldname": "contact_email", "fieldname": "contact_email",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -1184,6 +1184,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.lead || doc.customer", "depends_on": "eval:doc.lead || doc.customer",
"fetch_if_empty": 0,
"fieldname": "contact_mobile", "fieldname": "contact_mobile",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
@@ -1216,6 +1217,7 @@
"collapsible": 1, "collapsible": 1,
"collapsible_depends_on": "", "collapsible_depends_on": "",
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "more_info", "fieldname": "more_info",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1249,6 +1251,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "source", "fieldname": "source",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1285,6 +1288,7 @@
"columns": 0, "columns": 0,
"depends_on": "eval: doc.source==\"Campaign\"", "depends_on": "eval: doc.source==\"Campaign\"",
"description": "Enter name of campaign if source of enquiry is campaign", "description": "Enter name of campaign if source of enquiry is campaign",
"fetch_if_empty": 0,
"fieldname": "campaign", "fieldname": "campaign",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1319,6 +1323,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break1", "fieldname": "column_break1",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -1351,6 +1356,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "company", "fieldname": "company",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1386,6 +1392,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "Today", "default": "Today",
"fetch_if_empty": 0,
"fieldname": "transaction_date", "fieldname": "transaction_date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0, "hidden": 0,
@@ -1420,6 +1427,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "amended_from", "fieldname": "amended_from",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1460,7 +1468,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-10-01 09:28:43.990999", "modified": "2019-04-25 18:55:43.874656",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "CRM", "module": "CRM",
"name": "Opportunity", "name": "Opportunity",
@@ -1508,11 +1516,11 @@
"quick_entry": 0, "quick_entry": 0,
"read_only": 0, "read_only": 0,
"read_only_onload": 0, "read_only_onload": 0,
"search_fields": "status,transaction_date,customer,lead,opportunity_type,territory,company", "search_fields": "status,transaction_date,party_name,opportunity_type,territory,company",
"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": "customer", "timeline_field": "party_name",
"title_field": "title", "title_field": "title",
"track_changes": 0, "track_changes": 0,
"track_seen": 1, "track_seen": 1,

View File

@@ -16,8 +16,8 @@ sender_field = "contact_email"
class Opportunity(TransactionBase): class Opportunity(TransactionBase):
def after_insert(self): def after_insert(self):
if self.lead: if self.opportunity_from == "Lead":
frappe.get_doc("Lead", self.lead).set_status(update=True) frappe.get_doc("Lead", self.party_name).set_status(update=True)
def validate(self): def validate(self):
self._prev = frappe._dict({ self._prev = frappe._dict({
@@ -29,12 +29,8 @@ class Opportunity(TransactionBase):
self.make_new_lead_if_required() self.make_new_lead_if_required()
if not self.enquiry_from:
frappe.throw(_("Opportunity From field is mandatory"))
self.validate_item_details() self.validate_item_details()
self.validate_uom_is_integer("uom", "qty") self.validate_uom_is_integer("uom", "qty")
self.validate_lead_cust()
self.validate_cust_name() self.validate_cust_name()
if not self.title: if not self.title:
@@ -45,7 +41,7 @@ class Opportunity(TransactionBase):
def make_new_lead_if_required(self): def make_new_lead_if_required(self):
"""Set lead against new opportunity""" """Set lead against new opportunity"""
if not (self.lead or self.customer) and self.contact_email: if (not self.get("party_name")) and self.contact_email:
# check if customer is already created agains the self.contact_email # check if customer is already created agains the self.contact_email
customer = frappe.db.sql("""select customer = frappe.db.sql("""select
distinct `tabDynamic Link`.link_name as customer distinct `tabDynamic Link`.link_name as customer
@@ -61,8 +57,8 @@ class Opportunity(TransactionBase):
`tabDynamic Link`.link_doctype='Customer' `tabDynamic Link`.link_doctype='Customer'
""".format(self.contact_email), as_dict=True) """.format(self.contact_email), as_dict=True)
if customer and customer[0].customer: if customer and customer[0].customer:
self.customer = customer[0].customer self.party_name = customer[0].customer
self.enquiry_from = "Customer" self.opportunity_from = "Customer"
return return
lead_name = frappe.db.get_value("Lead", {"email_id": self.contact_email}) lead_name = frappe.db.get_value("Lead", {"email_id": self.contact_email})
@@ -89,8 +85,8 @@ class Opportunity(TransactionBase):
lead.insert(ignore_permissions=True) lead.insert(ignore_permissions=True)
lead_name = lead.name lead_name = lead.name
self.enquiry_from = "Lead" self.opportunity_from = "Lead"
self.lead = lead_name self.party_name = lead_name
def declare_enquiry_lost(self,arg): def declare_enquiry_lost(self,arg):
if not self.has_active_quotation(): if not self.has_active_quotation():
@@ -137,10 +133,10 @@ class Opportunity(TransactionBase):
return True return True
def validate_cust_name(self): def validate_cust_name(self):
if self.customer: if self.party_name and self.opportunity_from == 'Customer':
self.customer_name = frappe.db.get_value("Customer", self.customer, "customer_name") self.customer_name = frappe.db.get_value("Customer", self.party_name, "customer_name")
elif self.lead: elif self.party_name and self.opportunity_from == 'Lead':
lead_name, company_name = frappe.db.get_value("Lead", self.lead, ["lead_name", "company_name"]) lead_name, company_name = frappe.db.get_value("Lead", self.party_name, ["lead_name", "company_name"])
self.customer_name = company_name or lead_name self.customer_name = company_name or lead_name
def on_update(self): def on_update(self):
@@ -153,16 +149,16 @@ class Opportunity(TransactionBase):
opts.description = "" opts.description = ""
opts.contact_date = self.contact_date opts.contact_date = self.contact_date
if self.customer: if self.party_name and self.opportunity_from == 'Customer':
if self.contact_person: if self.contact_person:
opts.description = 'Contact '+cstr(self.contact_person) opts.description = 'Contact '+cstr(self.contact_person)
else: else:
opts.description = 'Contact customer '+cstr(self.customer) opts.description = 'Contact customer '+cstr(self.party_name)
elif self.lead: elif self.party_name and self.opportunity_from == 'Lead':
if self.contact_display: if self.contact_display:
opts.description = 'Contact '+cstr(self.contact_display) opts.description = 'Contact '+cstr(self.contact_display)
else: else:
opts.description = 'Contact lead '+cstr(self.lead) opts.description = 'Contact lead '+cstr(self.party_name)
opts.subject = opts.description opts.subject = opts.description
opts.description += '. By : ' + cstr(self.contact_by) opts.description += '. By : ' + cstr(self.contact_by)
@@ -187,17 +183,6 @@ class Opportunity(TransactionBase):
for key in item_fields: for key in item_fields:
if not d.get(key): d.set(key, item.get(key)) if not d.get(key): d.set(key, item.get(key))
def validate_lead_cust(self):
if self.enquiry_from == 'Lead':
if not self.lead:
frappe.throw(_("Lead must be set if Opportunity is made from Lead"))
else:
self.customer = None
elif self.enquiry_from == 'Customer':
if not self.customer:
msgprint(_("Customer is mandatory if 'Opportunity From' is selected as Customer"), raise_exception=1)
else:
self.lead = None
@frappe.whitelist() @frappe.whitelist()
def get_item_details(item_code): def get_item_details(item_code):
@@ -219,8 +204,11 @@ def make_quotation(source_name, target_doc=None):
quotation = frappe.get_doc(target) quotation = frappe.get_doc(target)
company_currency = frappe.get_cached_value('Company', quotation.company, "default_currency") company_currency = frappe.get_cached_value('Company', quotation.company, "default_currency")
party_account_currency = get_party_account_currency("Customer", quotation.customer,
quotation.company) if quotation.customer else company_currency if quotation.quotation_to == 'Customer' and quotation.party_name:
party_account_currency = get_party_account_currency("Customer", quotation.party_name, quotation.company)
else:
party_account_currency = company_currency
quotation.currency = party_account_currency or company_currency quotation.currency = party_account_currency or company_currency
@@ -246,7 +234,7 @@ def make_quotation(source_name, target_doc=None):
"Opportunity": { "Opportunity": {
"doctype": "Quotation", "doctype": "Quotation",
"field_map": { "field_map": {
"enquiry_from": "quotation_to", "opportunity_from": "quotation_to",
"opportunity_type": "order_type", "opportunity_type": "order_type",
"name": "enq_no", "name": "enq_no",
} }

View File

@@ -1,5 +1,5 @@
frappe.listview_settings['Opportunity'] = { frappe.listview_settings['Opportunity'] = {
add_fields: ["customer_name", "opportunity_type", "enquiry_from", "status"], add_fields: ["customer_name", "opportunity_type", "opportunity_from", "status"],
get_indicator: function(doc) { get_indicator: function(doc) {
var indicator = [__(doc.status), frappe.utils.guess_colour(doc.status), "status,=," + doc.status]; var indicator = [__(doc.status), frappe.utils.guess_colour(doc.status), "status,=," + doc.status];
if(doc.status=="Quotation") { if(doc.status=="Quotation") {

View File

@@ -6,7 +6,7 @@ QUnit.test("test: opportunity", function (assert) {
() => frappe.timeout(1), () => frappe.timeout(1),
() => frappe.click_button('New'), () => frappe.click_button('New'),
() => frappe.timeout(1), () => frappe.timeout(1),
() => cur_frm.set_value('enquiry_from', 'Customer'), () => cur_frm.set_value('opportunity_from', 'Customer'),
() => cur_frm.set_value('customer', 'Test Customer 1'), () => cur_frm.set_value('customer', 'Test Customer 1'),
// check items // check items

View File

@@ -37,13 +37,13 @@ class TestOpportunity(unittest.TestCase):
# new lead should be created against the new.opportunity@example.com # new lead should be created against the new.opportunity@example.com
opp_doc = frappe.get_doc(args).insert(ignore_permissions=True) opp_doc = frappe.get_doc(args).insert(ignore_permissions=True)
self.assertTrue(opp_doc.lead) self.assertTrue(opp_doc.party_name)
self.assertEqual(opp_doc.enquiry_from, "Lead") self.assertEqual(opp_doc.opportunity_from, "Lead")
self.assertEqual(frappe.db.get_value("Lead", opp_doc.lead, "email_id"), self.assertEqual(frappe.db.get_value("Lead", opp_doc.party_name, "email_id"),
'new.opportunity@example.com') 'new.opportunity@example.com')
# create new customer and create new contact against 'new.opportunity@example.com' # create new customer and create new contact against 'new.opportunity@example.com'
customer = make_customer(opp_doc.lead).insert(ignore_permissions=True) customer = make_customer(opp_doc.party_name).insert(ignore_permissions=True)
frappe.get_doc({ frappe.get_doc({
"doctype": "Contact", "doctype": "Contact",
"email_id": "new.opportunity@example.com", "email_id": "new.opportunity@example.com",
@@ -55,9 +55,9 @@ class TestOpportunity(unittest.TestCase):
}).insert(ignore_permissions=True) }).insert(ignore_permissions=True)
opp_doc = frappe.get_doc(args).insert(ignore_permissions=True) opp_doc = frappe.get_doc(args).insert(ignore_permissions=True)
self.assertTrue(opp_doc.customer) self.assertTrue(opp_doc.party_name)
self.assertEqual(opp_doc.enquiry_from, "Customer") self.assertEqual(opp_doc.opportunity_from, "Customer")
self.assertEqual(opp_doc.customer, customer.name) self.assertEqual(opp_doc.party_name, customer.name)
def make_opportunity(**args): def make_opportunity(**args):
args = frappe._dict(args) args = frappe._dict(args)
@@ -65,17 +65,17 @@ def make_opportunity(**args):
opp_doc = frappe.get_doc({ opp_doc = frappe.get_doc({
"doctype": "Opportunity", "doctype": "Opportunity",
"company": args.company or "_Test Company", "company": args.company or "_Test Company",
"enquiry_from": args.enquiry_from or "Customer", "opportunity_from": args.opportunity_from or "Customer",
"opportunity_type": "Sales", "opportunity_type": "Sales",
"with_items": args.with_items or 0, "with_items": args.with_items or 0,
"transaction_date": today() "transaction_date": today()
}) })
if opp_doc.enquiry_from == 'Customer': if opp_doc.opportunity_from == 'Customer':
opp_doc.customer = args.customer or "_Test Customer" opp_doc.party_name= args.customer or "_Test Customer"
if opp_doc.enquiry_from == 'Lead': if opp_doc.opportunity_from == 'Lead':
opp_doc.customer = args.lead or "_T-Lead-00001" opp_doc.party_name = args.lead or "_T-Lead-00001"
if args.with_items: if args.with_items:
opp_doc.append('items', { opp_doc.append('items', {

View File

@@ -2,9 +2,9 @@
{ {
"doctype": "Opportunity", "doctype": "Opportunity",
"name": "_Test Opportunity 1", "name": "_Test Opportunity 1",
"enquiry_from": "Lead", "opportunity_from": "Lead",
"enquiry_type": "Sales", "enquiry_type": "Sales",
"lead": "_T-Lead-00001", "party_name": "_T-Lead-00001",
"transaction_date": "2013-12-12", "transaction_date": "2013-12-12",
"items": [{ "items": [{
"item_name": "Test Item", "item_name": "Test Item",

View File

@@ -66,7 +66,7 @@ def get_columns():
def get_communication_details(filters): def get_communication_details(filters):
communication_count = None communication_count = None
communication_list = [] communication_list = []
opportunities = frappe.db.get_values('Opportunity', {'enquiry_from': 'Lead'},\ opportunities = frappe.db.get_values('Opportunity', {'opportunity_from': 'Lead'},\
['name', 'customer_name', 'lead', 'contact_email'], as_dict=1) ['name', 'customer_name', 'lead', 'contact_email'], as_dict=1)
for d in opportunities: for d in opportunities:

View File

@@ -56,7 +56,7 @@ def work(domain="Manufacturing"):
def make_opportunity(domain): def make_opportunity(domain):
b = frappe.get_doc({ b = frappe.get_doc({
"doctype": "Opportunity", "doctype": "Opportunity",
"enquiry_from": "Customer", "opportunity_from": "Customer",
"customer": get_random("Customer"), "customer": get_random("Customer"),
"opportunity_type": "Sales", "opportunity_type": "Sales",
"with_items": 1, "with_items": 1,

View File

@@ -22,6 +22,9 @@ erpnext.integrations.plaidLink = class plaidLink {
frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.plaid_configuration') frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.plaid_configuration')
.then(result => { .then(result => {
if (result !== "disabled") { if (result !== "disabled") {
if (result.plaid_env == undefined || result.plaid_public_key == undefined) {
frappe.throw(__("Please add valid Plaid api keys in site_config.json first"));
}
me.plaid_env = result.plaid_env; me.plaid_env = result.plaid_env;
me.plaid_public_key = result.plaid_public_key; me.plaid_public_key = result.plaid_public_key;
me.client_name = result.client_name; me.client_name = result.client_name;

View File

@@ -51,7 +51,7 @@ def get_additional_salary_component(employee, start_date, end_date):
for d in additional_components: for d in additional_components:
component = frappe.get_doc("Salary Component", d.salary_component) component = frappe.get_doc("Salary Component", d.salary_component)
struct_row = {'salary_component': d.salary_component} struct_row = {'salary_component': d.salary_component}
for field in ["depends_on_lwp", "abbr", "is_tax_applicable", "variable_based_on_taxable_salary", "is_additional_component"]: for field in ["depends_on_payment_days", "abbr", "is_tax_applicable", "variable_based_on_taxable_salary", "is_additional_component"]:
struct_row[field] = component.get(field) struct_row[field] = component.get(field)
additional_components_list.append({ additional_components_list.append({

View File

@@ -113,7 +113,7 @@ def get_max_benefits(employee, on_date):
def get_max_benefits_remaining(employee, on_date, payroll_period): def get_max_benefits_remaining(employee, on_date, payroll_period):
max_benefits = get_max_benefits(employee, on_date) max_benefits = get_max_benefits(employee, on_date)
if max_benefits and max_benefits > 0: if max_benefits and max_benefits > 0:
have_depends_on_lwp = False have_depends_on_payment_days = False
per_day_amount_total = 0 per_day_amount_total = 0
payroll_period_days = get_payroll_period_days(on_date, on_date, employee)[0] payroll_period_days = get_payroll_period_days(on_date, on_date, employee)[0]
payroll_period_obj = frappe.get_doc("Payroll Period", payroll_period) payroll_period_obj = frappe.get_doc("Payroll Period", payroll_period)
@@ -122,22 +122,22 @@ def get_max_benefits_remaining(employee, on_date, payroll_period):
prev_sal_slip_flexi_total = get_sal_slip_total_benefit_given(employee, payroll_period_obj) prev_sal_slip_flexi_total = get_sal_slip_total_benefit_given(employee, payroll_period_obj)
if prev_sal_slip_flexi_total > 0: if prev_sal_slip_flexi_total > 0:
# Check salary structure hold depends_on_lwp component # Check salary structure hold depends_on_payment_days component
# If yes then find the amount per day of each component and find the sum # If yes then find the amount per day of each component and find the sum
sal_struct_name = get_assigned_salary_structure(employee, on_date) sal_struct_name = get_assigned_salary_structure(employee, on_date)
if sal_struct_name: if sal_struct_name:
sal_struct = frappe.get_doc("Salary Structure", sal_struct_name) sal_struct = frappe.get_doc("Salary Structure", sal_struct_name)
for sal_struct_row in sal_struct.get("earnings"): for sal_struct_row in sal_struct.get("earnings"):
salary_component = frappe.get_doc("Salary Component", sal_struct_row.salary_component) salary_component = frappe.get_doc("Salary Component", sal_struct_row.salary_component)
if salary_component.depends_on_lwp == 1 and salary_component.pay_against_benefit_claim != 1: if salary_component.depends_on_payment_days == 1 and salary_component.pay_against_benefit_claim != 1:
have_depends_on_lwp = True have_depends_on_payment_days = True
benefit_amount = get_benefit_pro_rata_ratio_amount(sal_struct, salary_component.max_benefit_amount) benefit_amount = get_benefit_pro_rata_ratio_amount(sal_struct, salary_component.max_benefit_amount)
amount_per_day = benefit_amount / payroll_period_days amount_per_day = benefit_amount / payroll_period_days
per_day_amount_total += amount_per_day per_day_amount_total += amount_per_day
# Then the sum multiply with the no of lwp in that period # Then the sum multiply with the no of lwp in that period
# Include that amount to the prev_sal_slip_flexi_total to get the actual # Include that amount to the prev_sal_slip_flexi_total to get the actual
if have_depends_on_lwp and per_day_amount_total > 0: if have_depends_on_payment_days and per_day_amount_total > 0:
holidays = get_holidays_for_employee(employee, payroll_period_obj.start_date, on_date) holidays = get_holidays_for_employee(employee, payroll_period_obj.start_date, on_date)
working_days = date_diff(on_date, payroll_period_obj.start_date) + 1 working_days = date_diff(on_date, payroll_period_obj.start_date) + 1
leave_days = calculate_lwp(employee, payroll_period_obj.start_date, holidays, working_days) leave_days = calculate_lwp(employee, payroll_period_obj.start_date, holidays, working_days)
@@ -185,7 +185,7 @@ def get_benefit_component_amount(employee, start_date, end_date, struct_row, sal
'payroll_period': payroll_period 'payroll_period': payroll_period
}) })
if frappe.db.get_value("Salary Component", struct_row.salary_component, "depends_on_lwp") != 1: if frappe.db.get_value("Salary Component", struct_row.salary_component, "depends_on_payment_days") != 1:
if frequency == "Monthly" and actual_payroll_days in range(360, 370): if frequency == "Monthly" and actual_payroll_days in range(360, 370):
period_length = 1 period_length = 1
period_factor = 12 period_factor = 12

View File

@@ -170,7 +170,7 @@ def get_last_payroll_period_benefits(employee, sal_slip_start_date, sal_slip_end
amount += current_claimed_amount amount += current_claimed_amount
struct_row = {} struct_row = {}
salary_components_dict = {} salary_components_dict = {}
struct_row['depends_on_lwp'] = salary_component.depends_on_lwp struct_row['depends_on_payment_days'] = salary_component.depends_on_payment_days
struct_row['salary_component'] = salary_component.name struct_row['salary_component'] = salary_component.name
struct_row['abbr'] = salary_component.salary_component_abbr struct_row['abbr'] = salary_component.salary_component_abbr
struct_row['do_not_include_in_total'] = salary_component.do_not_include_in_total struct_row['do_not_include_in_total'] = salary_component.do_not_include_in_total

View File

@@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 1, "allow_rename": 1,
@@ -20,6 +21,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "max_amount", "fieldname": "max_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -29,7 +31,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Max Amount", "label": "Max Exemption Amount",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@@ -39,7 +41,7 @@
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0, "translatable": 0,
@@ -52,6 +54,8 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "1",
"fetch_if_empty": 0,
"fieldname": "is_active", "fieldname": "is_active",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -88,7 +92,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-06-19 16:33:48.419267", "modified": "2019-04-25 13:20:31.367158",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Employee Tax Exemption Category", "name": "Employee Tax Exemption Category",
@@ -159,6 +163,7 @@
"show_name_in_global_search": 0, "show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 0,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@@ -10,6 +10,7 @@ frappe.ui.form.on('Employee Tax Exemption Declaration', {
} }
} }
}); });
frm.set_query('payroll_period', function() { frm.set_query('payroll_period', function() {
const fields = {'employee': 'Employee', 'company': 'Company'}; const fields = {'employee': 'Employee', 'company': 'Company'};
@@ -27,6 +28,7 @@ frappe.ui.form.on('Employee Tax Exemption Declaration', {
} }
} }
}); });
frm.set_query('exemption_sub_category', 'declarations', function() { frm.set_query('exemption_sub_category', 'declarations', function() {
return { return {
filters: { filters: {
@@ -34,5 +36,16 @@ frappe.ui.form.on('Employee Tax Exemption Declaration', {
} }
} }
}); });
},
refresh: function(frm) {
if(frm.doc.docstatus==1) {
frm.add_custom_button(__('Submit Proof'), function() {
frappe.model.open_mapped_doc({
method: "erpnext.hr.doctype.employee_tax_exemption_declaration.employee_tax_exemption_declaration.make_proof_submission",
frm: frm
});
}).addClass("btn-primary");
}
} }
}); });

View File

@@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 1, "allow_rename": 1,
@@ -20,6 +21,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "employee", "fieldname": "employee",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -53,9 +55,10 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "employee.company", "fetch_from": "employee.employee_name",
"fieldname": "company", "fetch_if_empty": 0,
"fieldtype": "Link", "fieldname": "employee_name",
"fieldtype": "Data",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@@ -63,104 +66,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Company", "label": "Employee Name",
"length": 0,
"no_copy": 0,
"options": "Company",
"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": "column_break_2",
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "payroll_period",
"fieldtype": "Link",
"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": "Payroll Period",
"length": 0,
"no_copy": 0,
"options": "Payroll Period",
"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": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "total_exemption_amount",
"fieldtype": "Currency",
"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": "Total Exemption Amount",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@@ -184,6 +90,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "employee.department", "fetch_from": "employee.department",
"fetch_if_empty": 0,
"fieldname": "department", "fieldname": "department",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -217,6 +124,108 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_2",
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "payroll_period",
"fieldtype": "Link",
"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": "Payroll Period",
"length": 0,
"no_copy": 0,
"options": "Payroll Period",
"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": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.company",
"fetch_if_empty": 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,
"options": "Company",
"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,
"fetch_if_empty": 0,
"fieldname": "amended_from", "fieldname": "amended_from",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -249,6 +258,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_8", "fieldname": "section_break_8",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -280,6 +290,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "declarations", "fieldname": "declarations",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -300,7 +311,137 @@
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "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,
"fetch_if_empty": 0,
"fieldname": "section_break_10",
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "total_declared_amount",
"fieldtype": "Currency",
"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": "Total Declared Amount",
"length": 0,
"no_copy": 0,
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_12",
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "total_exemption_amount",
"fieldtype": "Currency",
"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": "Total Exemption Amount",
"length": 0,
"no_copy": 0,
"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, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0, "translatable": 0,
@@ -317,7 +458,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-08-21 16:15:49.363307", "modified": "2019-04-25 16:38:05.847925",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Employee Tax Exemption Declaration", "name": "Employee Tax Exemption Declaration",

View File

@@ -6,28 +6,61 @@ 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 erpnext.hr.utils import validate_tax_declaration, calculate_annual_eligible_hra_exemption from frappe.utils import flt
from frappe.model.mapper import get_mapped_doc
from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, calculate_annual_eligible_hra_exemption
class DuplicateDeclarationError(frappe.ValidationError): pass
class EmployeeTaxExemptionDeclaration(Document): class EmployeeTaxExemptionDeclaration(Document):
def validate(self): def validate(self):
validate_tax_declaration(self.declarations) validate_tax_declaration(self.declarations)
self.total_exemption_amount = 0 self.validate_duplicate()
self.set_total_declared_amount()
self.set_total_exemption_amount()
self.calculate_hra_exemption() self.calculate_hra_exemption()
for item in self.declarations:
self.total_exemption_amount += item.amount
def before_submit(self): def validate_duplicate(self):
if frappe.db.exists({"doctype": "Employee Tax Exemption Declaration", duplicate = frappe.db.get_value("Employee Tax Exemption Declaration",
"employee": self.employee, filters = {
"payroll_period": self.payroll_period, "employee": self.employee,
"docstatus": 1}): "payroll_period": self.payroll_period,
frappe.throw(_("Tax Declaration of {0} for period {1} already submitted.")\ "name": ["!=", self.name]
.format(self.employee, self.payroll_period), frappe.DocstatusTransitionError) }
)
if duplicate:
frappe.throw(_("Duplicate Tax Declaration of {0} for period {1}")
.format(self.employee, self.payroll_period), DuplicateDeclarationError)
def set_total_declared_amount(self):
self.total_declared_amount = 0.0
for d in self.declarations:
self.total_declared_amount += flt(d.amount)
def set_total_exemption_amount(self):
self.total_exemption_amount = get_total_exemption_amount(self.declarations)
def calculate_hra_exemption(self): def calculate_hra_exemption(self):
hra_exemption = calculate_annual_eligible_hra_exemption(self) self.salary_structure_hra, self.annual_hra_exemption, self.monthly_hra_exemption = 0, 0, 0
if hra_exemption: if self.get("monthly_house_rent"):
self.total_exemption_amount += hra_exemption["annual_exemption"] hra_exemption = calculate_annual_eligible_hra_exemption(self)
self.salary_structure_hra = hra_exemption["hra_amount"] if hra_exemption:
self.annual_hra_exemption = hra_exemption["annual_exemption"] self.total_exemption_amount += hra_exemption["annual_exemption"]
self.monthly_hra_exemption = hra_exemption["monthly_exemption"] self.salary_structure_hra = hra_exemption["hra_amount"]
self.annual_hra_exemption = hra_exemption["annual_exemption"]
self.monthly_hra_exemption = hra_exemption["monthly_exemption"]
@frappe.whitelist()
def make_proof_submission(source_name, target_doc=None):
doclist = get_mapped_doc("Employee Tax Exemption Declaration", source_name, {
"Employee Tax Exemption Declaration": {
"doctype": "Employee Tax Exemption Proof Submission",
"field_no_map": ["monthly_house_rent", "monthly_hra_exemption"]
},
"Employee Tax Exemption Declaration Category": {
"doctype": "Employee Tax Exemption Proof Submission Detail",
"add_if_empty": True
}
}, target_doc)
return doclist

View File

@@ -6,6 +6,7 @@ from __future__ import unicode_literals
import frappe, erpnext import frappe, erpnext
import unittest import unittest
from erpnext.hr.doctype.employee.test_employee import make_employee from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.hr.doctype.employee_tax_exemption_declaration.employee_tax_exemption_declaration import DuplicateDeclarationError
class TestEmployeeTaxExemptionDeclaration(unittest.TestCase): class TestEmployeeTaxExemptionDeclaration(unittest.TestCase):
def setUp(self): def setUp(self):
@@ -15,71 +16,71 @@ class TestEmployeeTaxExemptionDeclaration(unittest.TestCase):
create_exemption_category() create_exemption_category()
frappe.db.sql("""delete from `tabEmployee Tax Exemption Declaration`""") frappe.db.sql("""delete from `tabEmployee Tax Exemption Declaration`""")
def test_exemption_amount_greater_than_category_max(self):
declaration = frappe.get_doc({
"doctype": "Employee Tax Exemption Declaration",
"employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
"payroll_period": "_Test Payroll Period",
"declarations": [dict(exemption_sub_category = "_Test Sub Category",
exemption_category = "_Test Category",
amount = 150000)]
})
self.assertRaises(frappe.ValidationError, declaration.save)
declaration = frappe.get_doc({
"doctype": "Employee Tax Exemption Declaration",
"payroll_period": "_Test Payroll Period",
"employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
"declarations": [dict(exemption_sub_category = "_Test Sub Category",
exemption_category = "_Test Category",
amount = 90000)]
})
self.assertTrue(declaration.save)
def test_duplicate_category_in_declaration(self): def test_duplicate_category_in_declaration(self):
declaration = frappe.get_doc({ declaration = frappe.get_doc({
"doctype": "Employee Tax Exemption Declaration", "doctype": "Employee Tax Exemption Declaration",
"employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"), "employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
"company": erpnext.get_default_company(), "company": erpnext.get_default_company(),
"payroll_period": "_Test Payroll Period", "payroll_period": "_Test Payroll Period",
"declarations": [dict(exemption_sub_category = "_Test Sub Category", "declarations": [
exemption_category = "_Test Category", dict(exemption_sub_category = "_Test Sub Category",
amount = 100000), exemption_category = "_Test Category",
dict(exemption_sub_category = "_Test Sub Category", amount = 100000),
exemption_category = "_Test Category", dict(exemption_sub_category = "_Test Sub Category",
amount = 50000), exemption_category = "_Test Category",
] amount = 50000)
]
}) })
self.assertRaises(frappe.ValidationError, declaration.save) self.assertRaises(frappe.ValidationError, declaration.save)
def test_duplicate_submission_for_payroll_period(self): def test_duplicate_entry_for_payroll_period(self):
declaration = frappe.get_doc({ declaration = frappe.get_doc({
"doctype": "Employee Tax Exemption Declaration", "doctype": "Employee Tax Exemption Declaration",
"employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"), "employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
"company": erpnext.get_default_company(), "company": erpnext.get_default_company(),
"payroll_period": "_Test Payroll Period", "payroll_period": "_Test Payroll Period",
"declarations": [dict(exemption_sub_category = "_Test Sub Category", "declarations": [
exemption_category = "_Test Category", dict(exemption_sub_category = "_Test Sub Category",
amount = 100000), exemption_category = "_Test Category",
dict(exemption_sub_category = "_Test1 Sub Category", amount = 100000),
exemption_category = "_Test Category", dict(exemption_sub_category = "_Test1 Sub Category",
amount = 50000), exemption_category = "_Test Category",
] amount = 50000),
]
}).insert() }).insert()
declaration.submit()
self.assertEquals(declaration.docstatus, 1)
duplicate_declaration = frappe.get_doc({ duplicate_declaration = frappe.get_doc({
"doctype": "Employee Tax Exemption Declaration", "doctype": "Employee Tax Exemption Declaration",
"employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"), "employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
"company": erpnext.get_default_company(), "company": erpnext.get_default_company(),
"payroll_period": "_Test Payroll Period", "payroll_period": "_Test Payroll Period",
"declarations": [dict(exemption_sub_category = "_Test Sub Category", "declarations": [
exemption_category = "_Test Category", dict(exemption_sub_category = "_Test Sub Category",
amount = 100000) exemption_category = "_Test Category",
] amount = 100000)
}).insert() ]
self.assertRaises(frappe.DocstatusTransitionError, duplicate_declaration.submit) })
self.assertRaises(DuplicateDeclarationError, duplicate_declaration.insert)
duplicate_declaration.employee = frappe.get_value("Employee", {"user_id":"employee1@taxexepmtion.com"}, "name") duplicate_declaration.employee = frappe.get_value("Employee", {"user_id":"employee1@taxexepmtion.com"}, "name")
self.assertTrue(duplicate_declaration.submit) self.assertTrue(duplicate_declaration.insert)
def test_exemption_amount(self):
declaration = frappe.get_doc({
"doctype": "Employee Tax Exemption Declaration",
"employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
"company": erpnext.get_default_company(),
"payroll_period": "_Test Payroll Period",
"declarations": [
dict(exemption_sub_category = "_Test Sub Category",
exemption_category = "_Test Category",
amount = 80000),
dict(exemption_sub_category = "_Test1 Sub Category",
exemption_category = "_Test Category",
amount = 60000),
]
}).insert()
self.assertEqual(declaration.total_exemption_amount, 100000)
def create_payroll_period(): def create_payroll_period():
if not frappe.db.exists("Payroll Period", "_Test Payroll Period"): if not frappe.db.exists("Payroll Period", "_Test Payroll Period"):

View File

@@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@@ -19,6 +20,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "exemption_sub_category", "fieldname": "exemption_sub_category",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -53,6 +55,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "exemption_sub_category.exemption_category", "fetch_from": "exemption_sub_category.exemption_category",
"fetch_if_empty": 0,
"fieldname": "exemption_category", "fieldname": "exemption_category",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -70,7 +73,7 @@
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 1,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
@@ -86,7 +89,9 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "amount", "fetch_from": "exemption_sub_category.max_amount",
"fetch_if_empty": 0,
"fieldname": "max_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
@@ -95,7 +100,40 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Amount", "label": "Maximum Exemption Amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "amount",
"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": "Declared Amount",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@@ -122,7 +160,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-05-29 15:58:05.779031", "modified": "2019-04-25 15:45:11.279158",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Employee Tax Exemption Declaration Category", "name": "Employee Tax Exemption Declaration Category",
@@ -136,5 +174,6 @@
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 1,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@@ -10,6 +10,7 @@ frappe.ui.form.on('Employee Tax Exemption Proof Submission', {
} }
} }
}); });
frm.set_query('payroll_period', function() { frm.set_query('payroll_period', function() {
if(frm.doc.employee && frm.doc.company){ if(frm.doc.employee && frm.doc.company){
return { return {
@@ -21,6 +22,7 @@ frappe.ui.form.on('Employee Tax Exemption Proof Submission', {
frappe.msgprint(__("Please select Employee")); frappe.msgprint(__("Please select Employee"));
} }
}); });
frm.set_query('exemption_sub_category', 'tax_exemption_proofs', function() { frm.set_query('exemption_sub_category', 'tax_exemption_proofs', function() {
return { return {
filters: { filters: {
@@ -29,11 +31,28 @@ frappe.ui.form.on('Employee Tax Exemption Proof Submission', {
} }
}); });
}, },
employee: function(frm){
if(frm.doc.employee){ refresh: function(frm) {
frm.add_fetch('employee', 'company', 'company'); if(frm.doc.docstatus === 0) {
}else{ let filters = {
frm.set_value('company', ''); docstatus: 1,
company: frm.doc.company
};
if(frm.doc.employee) filters["employee"] = frm.doc.employee;
if(frm.doc.payroll_period) filters["payroll_period"] = frm.doc.payroll_period;
frm.add_custom_button(__('Get Details From Declaration'), function() {
erpnext.utils.map_current_doc({
method: "erpnext.hr.doctype.employee_tax_exemption_declaration.employee_tax_exemption_declaration.make_proof_submission",
source_doctype: "Employee Tax Exemption Declaration",
target: frm,
date_field: "creation",
setters: {
employee: frm.doc.employee || undefined
},
get_query_filters: filters
});
});
} }
} }
}); });

View File

@@ -1,8 +1,9 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 1,
"allow_rename": 0, "allow_rename": 1,
"autoname": "HR-TAX-PRF-.YYYY.-.#####", "autoname": "HR-TAX-PRF-.YYYY.-.#####",
"beta": 0, "beta": 0,
"creation": "2018-04-13 17:24:11.456132", "creation": "2018-04-13 17:24:11.456132",
@@ -20,6 +21,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "employee", "fieldname": "employee",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -53,8 +55,10 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "company", "fetch_from": "employee.employee_name",
"fieldtype": "Link", "fetch_if_empty": 0,
"fieldname": "employee_name",
"fieldtype": "Data",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@@ -62,10 +66,9 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Company", "label": "Employee Name",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Company",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
@@ -79,70 +82,6 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "payroll_period",
"fieldtype": "Link",
"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": "Payroll Period",
"length": 0,
"no_copy": 0,
"options": "Payroll Period",
"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": 0
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@@ -151,6 +90,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "employee.department", "fetch_from": "employee.department",
"fetch_if_empty": 0,
"fieldname": "department", "fieldname": "department",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -184,8 +124,9 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "submission_date", "fetch_if_empty": 0,
"fieldtype": "Date", "fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@@ -193,7 +134,6 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Submission Date",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@@ -216,6 +156,273 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "Today",
"fetch_if_empty": 0,
"fieldname": "submission_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": "Submission Date",
"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": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "payroll_period",
"fieldtype": "Link",
"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": "Payroll Period",
"length": 0,
"no_copy": 0,
"options": "Payroll Period",
"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": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.company",
"fetch_if_empty": 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,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "tax_exemption_proofs",
"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": "Tax Exemption Proofs",
"length": 0,
"no_copy": 0,
"options": "Employee Tax Exemption Proof Submission Detail",
"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,
"fetch_if_empty": 0,
"fieldname": "section_break_10",
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "total_actual_amount",
"fieldtype": "Currency",
"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": "Total Actual Amount",
"length": 0,
"no_copy": 0,
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_12",
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "exemption_amount", "fieldname": "exemption_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -248,70 +455,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "section_break_5", "fetch_if_empty": 0,
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "tax_exemption_proofs",
"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": "Tax Exemption Proofs",
"length": 0,
"no_copy": 0,
"options": "Employee Tax Exemption Proof Submission Detail",
"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": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "attachment_section", "fieldname": "attachment_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -344,6 +488,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "attachments", "fieldname": "attachments",
"fieldtype": "Attach", "fieldtype": "Attach",
"hidden": 0, "hidden": 0,
@@ -376,6 +521,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "amended_from", "fieldname": "amended_from",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -412,7 +558,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-08-21 16:15:38.096846", "modified": "2019-04-25 17:06:36.569549",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Employee Tax Exemption Proof Submission", "name": "Employee Tax Exemption Proof Submission",

View File

@@ -6,20 +6,30 @@ 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 erpnext.hr.utils import validate_tax_declaration, calculate_hra_exemption_for_period from frappe.utils import flt
from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, calculate_hra_exemption_for_period
class EmployeeTaxExemptionProofSubmission(Document): class EmployeeTaxExemptionProofSubmission(Document):
def validate(self): def validate(self):
validate_tax_declaration(self.tax_exemption_proofs) validate_tax_declaration(self.tax_exemption_proofs)
self.exemption_amount = 0 self.set_total_actual_amount()
self.set_total_exemption_amount()
self.calculate_hra_exemption() self.calculate_hra_exemption()
for proof in self.tax_exemption_proofs:
self.exemption_amount += proof.amount def set_total_actual_amount(self):
self.total_actual_amount = flt(self.get("house_rent_payment_amount"))
for d in self.tax_exemption_proofs:
self.total_actual_amount += flt(d.amount)
def set_total_exemption_amount(self):
self.exemption_amount = get_total_exemption_amount(self.tax_exemption_proofs)
def calculate_hra_exemption(self): def calculate_hra_exemption(self):
hra_exemption = calculate_hra_exemption_for_period(self) self.monthly_hra_exemption, self.monthly_house_rent, self.total_eligible_hra_exemption = 0, 0, 0
if hra_exemption: if self.get("house_rent_payment_amount"):
self.exemption_amount += hra_exemption["total_eligible_hra_exemption"] hra_exemption = calculate_hra_exemption_for_period(self)
self.monthly_hra_exemption = hra_exemption["monthly_exemption"] if hra_exemption:
self.monthly_house_rent = hra_exemption["monthly_house_rent"] self.exemption_amount += hra_exemption["total_eligible_hra_exemption"]
self.total_eligible_hra_exemption = hra_exemption["total_eligible_hra_exemption"] self.monthly_hra_exemption = hra_exemption["monthly_exemption"]
self.monthly_house_rent = hra_exemption["monthly_house_rent"]
self.total_eligible_hra_exemption = hra_exemption["total_eligible_hra_exemption"]

View File

@@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@@ -14,10 +15,12 @@
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "exemption_sub_category", "fieldname": "exemption_sub_category",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -46,11 +49,13 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "exemption_sub_category.exemption_category", "fetch_from": "exemption_sub_category.exemption_category",
"fetch_if_empty": 0,
"fieldname": "exemption_category", "fieldname": "exemption_category",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "hidden": 0,
@@ -79,10 +84,46 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "exemption_sub_category.max_amount",
"fetch_if_empty": 0,
"fieldname": "max_amount",
"fieldtype": "Currency",
"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": "Maximum Exemption Amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"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,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "type_of_proof", "fieldname": "type_of_proof",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -111,10 +152,12 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "amount", "fieldname": "amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -124,7 +167,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Amount", "label": "Actual Amount",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@@ -134,7 +177,7 @@
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0, "translatable": 0,
@@ -151,7 +194,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-05-16 22:42:59.750733", "modified": "2019-04-25 15:45:03.154904",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Employee Tax Exemption Proof Submission Detail", "name": "Employee Tax Exemption Proof Submission Detail",
@@ -165,5 +208,6 @@
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 1,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 1, "allow_rename": 1,
@@ -15,10 +16,12 @@
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "exemption_category", "fieldname": "exemption_category",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -26,8 +29,8 @@
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 1,
"label": "Tax Exemption Category", "label": "Tax Exemption Category",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@@ -42,14 +45,18 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "exemption_category.max_amount",
"fetch_if_empty": 1,
"fieldname": "max_amount", "fieldname": "max_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -59,7 +66,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Max Amount", "label": "Max Exemption Amount",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@@ -69,17 +76,21 @@
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "1",
"fetch_if_empty": 0,
"fieldname": "is_active", "fieldname": "is_active",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -102,6 +113,7 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
} }
], ],
@@ -115,7 +127,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-05-09 13:25:01.595240", "modified": "2019-04-25 13:24:05.164877",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Employee Tax Exemption Sub Category", "name": "Employee Tax Exemption Sub Category",
@@ -124,7 +136,6 @@
"permissions": [ "permissions": [
{ {
"amend": 0, "amend": 0,
"apply_user_permissions": 0,
"cancel": 0, "cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
@@ -144,7 +155,6 @@
}, },
{ {
"amend": 0, "amend": 0,
"apply_user_permissions": 0,
"cancel": 0, "cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
@@ -164,7 +174,6 @@
}, },
{ {
"amend": 0, "amend": 0,
"apply_user_permissions": 0,
"cancel": 0, "cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
@@ -189,6 +198,7 @@
"show_name_in_global_search": 0, "show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 0,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@@ -4,7 +4,13 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _
from frappe.utils import flt
from frappe.model.document import Document from frappe.model.document import Document
class EmployeeTaxExemptionSubCategory(Document): class EmployeeTaxExemptionSubCategory(Document):
pass def validate(self):
category_max_amount = frappe.db.get_value("Employee Tax Exemption Category", self.exemption_category, "max_amount")
if flt(self.max_amount) > flt(category_max_amount):
frappe.throw(_("Max Exemption Amount cannot be greater than maximum exemption amount {0} of Tax Exemption Category {1}")
.format(category_max_amount, self.exemption_category))

View File

@@ -135,6 +135,7 @@ class LeaveApplication(Document):
date = dt.strftime("%Y-%m-%d") date = dt.strftime("%Y-%m-%d")
doc = frappe.new_doc("Attendance") doc = frappe.new_doc("Attendance")
doc.employee = self.employee doc.employee = self.employee
doc.employee_name = self.employee_name
doc.attendance_date = date doc.attendance_date = date
doc.company = self.company doc.company = self.company
doc.leave_type = self.leave_type doc.leave_type = self.leave_type

View File

@@ -75,5 +75,5 @@ var set_value_for_condition_and_formula = function(frm) {
frm.set_value("amount_based_on_formula", 0); frm.set_value("amount_based_on_formula", 0);
frm.set_value("statistical_component", 0); frm.set_value("statistical_component", 0);
frm.set_value("do_not_include_in_total", 0); frm.set_value("do_not_include_in_total", 0);
frm.set_value("depends_on_lwp", 0); frm.set_value("depends_on_payment_days", 0);
}; };

View File

@@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 1, "allow_rename": 1,
@@ -19,6 +20,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "salary_component", "fieldname": "salary_component",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -51,6 +53,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "salary_component_abbr", "fieldname": "salary_component_abbr",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -85,6 +88,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "type", "fieldname": "type",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -119,6 +123,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.is_flexible_benefit != 1", "depends_on": "eval:doc.is_flexible_benefit != 1",
"fetch_if_empty": 0,
"fieldname": "is_additional_component", "fieldname": "is_additional_component",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -153,6 +158,7 @@
"columns": 0, "columns": 0,
"default": "1", "default": "1",
"depends_on": "eval:doc.type == \"Earning\"", "depends_on": "eval:doc.type == \"Earning\"",
"fetch_if_empty": 0,
"fieldname": "is_tax_applicable", "fieldname": "is_tax_applicable",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -186,6 +192,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "1", "default": "1",
"fetch_if_empty": 0,
"fieldname": "is_payable", "fieldname": "is_payable",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -218,7 +225,9 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "depends_on_lwp", "default": "1",
"fetch_if_empty": 0,
"fieldname": "depends_on_payment_days",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
@@ -227,7 +236,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Depends on Leave Without Pay", "label": "Depends on Payment Days",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@@ -250,6 +259,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "do_not_include_in_total", "fieldname": "do_not_include_in_total",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -282,6 +292,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_4", "fieldname": "column_break_4",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -313,6 +324,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "disabled", "fieldname": "disabled",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -345,6 +357,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "description", "fieldname": "description",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
@@ -378,6 +391,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ", "description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ",
"fetch_if_empty": 0,
"fieldname": "statistical_component", "fieldname": "statistical_component",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -411,6 +425,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.type==\"Earning\" && doc.is_additional_component != 1 && doc.statistical_component!=1", "depends_on": "eval:doc.type==\"Earning\" && doc.is_additional_component != 1 && doc.statistical_component!=1",
"fetch_if_empty": 0,
"fieldname": "flexible_benefits", "fieldname": "flexible_benefits",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -444,6 +459,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.is_additional_component != 1", "depends_on": "eval:doc.is_additional_component != 1",
"fetch_if_empty": 0,
"fieldname": "is_flexible_benefit", "fieldname": "is_flexible_benefit",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -477,6 +493,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "is_flexible_benefit", "depends_on": "is_flexible_benefit",
"fetch_if_empty": 0,
"fieldname": "max_benefit_amount", "fieldname": "max_benefit_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -509,6 +526,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_9", "fieldname": "column_break_9",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -541,6 +559,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "is_flexible_benefit", "depends_on": "is_flexible_benefit",
"fetch_if_empty": 0,
"fieldname": "pay_against_benefit_claim", "fieldname": "pay_against_benefit_claim",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -574,6 +593,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.is_flexible_benefit == 1 & doc.create_separate_payment_entry_against_benefit_claim !=1", "depends_on": "eval:doc.is_flexible_benefit == 1 & doc.create_separate_payment_entry_against_benefit_claim !=1",
"fetch_if_empty": 0,
"fieldname": "only_tax_impact", "fieldname": "only_tax_impact",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -607,6 +627,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.is_flexible_benefit == 1 & doc.only_tax_impact !=1", "depends_on": "eval:doc.is_flexible_benefit == 1 & doc.only_tax_impact !=1",
"fetch_if_empty": 0,
"fieldname": "create_separate_payment_entry_against_benefit_claim", "fieldname": "create_separate_payment_entry_against_benefit_claim",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -640,6 +661,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.type=='Deduction'", "depends_on": "eval:doc.type=='Deduction'",
"fetch_if_empty": 0,
"fieldname": "section_break_11", "fieldname": "section_break_11",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -671,6 +693,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "variable_based_on_taxable_salary", "fieldname": "variable_based_on_taxable_salary",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -704,6 +727,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.statistical_component != 1", "depends_on": "eval:doc.statistical_component != 1",
"fetch_if_empty": 0,
"fieldname": "section_break_5", "fieldname": "section_break_5",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -736,6 +760,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "accounts", "fieldname": "accounts",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -771,6 +796,7 @@
"collapsible_depends_on": "", "collapsible_depends_on": "",
"columns": 0, "columns": 0,
"depends_on": "eval:doc.is_flexible_benefit != 1 && doc.variable_based_on_taxable_salary != 1", "depends_on": "eval:doc.is_flexible_benefit != 1 && doc.variable_based_on_taxable_salary != 1",
"fetch_if_empty": 0,
"fieldname": "condition_and_formula", "fieldname": "condition_and_formula",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -803,6 +829,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "condition", "fieldname": "condition",
"fieldtype": "Code", "fieldtype": "Code",
"hidden": 0, "hidden": 0,
@@ -836,6 +863,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "", "default": "",
"fetch_if_empty": 0,
"fieldname": "amount_based_on_formula", "fieldname": "amount_based_on_formula",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -869,6 +897,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.amount_based_on_formula!==0", "depends_on": "eval:doc.amount_based_on_formula!==0",
"fetch_if_empty": 0,
"fieldname": "formula", "fieldname": "formula",
"fieldtype": "Code", "fieldtype": "Code",
"hidden": 0, "hidden": 0,
@@ -902,6 +931,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.amount_based_on_formula!==1", "depends_on": "eval:doc.amount_based_on_formula!==1",
"fetch_if_empty": 0,
"fieldname": "amount", "fieldname": "amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -934,6 +964,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_28", "fieldname": "column_break_28",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -965,6 +996,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "help", "fieldname": "help",
"fieldtype": "HTML", "fieldtype": "HTML",
"hidden": 0, "hidden": 0,
@@ -1003,7 +1035,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-09-20 16:44:58.876044", "modified": "2019-04-16 19:08:55.323567",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Salary Component", "name": "Salary Component",

View File

@@ -19,6 +19,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "salary_component", "fieldname": "salary_component",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -55,6 +56,7 @@
"default": "", "default": "",
"depends_on": "eval:doc.parenttype=='Salary Structure'", "depends_on": "eval:doc.parenttype=='Salary Structure'",
"fetch_from": "salary_component.salary_component_abbr", "fetch_from": "salary_component.salary_component_abbr",
"fetch_if_empty": 0,
"fieldname": "abbr", "fieldname": "abbr",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -88,6 +90,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_3", "fieldname": "column_break_3",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -121,6 +124,7 @@
"columns": 0, "columns": 0,
"description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ", "description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ",
"fetch_from": "salary_component.statistical_component", "fetch_from": "salary_component.statistical_component",
"fetch_if_empty": 0,
"fieldname": "statistical_component", "fieldname": "statistical_component",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -154,6 +158,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "salary_component.is_tax_applicable", "fetch_from": "salary_component.is_tax_applicable",
"fetch_if_empty": 0,
"fieldname": "is_tax_applicable", "fieldname": "is_tax_applicable",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -187,6 +192,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "salary_component.is_flexible_benefit", "fetch_from": "salary_component.is_flexible_benefit",
"fetch_if_empty": 0,
"fieldname": "is_flexible_benefit", "fieldname": "is_flexible_benefit",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -221,6 +227,7 @@
"columns": 0, "columns": 0,
"default": "", "default": "",
"fetch_from": "salary_component.is_additional_component", "fetch_from": "salary_component.is_additional_component",
"fetch_if_empty": 0,
"fieldname": "is_additional_component", "fieldname": "is_additional_component",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 1, "hidden": 1,
@@ -255,6 +262,7 @@
"columns": 0, "columns": 0,
"default": "", "default": "",
"fetch_from": "salary_component.variable_based_on_taxable_salary", "fetch_from": "salary_component.variable_based_on_taxable_salary",
"fetch_if_empty": 0,
"fieldname": "variable_based_on_taxable_salary", "fieldname": "variable_based_on_taxable_salary",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -288,8 +296,9 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_from": "salary_component.depends_on_lwp", "fetch_from": "salary_component.depends_on_payment_days",
"fieldname": "depends_on_lwp", "fetch_if_empty": 0,
"fieldname": "depends_on_payment_days",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
@@ -298,7 +307,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Depends on Leave Without Pay", "label": "Depends on Payment Days",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@@ -322,6 +331,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.is_flexible_benefit != 1", "depends_on": "eval:doc.is_flexible_benefit != 1",
"fetch_if_empty": 0,
"fieldname": "section_break_2", "fieldname": "section_break_2",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -354,6 +364,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.parenttype=='Salary Structure'", "depends_on": "eval:doc.parenttype=='Salary Structure'",
"fetch_if_empty": 0,
"fieldname": "condition", "fieldname": "condition",
"fieldtype": "Code", "fieldtype": "Code",
"hidden": 0, "hidden": 0,
@@ -389,6 +400,7 @@
"default": "0", "default": "0",
"depends_on": "eval:doc.parenttype=='Salary Structure'", "depends_on": "eval:doc.parenttype=='Salary Structure'",
"fetch_from": "", "fetch_from": "",
"fetch_if_empty": 0,
"fieldname": "amount_based_on_formula", "fieldname": "amount_based_on_formula",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -425,6 +437,7 @@
"default": "", "default": "",
"depends_on": "eval:doc.amount_based_on_formula!==0 && doc.parenttype==='Salary Structure'", "depends_on": "eval:doc.amount_based_on_formula!==0 && doc.parenttype==='Salary Structure'",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "formula", "fieldname": "formula",
"fieldtype": "Code", "fieldtype": "Code",
"hidden": 0, "hidden": 0,
@@ -458,6 +471,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.amount_based_on_formula!==1 || doc.parenttype==='Salary Slip'", "depends_on": "eval:doc.amount_based_on_formula!==1 || doc.parenttype==='Salary Slip'",
"fetch_if_empty": 0,
"fieldname": "amount", "fieldname": "amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -491,6 +505,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "do_not_include_in_total", "fieldname": "do_not_include_in_total",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -524,6 +539,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.parenttype=='Salary Structure'", "depends_on": "eval:doc.parenttype=='Salary Structure'",
"fetch_if_empty": 0,
"fieldname": "default_amount", "fieldname": "default_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -558,6 +574,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.parenttype=='Salary Slip' && doc.parentfield=='deductions' && doc.variable_based_on_taxable_salary == 1", "depends_on": "eval:doc.parenttype=='Salary Slip' && doc.parentfield=='deductions' && doc.variable_based_on_taxable_salary == 1",
"fetch_if_empty": 0,
"fieldname": "tax_on_flexible_benefit", "fieldname": "tax_on_flexible_benefit",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -591,6 +608,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.parenttype=='Salary Slip' && doc.parentfield=='deductions' && doc.variable_based_on_taxable_salary == 1", "depends_on": "eval:doc.parenttype=='Salary Slip' && doc.parentfield=='deductions' && doc.variable_based_on_taxable_salary == 1",
"fetch_if_empty": 0,
"fieldname": "tax_on_additional_salary", "fieldname": "tax_on_additional_salary",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -624,6 +642,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.parenttype=='Salary Structure'", "depends_on": "eval:doc.parenttype=='Salary Structure'",
"fetch_if_empty": 0,
"fieldname": "section_break_11", "fieldname": "section_break_11",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -656,6 +675,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.parenttype=='Salary Structure'", "depends_on": "eval:doc.parenttype=='Salary Structure'",
"fetch_if_empty": 0,
"fieldname": "condition_and_formula_help", "fieldname": "condition_and_formula_help",
"fieldtype": "HTML", "fieldtype": "HTML",
"hidden": 0, "hidden": 0,
@@ -693,7 +713,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2019-02-04 14:41:56.030991", "modified": "2019-04-16 19:09:31.726597",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Salary Detail", "name": "Salary Detail",

View File

@@ -132,9 +132,6 @@ var get_emp_and_leave_details = function(doc, dt, dn) {
}); });
} }
cur_frm.cscript.employee = function(doc,dt,dn){
get_emp_and_leave_details(doc, dt, dn);
}
cur_frm.cscript.leave_without_pay = function(doc,dt,dn){ cur_frm.cscript.leave_without_pay = function(doc,dt,dn){
if (doc.employee && doc.start_date && doc.end_date) { if (doc.employee && doc.start_date && doc.end_date) {
@@ -160,7 +157,7 @@ cur_frm.cscript.amount = function(doc,dt,dn){
calculate_all(doc, dt, dn); calculate_all(doc, dt, dn);
} }
cur_frm.cscript.depends_on_lwp = function(doc,dt,dn){ cur_frm.cscript.depends_on_payment_days = function(doc,dt,dn){
calculate_earning_total(doc, dt, dn, true); calculate_earning_total(doc, dt, dn, true);
calculate_ded_total(doc, dt, dn, true); calculate_ded_total(doc, dt, dn, true);
calculate_net_pay(doc, dt, dn); calculate_net_pay(doc, dt, dn);
@@ -174,7 +171,7 @@ var calculate_earning_total = function(doc, dt, dn, reset_amount) {
var tbl = doc.earnings || []; var tbl = doc.earnings || [];
var total_earn = 0; var total_earn = 0;
for(var i = 0; i < tbl.length; i++){ for(var i = 0; i < tbl.length; i++){
if(cint(tbl[i].depends_on_lwp) == 1) { if(cint(tbl[i].depends_on_payment_days) == 1) {
tbl[i].amount = Math.round(tbl[i].default_amount)*(flt(doc.payment_days) / tbl[i].amount = Math.round(tbl[i].default_amount)*(flt(doc.payment_days) /
cint(doc.total_working_days)*100)/100; cint(doc.total_working_days)*100)/100;
} else if(reset_amount && tbl[i].default_amount) { } else if(reset_amount && tbl[i].default_amount) {
@@ -196,7 +193,7 @@ var calculate_ded_total = function(doc, dt, dn, reset_amount) {
var tbl = doc.deductions || []; var tbl = doc.deductions || [];
var total_ded = 0; var total_ded = 0;
for(var i = 0; i < tbl.length; i++){ for(var i = 0; i < tbl.length; i++){
if(cint(tbl[i].depends_on_lwp) == 1) { if(cint(tbl[i].depends_on_payment_days) == 1) {
tbl[i].amount = Math.round(tbl[i].default_amount)*(flt(doc.payment_days)/cint(doc.total_working_days)*100)/100; tbl[i].amount = Math.round(tbl[i].default_amount)*(flt(doc.payment_days)/cint(doc.total_working_days)*100)/100;
} else if(reset_amount && tbl[i].default_amount) { } else if(reset_amount && tbl[i].default_amount) {
tbl[i].amount = tbl[i].default_amount; tbl[i].amount = tbl[i].default_amount;
@@ -209,16 +206,12 @@ var calculate_ded_total = function(doc, dt, dn, reset_amount) {
refresh_many(['deductions', 'total_deduction']); refresh_many(['deductions', 'total_deduction']);
} }
// Calculate net payable amount
// ------------------------------------------------------------------------
var calculate_net_pay = function(doc, dt, dn) { var calculate_net_pay = function(doc, dt, dn) {
doc.net_pay = flt(doc.gross_pay) - flt(doc.total_deduction); doc.net_pay = flt(doc.gross_pay) - flt(doc.total_deduction);
doc.rounded_total = Math.round(doc.net_pay); doc.rounded_total = Math.round(doc.net_pay);
refresh_many(['net_pay', 'rounded_total']); refresh_many(['net_pay', 'rounded_total']);
} }
// validate
// ------------------------------------------------------------------------
cur_frm.cscript.validate = function(doc, dt, dn) { cur_frm.cscript.validate = function(doc, dt, dn) {
calculate_all(doc, dt, dn); calculate_all(doc, dt, dn);
} }

View File

@@ -131,11 +131,12 @@ class SalarySlip(TransactionBase):
for d in self.get(key): for d in self.get(key):
if d.salary_component == struct_row.salary_component: if d.salary_component == struct_row.salary_component:
component_row = d component_row = d
if not component_row: if not component_row:
self.append(key, { self.append(key, {
'amount': amount, 'amount': amount,
'default_amount': amount, 'default_amount': amount,
'depends_on_lwp' : struct_row.depends_on_lwp, 'depends_on_payment_days' : struct_row.depends_on_payment_days,
'salary_component' : struct_row.salary_component, 'salary_component' : struct_row.salary_component,
'abbr' : struct_row.abbr, 'abbr' : struct_row.abbr,
'do_not_include_in_total' : struct_row.do_not_include_in_total, 'do_not_include_in_total' : struct_row.do_not_include_in_total,
@@ -147,12 +148,11 @@ class SalarySlip(TransactionBase):
'tax_on_additional_salary': additional_tax 'tax_on_additional_salary': additional_tax
}) })
else: else:
if overwrite: if not overwrite:
component_row.default_amount = amount amount += struct_row.get("default_amount", 0)
component_row.amount = amount
else: component_row.default_amount = amount
component_row.default_amount += amount component_row.amount = amount
component_row.amount = component_row.default_amount
component_row.tax_on_flexible_benefit = benefit_tax component_row.tax_on_flexible_benefit = benefit_tax
component_row.tax_on_additional_salary = additional_tax component_row.tax_on_additional_salary = additional_tax
@@ -167,7 +167,7 @@ class SalarySlip(TransactionBase):
if d.amount_based_on_formula: if d.amount_based_on_formula:
formula = d.formula.strip() if d.formula else None formula = d.formula.strip() if d.formula else None
if formula: if formula:
amount = frappe.safe_eval(formula, self.whitelisted_globals, data) amount = rounded(frappe.safe_eval(formula, self.whitelisted_globals, data))
if amount: if amount:
data[d.abbr] = amount data[d.abbr] = amount
@@ -418,7 +418,7 @@ class SalarySlip(TransactionBase):
for d in self.get(component_type): for d in self.get(component_type):
if (self.salary_structure and if (self.salary_structure and
cint(d.depends_on_lwp) and cint(d.depends_on_payment_days) and
(not (not
self.salary_slip_based_on_timesheet or self.salary_slip_based_on_timesheet or
getdate(self.start_date) < joining_date or getdate(self.start_date) < joining_date or
@@ -431,7 +431,7 @@ class SalarySlip(TransactionBase):
) )
elif not self.payment_days and not self.salary_slip_based_on_timesheet and \ elif not self.payment_days and not self.salary_slip_based_on_timesheet and \
cint(d.depends_on_lwp): cint(d.depends_on_payment_days):
d.amount = 0 d.amount = 0
elif not d.amount: elif not d.amount:
d.amount = d.default_amount d.amount = d.default_amount
@@ -599,12 +599,11 @@ class SalarySlip(TransactionBase):
annual_earning = taxable_earning["taxable_earning"] * period_factor annual_earning = taxable_earning["taxable_earning"] * period_factor
exemption_amount = 0 exemption_amount = 0
if frappe.db.exists("Employee Tax Exemption Declaration", {"employee": self.employee, if frappe.db.exists("Employee Tax Exemption Declaration", {"employee": self.employee,
"payroll_period": payroll_period.name, "docstatus": 1}): "payroll_period": payroll_period.name, "docstatus": 1}):
exemption_amount = frappe.db.get_value("Employee Tax Exemption Declaration", exemption_amount = frappe.db.get_value("Employee Tax Exemption Declaration",
{"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1}, {"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1},
"total_exemption_amount") "total_exemption_amount")
annual_taxable_earning = annual_earning - exemption_amount annual_taxable_earning = annual_earning - exemption_amount
if self.deduct_tax_for_unclaimed_employee_benefits or self.deduct_tax_for_unsubmitted_tax_exemption_proof: if self.deduct_tax_for_unclaimed_employee_benefits or self.deduct_tax_for_unsubmitted_tax_exemption_proof:
tax_detail = self.get_tax_paid_in_period(payroll_period, tax_component) tax_detail = self.get_tax_paid_in_period(payroll_period, tax_component)
if tax_detail: if tax_detail:
@@ -736,22 +735,24 @@ class SalarySlip(TransactionBase):
# less paid taxes # less paid taxes
if args.get("pro_rata_tax_paid"): if args.get("pro_rata_tax_paid"):
tax_amount -= args.get("pro_rata_tax_paid") tax_amount -= args.get("pro_rata_tax_paid")
tax_amount = rounded(tax_amount)
struct_row = self.get_salary_slip_row(args.get("tax_component")) struct_row = self.get_salary_slip_row(args.get("tax_component"))
return [struct_row, tax_amount, benefit_tax, additional_tax] return [struct_row, tax_amount, benefit_tax, additional_tax]
def calculate_tax_by_tax_slab(self, payroll_period, annual_earning): def calculate_tax_by_tax_slab(self, payroll_period, annual_taxable_earning):
payroll_period_obj = frappe.get_doc("Payroll Period", payroll_period) payroll_period_obj = frappe.get_doc("Payroll Period", payroll_period)
data = self.get_data_for_eval() data = self.get_data_for_eval()
data.update({"annual_taxable_earning": annual_taxable_earning})
taxable_amount = 0 taxable_amount = 0
for slab in payroll_period_obj.taxable_salary_slabs: for slab in payroll_period_obj.taxable_salary_slabs:
if slab.condition and not self.eval_tax_slab_condition(slab.condition, data): if slab.condition and not self.eval_tax_slab_condition(slab.condition, data):
continue continue
if not slab.to_amount and annual_earning > slab.from_amount: if not slab.to_amount and annual_taxable_earning > slab.from_amount:
taxable_amount += (annual_earning - slab.from_amount) * slab.percent_deduction *.01 taxable_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
continue continue
if annual_earning > slab.from_amount and annual_earning < slab.to_amount: if annual_taxable_earning > slab.from_amount and annual_taxable_earning < slab.to_amount:
taxable_amount += (annual_earning - slab.from_amount) * slab.percent_deduction *.01 taxable_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
elif annual_earning > slab.from_amount and annual_earning > slab.to_amount: elif annual_taxable_earning > slab.from_amount and annual_taxable_earning > slab.to_amount:
taxable_amount += (slab.to_amount - slab.from_amount) * slab.percent_deduction * .01 taxable_amount += (slab.to_amount - slab.from_amount) * slab.percent_deduction * .01
return taxable_amount return taxable_amount
@@ -770,13 +771,21 @@ class SalarySlip(TransactionBase):
def get_period_factor(self, period_start, period_end, start_date=None, end_date=None): def get_period_factor(self, period_start, period_end, start_date=None, end_date=None):
# TODO if both deduct checked update the factor to make tax consistent # TODO if both deduct checked update the factor to make tax consistent
joining_date, relieving_date = frappe.db.get_value("Employee", self.employee, ["date_of_joining", "relieving_date"])
if getdate(joining_date) > getdate(period_start):
period_start = joining_date
if relieving_date and getdate(relieving_date) < getdate(period_end):
period_end = relieving_date
payroll_days = date_diff(period_end, period_start) + 1 payroll_days = date_diff(period_end, period_start) + 1
if start_date and end_date: if start_date and end_date:
salary_days = date_diff(end_date, start_date) + 1 salary_days = date_diff(end_date, start_date) + 1
return flt(payroll_days)/flt(salary_days) return flt(payroll_days)/flt(salary_days)
# if period configured for a year and monthly frequency return 12 to make tax calc consistent # if period configured for a year and monthly frequency return 12 to make tax calc consistent
if 360 <= payroll_days <= 370 and self.payroll_frequency == "Monthly": if 360 <= payroll_days <= 370 and self.payroll_frequency == "Monthly":
return 12 return 12
salary_days = date_diff(self.end_date, self.start_date) + 1 salary_days = date_diff(self.end_date, self.start_date) + 1
return flt(payroll_days)/flt(salary_days) return flt(payroll_days)/flt(salary_days)
@@ -784,7 +793,7 @@ class SalarySlip(TransactionBase):
component = frappe.get_doc("Salary Component", salary_component) component = frappe.get_doc("Salary Component", salary_component)
# Data for update_component_row # Data for update_component_row
struct_row = {} struct_row = {}
struct_row['depends_on_lwp'] = component.depends_on_lwp struct_row['depends_on_payment_days'] = component.depends_on_payment_days
struct_row['salary_component'] = component.name struct_row['salary_component'] = component.name
struct_row['abbr'] = component.salary_component_abbr struct_row['abbr'] = component.salary_component_abbr
struct_row['do_not_include_in_total'] = component.do_not_include_in_total struct_row['do_not_include_in_total'] = component.do_not_include_in_total

View File

@@ -13,7 +13,8 @@ from frappe.utils import getdate, nowdate, add_days, add_months, flt, get_first_
from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
from erpnext.hr.doctype.payroll_entry.payroll_entry import get_month_details from erpnext.hr.doctype.payroll_entry.payroll_entry import get_month_details
from erpnext.hr.doctype.employee.test_employee import make_employee from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.hr.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration import create_payroll_period, create_exemption_category from erpnext.hr.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration \
import create_payroll_period, create_exemption_category
class TestSalarySlip(unittest.TestCase): class TestSalarySlip(unittest.TestCase):
def setUp(self): def setUp(self):
@@ -36,8 +37,10 @@ class TestSalarySlip(unittest.TestCase):
no_of_days = self.get_no_of_days() no_of_days = self.get_no_of_days()
frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 1) frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 1)
make_employee("test_employee@salary.com") make_employee("test_employee@salary.com")
frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None) frappe.db.set_value("Employee", frappe.get_value("Employee",
frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active") {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None)
frappe.db.set_value("Employee", frappe.get_value("Employee",
{"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
ss = make_employee_salary_slip("test_employee@salary.com", "Monthly") ss = make_employee_salary_slip("test_employee@salary.com", "Monthly")
self.assertEqual(ss.total_working_days, no_of_days[0]) self.assertEqual(ss.total_working_days, no_of_days[0])
@@ -53,8 +56,10 @@ class TestSalarySlip(unittest.TestCase):
no_of_days = self.get_no_of_days() no_of_days = self.get_no_of_days()
frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0) frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0)
make_employee("test_employee@salary.com") make_employee("test_employee@salary.com")
frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None) frappe.db.set_value("Employee", frappe.get_value("Employee",
frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active") {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None)
frappe.db.set_value("Employee", frappe.get_value("Employee",
{"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
ss = make_employee_salary_slip("test_employee@salary.com", "Monthly") ss = make_employee_salary_slip("test_employee@salary.com", "Monthly")
self.assertEqual(ss.total_working_days, no_of_days[0] - no_of_days[1]) self.assertEqual(ss.total_working_days, no_of_days[0] - no_of_days[1])
@@ -100,16 +105,21 @@ class TestSalarySlip(unittest.TestCase):
self.assertEqual(ss.payment_days, (no_of_days[0] - getdate(date_of_joining).day + 1)) self.assertEqual(ss.payment_days, (no_of_days[0] - getdate(date_of_joining).day + 1))
# set relieving date in the same month # set relieving date in the same month
frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "date_of_joining", (add_days(nowdate(),-60))) frappe.db.set_value("Employee",frappe.get_value("Employee",
frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", relieving_date) {"employee_name":"test_employee@salary.com"}, "name"), "date_of_joining", (add_days(nowdate(),-60)))
frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "status", "Left") frappe.db.set_value("Employee", frappe.get_value("Employee",
{"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", relieving_date)
frappe.db.set_value("Employee", frappe.get_value("Employee",
{"employee_name":"test_employee@salary.com"}, "name"), "status", "Left")
ss.save() ss.save()
self.assertEqual(ss.total_working_days, no_of_days[0]) self.assertEqual(ss.total_working_days, no_of_days[0])
self.assertEqual(ss.payment_days, getdate(relieving_date).day) self.assertEqual(ss.payment_days, getdate(relieving_date).day)
frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None) frappe.db.set_value("Employee", frappe.get_value("Employee",
frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active") {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None)
frappe.db.set_value("Employee", frappe.get_value("Employee",
{"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
def test_employee_salary_slip_read_permission(self): def test_employee_salary_slip_read_permission(self):
make_employee("test_employee@salary.com") make_employee("test_employee@salary.com")
@@ -168,17 +178,22 @@ class TestSalarySlip(unittest.TestCase):
def test_tax_for_payroll_period(self): def test_tax_for_payroll_period(self):
data = {} data = {}
# test the impact of tax exemption declaration, tax exemption proof submission and deduct check boxes in annual tax calculation # test the impact of tax exemption declaration, tax exemption proof submission
# and deduct check boxes in annual tax calculation
# as per assigned salary structure 40500 in monthly salary so 236000*5/100/12 # as per assigned salary structure 40500 in monthly salary so 236000*5/100/12
frappe.db.sql("""delete from `tabPayroll Period`""") frappe.db.sql("""delete from `tabPayroll Period`""")
frappe.db.sql("""delete from `tabSalary Component`""") frappe.db.sql("""delete from `tabSalary Component`""")
payroll_period = create_payroll_period() payroll_period = create_payroll_period()
create_tax_slab(payroll_period) create_tax_slab(payroll_period)
employee = make_employee("test_tax@salary.slip") employee = make_employee("test_tax@salary.slip")
delete_docs = ["Salary Slip", "Additional Salary", delete_docs = [
"Employee Tax Exemption Declaration", "Salary Slip",
"Employee Tax Exemption Proof Submission", "Additional Salary",
"Employee Benefit Claim", "Salary Structure Assignment"] "Employee Tax Exemption Declaration",
"Employee Tax Exemption Proof Submission",
"Employee Benefit Claim",
"Salary Structure Assignment"
]
for doc in delete_docs: for doc in delete_docs:
frappe.db.sql("delete from `tab%s` where employee='%s'" % (doc, employee)) frappe.db.sql("delete from `tab%s` where employee='%s'" % (doc, employee))
@@ -298,12 +313,11 @@ def make_employee_salary_slip(user, payroll_frequency, salary_structure=None):
if not salary_slip: if not salary_slip:
salary_slip = make_salary_slip(salary_structure_doc.name, employee = employee) salary_slip = make_salary_slip(salary_structure_doc.name, employee = employee)
salary_slip.employee_name = frappe.get_value("Employee", {"name":frappe.db.get_value("Employee", {"user_id": user})}, "employee_name") salary_slip.employee_name = frappe.get_value("Employee",
{"name":frappe.db.get_value("Employee", {"user_id": user})}, "employee_name")
salary_slip.payroll_frequency = payroll_frequency salary_slip.payroll_frequency = payroll_frequency
salary_slip.posting_date = nowdate() salary_slip.posting_date = nowdate()
salary_slip.insert() salary_slip.insert()
# salary_slip.submit()
# salary_slip = salary_slip.name
return salary_slip return salary_slip
@@ -338,99 +352,99 @@ def create_account(company):
salary_account = frappe.db.get_value("Account", "Salary - " + frappe.get_cached_value('Company', company, 'abbr')) salary_account = frappe.db.get_value("Account", "Salary - " + frappe.get_cached_value('Company', company, 'abbr'))
if not salary_account: if not salary_account:
frappe.get_doc({ frappe.get_doc({
"doctype": "Account", "doctype": "Account",
"account_name": "Salary", "account_name": "Salary",
"parent_account": "Indirect Expenses - " + frappe.get_cached_value('Company', company, 'abbr'), "parent_account": "Indirect Expenses - " + frappe.get_cached_value('Company', company, 'abbr'),
"company": company "company": company
}).insert() }).insert()
return salary_account return salary_account
def make_earning_salary_component(setup=False, test_tax=False): def make_earning_salary_component(setup=False, test_tax=False):
data = [ data = [
{
"salary_component": 'Basic Salary',
"abbr":'BS',
"condition": 'base > 10000',
"formula": 'base*.5',
"type": "Earning",
"amount_based_on_formula": 1
},
{
"salary_component": 'HRA',
"abbr":'H',
"amount": 3000,
"type": "Earning"
},
{
"salary_component": 'Special Allowance',
"abbr":'SA',
"condition": 'H < 10000',
"formula": 'BS*.5',
"type": "Earning",
"amount_based_on_formula": 1
},
{
"salary_component": "Leave Encashment",
"abbr": 'LE',
"is_additional_component": 1,
"type": "Earning"
}
]
if test_tax:
data.extend([
{ {
"salary_component": 'Basic Salary', "salary_component": "Leave Travel Allowance",
"abbr":'BS', "abbr": 'B',
"condition": 'base > 10000', "is_flexible_benefit": 1,
"formula": 'base*.5',
"type": "Earning", "type": "Earning",
"amount_based_on_formula": 1 "pay_against_benefit_claim": 1,
"max_benefit_amount": 100000
}, },
{ {
"salary_component": 'HRA', "salary_component": "Medical Allowance",
"abbr":'H', "abbr": 'B',
"amount": 3000, "is_flexible_benefit": 1,
"type": "Earning" "pay_against_benefit_claim": 0,
},
{
"salary_component": 'Special Allowance',
"abbr":'SA',
"condition": 'H < 10000',
"formula": 'BS*.5',
"type": "Earning", "type": "Earning",
"amount_based_on_formula": 1 "max_benefit_amount": 15000
}, },
{ {
"salary_component": "Leave Encashment", "salary_component": "Perfomance Bonus",
"abbr": 'LE', "abbr": 'B',
"is_additional_component": 1, "is_additional_component": 1,
"type": "Earning" "type": "Earning"
} }
] ])
if test_tax:
data.extend([
{
"salary_component": "Leave Travel Allowance",
"abbr": 'B',
"is_flexible_benefit": 1,
"type": "Earning",
"pay_against_benefit_claim": 1,
"max_benefit_amount": 100000
},
{
"salary_component": "Medical Allowance",
"abbr": 'B',
"is_flexible_benefit": 1,
"pay_against_benefit_claim": 0,
"type": "Earning",
"max_benefit_amount": 15000
},
{
"salary_component": "Perfomance Bonus",
"abbr": 'B',
"is_additional_component": 1,
"type": "Earning"
}
])
if setup or test_tax: if setup or test_tax:
make_salary_component(data, test_tax) make_salary_component(data, test_tax)
data.append({ data.append({
"salary_component": 'Basic Salary', "salary_component": 'Basic Salary',
"abbr":'BS', "abbr":'BS',
"condition": 'base < 10000', "condition": 'base < 10000',
"formula": 'base*.2', "formula": 'base*.2',
"type": "Earning", "type": "Earning",
"amount_based_on_formula": 1 "amount_based_on_formula": 1
}) })
return data return data
def make_deduction_salary_component(setup=False, test_tax=False): def make_deduction_salary_component(setup=False, test_tax=False):
data = [ data = [
{ {
"salary_component": 'Professional Tax', "salary_component": 'Professional Tax',
"abbr":'PT', "abbr":'PT',
"condition": 'base > 10000', "condition": 'base > 10000',
"formula": 'base*.1', "formula": 'base*.1',
"type": "Deduction", "type": "Deduction",
"amount_based_on_formula": 1 "amount_based_on_formula": 1
}, },
{ {
"salary_component": 'TDS', "salary_component": 'TDS',
"abbr":'T', "abbr":'T',
"formula": 'base*.1', "formula": 'base*.1',
"type": "Deduction", "type": "Deduction",
"amount_based_on_formula": 1 "amount_based_on_formula": 1
} }
] ]
if not test_tax: if not test_tax:
data.append({ data.append({
"salary_component": 'TDS', "salary_component": 'TDS',
@@ -453,48 +467,63 @@ def get_tax_paid_in_period(employee):
def create_exemption_declaration(employee, payroll_period): def create_exemption_declaration(employee, payroll_period):
create_exemption_category() create_exemption_category()
declaration = frappe.get_doc({"doctype": "Employee Tax Exemption Declaration", declaration = frappe.get_doc({
"employee": employee, "doctype": "Employee Tax Exemption Declaration",
"payroll_period": payroll_period, "employee": employee,
"company": erpnext.get_default_company()}) "payroll_period": payroll_period,
declaration.append("declarations", {"exemption_sub_category": "_Test Sub Category", "company": erpnext.get_default_company()
"exemption_category": "_Test Category", })
"amount": 100000}) declaration.append("declarations", {
"exemption_sub_category": "_Test Sub Category",
"exemption_category": "_Test Category",
"amount": 100000
})
declaration.submit() declaration.submit()
def create_proof_submission(employee, payroll_period, amount): def create_proof_submission(employee, payroll_period, amount):
submission_date = add_months(payroll_period.start_date, random.randint(0, 11)) submission_date = add_months(payroll_period.start_date, random.randint(0, 11))
proof_submission = frappe.get_doc({"doctype": "Employee Tax Exemption Proof Submission", proof_submission = frappe.get_doc({
"employee": employee, "doctype": "Employee Tax Exemption Proof Submission",
"payroll_period": payroll_period.name, "employee": employee,
"submission_date": submission_date}) "payroll_period": payroll_period.name,
proof_submission.append("tax_exemption_proofs", {"exemption_sub_category": "_Test Sub Category", "submission_date": submission_date
"exemption_category": "_Test Category", "type_of_proof": "Test", "amount": amount}) })
proof_submission.append("tax_exemption_proofs", {
"exemption_sub_category": "_Test Sub Category",
"exemption_category": "_Test Category",
"type_of_proof": "Test", "amount": amount
})
proof_submission.submit() proof_submission.submit()
return submission_date return submission_date
def create_benefit_claim(employee, payroll_period, amount, component): def create_benefit_claim(employee, payroll_period, amount, component):
claim_date = add_months(payroll_period.start_date, random.randint(0, 11)) claim_date = add_months(payroll_period.start_date, random.randint(0, 11))
frappe.get_doc({"doctype": "Employee Benefit Claim", "employee": employee, frappe.get_doc({
"claimed_amount": amount, "claim_date": claim_date, "earning_component": "doctype": "Employee Benefit Claim",
component}).submit() "employee": employee,
"claimed_amount": amount,
"claim_date": claim_date,
"earning_component": component
}).submit()
return claim_date return claim_date
def create_tax_slab(payroll_period): def create_tax_slab(payroll_period):
data = [{ data = [
"from_amount": 250000, {
"to_amount": 500000, "from_amount": 250000,
"percent_deduction": 5 "to_amount": 500000,
}, "percent_deduction": 5
{ },
"from_amount": 500000, {
"to_amount": 1000000, "from_amount": 500000,
"percent_deduction": 20 "to_amount": 1000000,
}, "percent_deduction": 20
{ },
"from_amount": 1000000, {
"percent_deduction": 30 "from_amount": 1000000,
}] "percent_deduction": 30
}
]
payroll_period.taxable_salary_slabs = [] payroll_period.taxable_salary_slabs = []
for item in data: for item in data:
payroll_period.append("taxable_salary_slabs", item) payroll_period.append("taxable_salary_slabs", item)
@@ -526,9 +555,13 @@ def create_salary_slips_for_payroll_period(employee, salary_structure, payroll_p
def create_additional_salary(employee, payroll_period, amount): def create_additional_salary(employee, payroll_period, amount):
salary_date = add_months(payroll_period.start_date, random.randint(0, 11)) salary_date = add_months(payroll_period.start_date, random.randint(0, 11))
frappe.get_doc({"doctype": "Additional Salary", "employee": employee, frappe.get_doc({
"company": erpnext.get_default_company(), "doctype": "Additional Salary",
"salary_component": "Perfomance Bonus", "employee": employee,
"payroll_date": salary_date, "company": erpnext.get_default_company(),
"amount": amount, "type": "Earning"}).submit() "salary_component": "Perfomance Bonus",
"payroll_date": salary_date,
"amount": amount,
"type": "Earning"
}).submit()
return salary_date return salary_date

View File

@@ -246,7 +246,7 @@ frappe.ui.form.on('Salary Detail', {
frappe.model.set_value(cdt, cdn, 'amount', result.amount); frappe.model.set_value(cdt, cdn, 'amount', result.amount);
} }
frappe.model.set_value(cdt, cdn, 'statistical_component', result.statistical_component); frappe.model.set_value(cdt, cdn, 'statistical_component', result.statistical_component);
frappe.model.set_value(cdt, cdn, 'depends_on_lwp', result.depends_on_lwp); frappe.model.set_value(cdt, cdn, 'depends_on_payment_days', result.depends_on_payment_days);
frappe.model.set_value(cdt, cdn, 'do_not_include_in_total', result.do_not_include_in_total); frappe.model.set_value(cdt, cdn, 'do_not_include_in_total', result.do_not_include_in_total);
frappe.model.set_value(cdt, cdn, 'variable_based_on_taxable_salary', result.variable_based_on_taxable_salary); frappe.model.set_value(cdt, cdn, 'variable_based_on_taxable_salary', result.variable_based_on_taxable_salary);
frappe.model.set_value(cdt, cdn, 'is_tax_applicable', result.is_tax_applicable); frappe.model.set_value(cdt, cdn, 'is_tax_applicable', result.is_tax_applicable);

View File

@@ -18,7 +18,7 @@ class SalaryStructure(Document):
self.validate_max_benefits_with_flexi() self.validate_max_benefits_with_flexi()
def set_missing_values(self): def set_missing_values(self):
overwritten_fields = ["depends_on_lwp", "variable_based_on_taxable_salary", "is_tax_applicable", "is_flexible_benefit"] overwritten_fields = ["depends_on_payment_days", "variable_based_on_taxable_salary", "is_tax_applicable", "is_flexible_benefit"]
overwritten_fields_if_missing = ["amount_based_on_formula", "formula", "amount"] overwritten_fields_if_missing = ["amount_based_on_formula", "formula", "amount"]
for table in ["earnings", "deductions"]: for table in ["earnings", "deductions"]:
for d in self.get(table): for d in self.get(table):

View File

@@ -6,7 +6,7 @@
"docstatus": 0, "docstatus": 0,
"doctype": "Print Format", "doctype": "Print Format",
"font": "Default", "font": "Default",
"format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"HTML\", \"options\": \" <h3 style=\\\"text-align: right;\\\">{{doc.name}}</h3><div><hr></div> \"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"employee\"}, {\"print_hide\": 0, \"fieldname\": \"employee_name\"}, {\"print_hide\": 0, \"fieldname\": \"department\"}, {\"print_hide\": 0, \"fieldname\": \"designation\"}, {\"print_hide\": 0, \"fieldname\": \"branch\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"start_date\"}, {\"print_hide\": 0, \"fieldname\": \"end_date\"}, {\"print_hide\": 0, \"fieldname\": \"total_working_hours\"}, {\"print_hide\": 0, \"fieldname\": \"hour_rate\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"time_sheet\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"working_hours\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"timesheets\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"salary_component\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"depends_on_lwp\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"earnings\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"salary_component\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"depends_on_lwp\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"deductions\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"gross_pay\"}, {\"print_hide\": 0, \"fieldname\": \"total_deduction\"}, {\"print_hide\": 0, \"fieldname\": \"net_pay\"}, {\"print_hide\": 0, \"fieldname\": \"rounded_total\"}, {\"print_hide\": 0, \"fieldname\": \"total_in_words\"}]", "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"HTML\", \"options\": \" <h3 style=\\\"text-align: right;\\\">{{doc.name}}</h3><div><hr></div> \"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"employee\"}, {\"print_hide\": 0, \"fieldname\": \"employee_name\"}, {\"print_hide\": 0, \"fieldname\": \"department\"}, {\"print_hide\": 0, \"fieldname\": \"designation\"}, {\"print_hide\": 0, \"fieldname\": \"branch\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"start_date\"}, {\"print_hide\": 0, \"fieldname\": \"end_date\"}, {\"print_hide\": 0, \"fieldname\": \"total_working_hours\"}, {\"print_hide\": 0, \"fieldname\": \"hour_rate\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"time_sheet\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"working_hours\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"timesheets\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"salary_component\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"depends_on_payment_days\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"earnings\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"salary_component\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"depends_on_payment_days\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"deductions\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"gross_pay\"}, {\"print_hide\": 0, \"fieldname\": \"total_deduction\"}, {\"print_hide\": 0, \"fieldname\": \"net_pay\"}, {\"print_hide\": 0, \"fieldname\": \"rounded_total\"}, {\"print_hide\": 0, \"fieldname\": \"total_in_words\"}]",
"idx": 0, "idx": 0,
"modified": "2016-08-21 21:02:59.896033", "modified": "2016-08-21 21:02:59.896033",
"modified_by": "Administrator", "modified_by": "Administrator",

View File

@@ -7,7 +7,7 @@
"docstatus": 0, "docstatus": 0,
"doctype": "Print Format", "doctype": "Print Format",
"font": "Default", "font": "Default",
"format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \" <h3 style=\\\"text-align: right;\\\"><span style=\\\"line-height: 1.42857;\\\">{{doc.name}}</span></h3>\\n<div>\\n <hr style=\\\"text-align: center;\\\">\\n</div> \"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"employee\", \"label\": \"Employee\"}, {\"print_hide\": 0, \"fieldname\": \"company\", \"label\": \"Company\"}, {\"print_hide\": 0, \"fieldname\": \"employee_name\", \"label\": \"Employee Name\"}, {\"print_hide\": 0, \"fieldname\": \"department\", \"label\": \"Department\"}, {\"print_hide\": 0, \"fieldname\": \"designation\", \"label\": \"Designation\"}, {\"print_hide\": 0, \"fieldname\": \"branch\", \"label\": \"Branch\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"start_date\", \"label\": \"Start Date\"}, {\"print_hide\": 0, \"fieldname\": \"end_date\", \"label\": \"End Date\"}, {\"print_hide\": 0, \"fieldname\": \"total_working_days\", \"label\": \"Working Days\"}, {\"print_hide\": 0, \"fieldname\": \"leave_without_pay\", \"label\": \"Leave Without Pay\"}, {\"print_hide\": 0, \"fieldname\": \"payment_days\", \"label\": \"Payment Days\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"salary_component\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"earnings\", \"label\": \"Earnings\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"salary_component\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"depends_on_lwp\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"deductions\", \"label\": \"Deductions\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"gross_pay\", \"label\": \"Gross Pay\"}, {\"print_hide\": 0, \"fieldname\": \"total_deduction\", \"label\": \"Total Deduction\"}, {\"print_hide\": 0, \"fieldname\": \"net_pay\", \"label\": \"Net Pay\"}, {\"print_hide\": 0, \"fieldname\": \"rounded_total\", \"label\": \"Rounded Total\"}, {\"print_hide\": 0, \"fieldname\": \"total_in_words\", \"label\": \"Total in words\"}]", "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \" <h3 style=\\\"text-align: right;\\\"><span style=\\\"line-height: 1.42857;\\\">{{doc.name}}</span></h3>\\n<div>\\n <hr style=\\\"text-align: center;\\\">\\n</div> \"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"employee\", \"label\": \"Employee\"}, {\"print_hide\": 0, \"fieldname\": \"company\", \"label\": \"Company\"}, {\"print_hide\": 0, \"fieldname\": \"employee_name\", \"label\": \"Employee Name\"}, {\"print_hide\": 0, \"fieldname\": \"department\", \"label\": \"Department\"}, {\"print_hide\": 0, \"fieldname\": \"designation\", \"label\": \"Designation\"}, {\"print_hide\": 0, \"fieldname\": \"branch\", \"label\": \"Branch\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"start_date\", \"label\": \"Start Date\"}, {\"print_hide\": 0, \"fieldname\": \"end_date\", \"label\": \"End Date\"}, {\"print_hide\": 0, \"fieldname\": \"total_working_days\", \"label\": \"Working Days\"}, {\"print_hide\": 0, \"fieldname\": \"leave_without_pay\", \"label\": \"Leave Without Pay\"}, {\"print_hide\": 0, \"fieldname\": \"payment_days\", \"label\": \"Payment Days\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"salary_component\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"earnings\", \"label\": \"Earnings\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"salary_component\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"depends_on_payment_days\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"deductions\", \"label\": \"Deductions\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"gross_pay\", \"label\": \"Gross Pay\"}, {\"print_hide\": 0, \"fieldname\": \"total_deduction\", \"label\": \"Total Deduction\"}, {\"print_hide\": 0, \"fieldname\": \"net_pay\", \"label\": \"Net Pay\"}, {\"print_hide\": 0, \"fieldname\": \"rounded_total\", \"label\": \"Rounded Total\"}, {\"print_hide\": 0, \"fieldname\": \"total_in_words\", \"label\": \"Total in words\"}]",
"idx": 0, "idx": 0,
"line_breaks": 0, "line_breaks": 0,
"modified": "2018-07-24 19:31:39.040701", "modified": "2018-07-24 19:31:39.040701",

View File

@@ -220,16 +220,30 @@ def get_employee_leave_policy(employee):
def validate_tax_declaration(declarations): def validate_tax_declaration(declarations):
subcategories = [] subcategories = []
for declaration in declarations: for d in declarations:
if declaration.exemption_sub_category in subcategories: if d.exemption_sub_category in subcategories:
frappe.throw(_("More than one selection for {0} not \ frappe.throw(_("More than one selection for {0} not allowed").format(d.exemption_sub_category))
allowed").format(declaration.exemption_sub_category), frappe.ValidationError) subcategories.append(d.exemption_sub_category)
subcategories.append(declaration.exemption_sub_category)
max_amount = frappe.db.get_value("Employee Tax Exemption Sub Category", \ def get_total_exemption_amount(declarations):
declaration.exemption_sub_category, "max_amount") exemptions = frappe._dict()
if declaration.amount > max_amount: for d in declarations:
frappe.throw(_("Max exemption amount for {0} is {1}").format(\ exemptions.setdefault(d.exemption_category, frappe._dict())
declaration.exemption_sub_category, max_amount), frappe.ValidationError) category_max_amount = exemptions.get(d.exemption_category).max_amount
if not category_max_amount:
category_max_amount = frappe.db.get_value("Employee Tax Exemption Category", d.exemption_category, "max_amount")
exemptions.get(d.exemption_category).max_amount = category_max_amount
sub_category_exemption_amount = d.max_amount \
if (d.max_amount and flt(d.amount) > flt(d.max_amount)) else d.amount
exemptions.get(d.exemption_category).setdefault("total_exemption_amount", 0.0)
exemptions.get(d.exemption_category).total_exemption_amount += flt(sub_category_exemption_amount)
if category_max_amount and exemptions.get(d.exemption_category).total_exemption_amount > category_max_amount:
exemptions.get(d.exemption_category).total_exemption_amount = category_max_amount
total_exemption_amount = sum([flt(d.total_exemption_amount) for d in exemptions.values()])
return total_exemption_amount
def get_leave_period(from_date, to_date, company): def get_leave_period(from_date, to_date, company):
leave_period = frappe.db.sql(""" leave_period = frappe.db.sql("""

View File

@@ -28,7 +28,7 @@ def make_opportunity(buyer_name, email_id):
lead.save(ignore_permissions=True) lead.save(ignore_permissions=True)
o = frappe.new_doc("Opportunity") o = frappe.new_doc("Opportunity")
o.enquiry_from = "Lead" o.opportunity_from = "Lead"
o.lead = frappe.get_all("Lead", filters={"email_id": email_id}, fields = ["name"])[0]["name"] o.lead = frappe.get_all("Lead", filters={"email_id": email_id}, fields = ["name"])[0]["name"]
o.save(ignore_permissions=True) o.save(ignore_permissions=True)

View File

@@ -590,5 +590,8 @@ erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019
erpnext.patches.v11_0.make_italian_localization_fields # 26-03-2019 erpnext.patches.v11_0.make_italian_localization_fields # 26-03-2019
erpnext.patches.v11_1.make_job_card_time_logs erpnext.patches.v11_1.make_job_card_time_logs
erpnext.patches.v11_1.set_variant_based_on erpnext.patches.v11_1.set_variant_based_on
erpnext.patches.v11_1.move_customer_lead_to_dynamic_column
erpnext.patches.v11_1.woocommerce_set_creation_user erpnext.patches.v11_1.woocommerce_set_creation_user
erpnext.patches.v11_1.set_salary_details_submitable erpnext.patches.v11_1.delete_bom_browser
erpnext.patches.v11_1.set_salary_details_submittable
erpnext.patches.v11_1.rename_depends_on_lwp

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
frappe.delete_doc_if_exists('Page', 'bom-browser')

View File

@@ -0,0 +1,14 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
frappe.reload_doctype("Quotation")
frappe.db.sql(""" UPDATE `tabQuotation` set party_name = lead WHERE quotation_to = 'Lead' """)
frappe.db.sql(""" UPDATE `tabQuotation` set party_name = customer WHERE quotation_to = 'Customer' """)
frappe.reload_doctype("Opportunity")
frappe.db.sql(""" UPDATE `tabOpportunity` set party_name = lead WHERE opportunity_from = 'Lead' """)
frappe.db.sql(""" UPDATE `tabOpportunity` set party_name = customer WHERE opportunity_from = 'Customer' """)

View File

@@ -0,0 +1,13 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from frappe import scrub
from frappe.model.utils.rename_field import rename_field
def execute():
for doctype in ("Salary Component", "Salary Detail"):
if "depends_on_lwp" in frappe.db.get_table_columns(doctype):
frappe.reload_doc("hr", "doctype", scrub(doctype))
rename_field(doctype, "depends_on_lwp", "depends_on_payment_days")

View File

@@ -7,5 +7,3 @@ def execute():
set sd.docstatus=1 set sd.docstatus=1
where ss.name=sd.parent and ss.docstatus=1 and sd.parenttype='Salary Structure' where ss.name=sd.parent and ss.docstatus=1 and sd.parenttype='Salary Structure'
""") """)

View File

@@ -53,7 +53,7 @@ def execute():
target_cols = standard_cols + ["salary_component", "amount", "depends_on_lwp", "default_amount"] target_cols = standard_cols + ["salary_component", "amount", "depends_on_payment_days", "default_amount"]
target_cols = "`" + "`, `".join(target_cols) + "`" target_cols = "`" + "`, `".join(target_cols) + "`"
for doctype, cols in dt_cols.items(): for doctype, cols in dt_cols.items():
@@ -99,27 +99,27 @@ def update_customizations():
"d_type": "salary_component", "d_type": "salary_component",
"deduction_type": "salary_component", "deduction_type": "salary_component",
"d_modified_amt": "amount", "d_modified_amt": "amount",
"depend_on_lwp": "depends_on_lwp" "depend_on_lwp": "depends_on_payment_days"
}, },
"Salary Structure Earning": { "Salary Structure Earning": {
"e_type": "salary_component", "e_type": "salary_component",
"earning_type": "salary_component", "earning_type": "salary_component",
"modified_value": "amount", "modified_value": "amount",
"depend_on_lwp": "depends_on_lwp" "depend_on_lwp": "depends_on_payment_days"
}, },
"Salary Slip Earning": { "Salary Slip Earning": {
"e_type": "salary_component", "e_type": "salary_component",
"earning_type": "salary_component", "earning_type": "salary_component",
"e_modified_amount": "amount", "e_modified_amount": "amount",
"e_amount" : "default_amount", "e_amount" : "default_amount",
"e_depends_on_lwp": "depends_on_lwp" "e_depends_on_lwp": "depends_on_payment_days"
}, },
"Salary Slip Deduction": { "Salary Slip Deduction": {
"d_type": "salary_component", "d_type": "salary_component",
"deduction_type": "salary_component", "deduction_type": "salary_component",
"d_modified_amount": "amount", "d_modified_amount": "amount",
"d_amount" : "default_amount", "d_amount" : "default_amount",
"d_depends_on_lwp": "depends_on_lwp" "d_depends_on_lwp": "depends_on_payment_days"
} }
} }

View File

@@ -1154,6 +1154,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
"brand": d.brand, "brand": d.brand,
"qty": d.qty, "qty": d.qty,
"uom": d.uom, "uom": d.uom,
"stock_uom": d.stock_uom,
"parenttype": d.parenttype, "parenttype": d.parenttype,
"parent": d.parent, "parent": d.parent,
"pricing_rule": d.pricing_rule, "pricing_rule": d.pricing_rule,

View File

@@ -262,18 +262,18 @@ def make_custom_fields(update=True):
'Employee Tax Exemption Declaration':[ 'Employee Tax Exemption Declaration':[
dict(fieldname='hra_section', label='HRA Exemption', dict(fieldname='hra_section', label='HRA Exemption',
fieldtype='Section Break', insert_after='declarations'), fieldtype='Section Break', insert_after='declarations'),
dict(fieldname='salary_structure_hra', label='HRA as per Salary Structure',
fieldtype='Currency', insert_after='hra_section', read_only=1),
dict(fieldname='monthly_house_rent', label='Monthly House Rent', dict(fieldname='monthly_house_rent', label='Monthly House Rent',
fieldtype='Currency', insert_after='salary_structure_hra'), fieldtype='Currency', insert_after='hra_section'),
dict(fieldname='rented_in_metro_city', label='Rented in Metro City', dict(fieldname='rented_in_metro_city', label='Rented in Metro City',
fieldtype='Check', insert_after='monthly_house_rent'), fieldtype='Check', insert_after='monthly_house_rent', depends_on='monthly_house_rent'),
dict(fieldname='salary_structure_hra', label='HRA as per Salary Structure',
fieldtype='Currency', insert_after='rented_in_metro_city', read_only=1, depends_on='monthly_house_rent'),
dict(fieldname='hra_column_break', fieldtype='Column Break', dict(fieldname='hra_column_break', fieldtype='Column Break',
insert_after='rented_in_metro_city'), insert_after='salary_structure_hra', depends_on='monthly_house_rent'),
dict(fieldname='annual_hra_exemption', label='Annual HRA Exemption', dict(fieldname='annual_hra_exemption', label='Annual HRA Exemption',
fieldtype='Currency', insert_after='hra_column_break', read_only=1), fieldtype='Currency', insert_after='hra_column_break', read_only=1, depends_on='monthly_house_rent'),
dict(fieldname='monthly_hra_exemption', label='Monthly HRA Exemption', dict(fieldname='monthly_hra_exemption', label='Monthly HRA Exemption',
fieldtype='Currency', insert_after='annual_hra_exemption', read_only=1) fieldtype='Currency', insert_after='annual_hra_exemption', read_only=1, depends_on='monthly_house_rent')
], ],
'Employee Tax Exemption Proof Submission': [ 'Employee Tax Exemption Proof Submission': [
dict(fieldname='hra_section', label='HRA Exemption', dict(fieldname='hra_section', label='HRA Exemption',
@@ -281,19 +281,19 @@ def make_custom_fields(update=True):
dict(fieldname='house_rent_payment_amount', label='House Rent Payment Amount', dict(fieldname='house_rent_payment_amount', label='House Rent Payment Amount',
fieldtype='Currency', insert_after='hra_section'), fieldtype='Currency', insert_after='hra_section'),
dict(fieldname='rented_in_metro_city', label='Rented in Metro City', dict(fieldname='rented_in_metro_city', label='Rented in Metro City',
fieldtype='Check', insert_after='house_rent_payment_amount'), fieldtype='Check', insert_after='house_rent_payment_amount', depends_on='house_rent_payment_amount'),
dict(fieldname='rented_from_date', label='Rented From Date', dict(fieldname='rented_from_date', label='Rented From Date',
fieldtype='Date', insert_after='rented_in_metro_city'), fieldtype='Date', insert_after='rented_in_metro_city', depends_on='house_rent_payment_amount'),
dict(fieldname='rented_to_date', label='Rented To Date', dict(fieldname='rented_to_date', label='Rented To Date',
fieldtype='Date', insert_after='rented_from_date'), fieldtype='Date', insert_after='rented_from_date', depends_on='house_rent_payment_amount'),
dict(fieldname='hra_column_break', fieldtype='Column Break', dict(fieldname='hra_column_break', fieldtype='Column Break',
insert_after='rented_to_date'), insert_after='rented_to_date', depends_on='house_rent_payment_amount'),
dict(fieldname='monthly_house_rent', label='Monthly House Rent', dict(fieldname='monthly_house_rent', label='Monthly House Rent',
fieldtype='Currency', insert_after='hra_column_break', read_only=1), fieldtype='Currency', insert_after='hra_column_break', read_only=1, depends_on='house_rent_payment_amount'),
dict(fieldname='monthly_hra_exemption', label='Monthly Eligible Amount', dict(fieldname='monthly_hra_exemption', label='Monthly Eligible Amount',
fieldtype='Currency', insert_after='monthly_house_rent', read_only=1), fieldtype='Currency', insert_after='monthly_house_rent', read_only=1, depends_on='house_rent_payment_amount'),
dict(fieldname='total_eligible_hra_exemption', label='Total Eligible HRA Exemption', dict(fieldname='total_eligible_hra_exemption', label='Total Eligible HRA Exemption',
fieldtype='Currency', insert_after='monthly_hra_exemption', read_only=1) fieldtype='Currency', insert_after='monthly_hra_exemption', read_only=1, depends_on='house_rent_payment_amount')
], ],
'Supplier': [ 'Supplier': [
{ {

View File

@@ -1,7 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe, re import frappe, re
from frappe import _ from frappe import _
from frappe.utils import cstr, flt, date_diff, getdate from frappe.utils import cstr, flt, date_diff, nowdate
from erpnext.regional.india import states, state_numbers from erpnext.regional.india import states, state_numbers
from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount
from erpnext.controllers.accounts_controller import get_taxes_and_charges from erpnext.controllers.accounts_controller import get_taxes_and_charges
@@ -144,24 +144,40 @@ def get_regional_address_details(out, doctype, company):
def calculate_annual_eligible_hra_exemption(doc): def calculate_annual_eligible_hra_exemption(doc):
basic_component = frappe.get_cached_value('Company', doc.company, "basic_component") basic_component = frappe.get_cached_value('Company', doc.company, "basic_component")
hra_component = frappe.get_cached_value('Company', doc.company, "hra_component") hra_component = frappe.get_cached_value('Company', doc.company, "hra_component")
if not (basic_component and hra_component):
frappe.throw(_("Please mention Basic and HRA component in Company"))
annual_exemption, monthly_exemption, hra_amount = 0, 0, 0 annual_exemption, monthly_exemption, hra_amount = 0, 0, 0
if hra_component and basic_component: if hra_component and basic_component:
assignment = get_salary_assignment(doc.employee, getdate()) assignment = get_salary_assignment(doc.employee, nowdate())
if assignment and frappe.db.exists("Salary Detail", {
"parent": assignment.salary_structure, if assignment:
"salary_component": hra_component, "parentfield": "earnings"}): hra_component_exists = frappe.db.exists("Salary Detail", {
basic_amount, hra_amount = get_component_amt_from_salary_slip(doc.employee, "parent": assignment.salary_structure,
assignment.salary_structure, basic_component, hra_component) "salary_component": hra_component,
if hra_amount: "parentfield": "earnings",
if doc.monthly_house_rent: "parenttype": "Salary Structure"
annual_exemption = calculate_hra_exemption(assignment.salary_structure, })
basic_amount, hra_amount, doc.monthly_house_rent, if hra_component_exists:
doc.rented_in_metro_city) basic_amount, hra_amount = get_component_amt_from_salary_slip(doc.employee,
if annual_exemption > 0: assignment.salary_structure, basic_component, hra_component)
monthly_exemption = annual_exemption / 12 if hra_amount:
else: if doc.monthly_house_rent:
annual_exemption = 0 annual_exemption = calculate_hra_exemption(assignment.salary_structure,
return {"hra_amount": hra_amount, "annual_exemption": annual_exemption, "monthly_exemption": monthly_exemption} basic_amount, hra_amount, doc.monthly_house_rent,
doc.rented_in_metro_city)
if annual_exemption > 0:
monthly_exemption = annual_exemption / 12
else:
annual_exemption = 0
elif doc.docstatus == 1:
frappe.throw(_("Salary Structure must be submitted before submission of Tax Ememption Declaration"))
return frappe._dict({
"hra_amount": hra_amount,
"annual_exemption": annual_exemption,
"monthly_exemption": monthly_exemption
})
def get_component_amt_from_salary_slip(employee, salary_structure, basic_component, hra_component): def get_component_amt_from_salary_slip(employee, salary_structure, basic_component, hra_component):
salary_slip = make_salary_slip(salary_structure, employee=employee) salary_slip = make_salary_slip(salary_structure, employee=employee)
@@ -181,8 +197,10 @@ def calculate_hra_exemption(salary_structure, basic, monthly_hra, monthly_house_
frequency = frappe.get_value("Salary Structure", salary_structure, "payroll_frequency") frequency = frappe.get_value("Salary Structure", salary_structure, "payroll_frequency")
# case 1: The actual amount allotted by the employer as the HRA. # case 1: The actual amount allotted by the employer as the HRA.
exemptions.append(get_annual_component_pay(frequency, monthly_hra)) exemptions.append(get_annual_component_pay(frequency, monthly_hra))
actual_annual_rent = monthly_house_rent * 12 actual_annual_rent = monthly_house_rent * 12
annual_basic = get_annual_component_pay(frequency, basic) annual_basic = get_annual_component_pay(frequency, basic)
# case 2: Actual rent paid less 10% of the basic salary. # case 2: Actual rent paid less 10% of the basic salary.
exemptions.append(flt(actual_annual_rent) - flt(annual_basic * 0.1)) exemptions.append(flt(actual_annual_rent) - flt(annual_basic * 0.1))
# case 3: 50% of the basic salary, if the employee is staying in a metro city (40% for a non-metro city). # case 3: 50% of the basic salary, if the employee is staying in a metro city (40% for a non-metro city).
@@ -205,15 +223,25 @@ def get_annual_component_pay(frequency, amount):
def validate_house_rent_dates(doc): def validate_house_rent_dates(doc):
if not doc.rented_to_date or not doc.rented_from_date: if not doc.rented_to_date or not doc.rented_from_date:
frappe.throw(_("House rented dates required for exemption calculation")) frappe.throw(_("House rented dates required for exemption calculation"))
if date_diff(doc.rented_to_date, doc.rented_from_date) < 14: if date_diff(doc.rented_to_date, doc.rented_from_date) < 14:
frappe.throw(_("House rented dates should be atleast 15 days apart")) frappe.throw(_("House rented dates should be atleast 15 days apart"))
proofs = frappe.db.sql("""select name from `tabEmployee Tax Exemption Proof Submission`
where docstatus=1 and employee='{0}' and payroll_period='{1}' and proofs = frappe.db.sql("""
(rented_from_date between '{2}' and '{3}' or rented_to_date between select name
'{2}' and '{3}')""".format(doc.employee, doc.payroll_period, from `tabEmployee Tax Exemption Proof Submission`
doc.rented_from_date, doc.rented_to_date)) where
docstatus=1 and employee=%(employee)s and payroll_period=%(payroll_period)s
and (rented_from_date between %(from_date)s and %(to_date)s or rented_to_date between %(from_date)s and %(to_date)s)
""", {
"employee": doc.employee,
"payroll_period": doc.payroll_period,
"from_date": doc.rented_from_date,
"to_date": doc.rented_to_date
})
if proofs: if proofs:
frappe.throw(_("House rent paid days overlap with {0}").format(proofs[0][0])) frappe.throw(_("House rent paid days overlapping with {0}").format(proofs[0][0]))
def calculate_hra_exemption_for_period(doc): def calculate_hra_exemption_for_period(doc):
monthly_rent, eligible_hra = 0, 0 monthly_rent, eligible_hra = 0, 0

View File

@@ -104,10 +104,6 @@ class Customer(TransactionBase):
if self.lead_name: if self.lead_name:
frappe.db.set_value('Lead', self.lead_name, 'status', 'Converted', update_modified=False) frappe.db.set_value('Lead', self.lead_name, 'status', 'Converted', update_modified=False)
for doctype in ('Opportunity', 'Quotation'):
for d in frappe.get_all(doctype, {'lead': self.lead_name}):
frappe.db.set_value(doctype, d.name, 'customer', self.name, update_modified=False)
def create_lead_address_contact(self): def create_lead_address_contact(self):
if self.lead_name: if self.lead_name:
# assign lead address to customer (if already not set) # assign lead address to customer (if already not set)

View File

@@ -6,6 +6,10 @@ def get_data():
'heatmap': True, 'heatmap': True,
'heatmap_message': _('This is based on transactions against this Customer. See timeline below for details'), 'heatmap_message': _('This is based on transactions against this Customer. See timeline below for details'),
'fieldname': 'customer', 'fieldname': 'customer',
'non_standard_fieldnames': {
'Quotation': 'party_name',
'Opportunity': 'party_name'
},
'transactions': [ 'transactions': [
{ {
'label': _('Pre Sales'), 'label': _('Pre Sales'),

View File

@@ -8,15 +8,27 @@ frappe.ui.form.on('Quotation', {
setup: function(frm) { setup: function(frm) {
frm.custom_make_buttons = { frm.custom_make_buttons = {
'Sales Order': 'Make Sales Order' 'Sales Order': 'Make Sales Order'
} },
frm.set_query("quotation_to", function() {
return{
"filters": {
"name": ["in", ["Customer", "Lead"]],
}
}
});
}, },
refresh: function(frm) { refresh: function(frm) {
frm.trigger("set_label"); frm.trigger("set_label");
frm.trigger("set_dynamic_field_label");
}, },
quotation_to: function(frm) { quotation_to: function(frm) {
frm.trigger("set_label"); frm.trigger("set_label");
frm.trigger("toggle_reqd_lead_customer");
frm.trigger("set_dynamic_field_label");
}, },
set_label: function(frm) { set_label: function(frm) {
@@ -28,10 +40,6 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
onload: function(doc, dt, dn) { onload: function(doc, dt, dn) {
var me = this; var me = this;
this._super(doc, dt, dn); this._super(doc, dt, dn);
if(doc.customer && !doc.quotation_to)
doc.quotation_to = "Customer";
else if(doc.lead && !doc.quotation_to)
doc.quotation_to = "Lead";
}, },
refresh: function(doc, dt, dn) { refresh: function(doc, dt, dn) {
@@ -97,25 +105,28 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
}, },
quotation_to: function() { set_dynamic_field_label: function(){
var me = this; if (this.frm.doc.quotation_to == "Customer")
if (this.frm.doc.quotation_to == "Lead") { {
this.frm.set_value("customer", null); this.frm.set_df_property("party_name", "label", "Customer");
this.frm.set_value("contact_person", null); this.frm.fields_dict.party_name.get_query = null;
} else if (this.frm.doc.quotation_to == "Customer") {
this.frm.set_value("lead", null);
} }
this.toggle_reqd_lead_customer(); if (this.frm.doc.quotation_to == "Lead")
{
this.frm.set_df_property("party_name", "label", "Lead");
this.frm.fields_dict.party_name.get_query = function() {
return{ query: "erpnext.controllers.queries.lead_query" }
}
}
}, },
toggle_reqd_lead_customer: function() { toggle_reqd_lead_customer: function() {
var me = this; var me = this;
this.frm.toggle_reqd("lead", this.frm.doc.quotation_to == "Lead");
this.frm.toggle_reqd("customer", this.frm.doc.quotation_to == "Customer");
// to overwrite the customer_filter trigger from queries.js // to overwrite the customer_filter trigger from queries.js
this.frm.toggle_reqd("party_name", this.frm.doc.quotation_to);
this.frm.set_query('customer_address', erpnext.queries.address_query); this.frm.set_query('customer_address', erpnext.queries.address_query);
this.frm.set_query('shipping_address_name', erpnext.queries.address_query); this.frm.set_query('shipping_address_name', erpnext.queries.address_query);
}, },
@@ -163,10 +174,6 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
cur_frm.script_manager.make(erpnext.selling.QuotationController); cur_frm.script_manager.make(erpnext.selling.QuotationController);
cur_frm.fields_dict.lead.get_query = function(doc,cdt,cdn) {
return{ query: "erpnext.controllers.queries.lead_query" }
}
cur_frm.cscript['Make Sales Order'] = function() { cur_frm.cscript['Make Sales Order'] = function() {
frappe.model.open_mapped_doc({ frappe.model.open_mapped_doc({
method: "erpnext.selling.doctype.quotation.quotation.make_sales_order", method: "erpnext.selling.doctype.quotation.quotation.make_sales_order",

View File

@@ -20,6 +20,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "customer_section", "fieldname": "customer_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -53,6 +54,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "{customer_name}", "default": "{customer_name}",
"fetch_if_empty": 0,
"fieldname": "title", "fieldname": "title",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
@@ -86,6 +88,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "", "default": "",
"fetch_if_empty": 0,
"fieldname": "naming_series", "fieldname": "naming_series",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -121,8 +124,9 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "Customer", "default": "Customer",
"fetch_if_empty": 0,
"fieldname": "quotation_to", "fieldname": "quotation_to",
"fieldtype": "Select", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@@ -135,7 +139,7 @@
"no_copy": 0, "no_copy": 0,
"oldfieldname": "quotation_to", "oldfieldname": "quotation_to",
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "\nLead\nCustomer", "options": "DocType",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
@@ -155,9 +159,10 @@
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.quotation_to == \"Customer\"", "depends_on": "",
"fieldname": "customer", "fetch_if_empty": 0,
"fieldtype": "Link", "fieldname": "party_name",
"fieldtype": "Dynamic Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@@ -165,12 +170,12 @@
"in_global_search": 1, "in_global_search": 1,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "Customer", "label": "Customer/Lead",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"oldfieldname": "customer", "oldfieldname": "customer",
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Customer", "options": "quotation_to",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
@@ -183,41 +188,6 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.quotation_to == \"Lead\"",
"fieldname": "lead",
"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": "Lead",
"length": 0,
"no_copy": 0,
"oldfieldname": "lead",
"oldfieldtype": "Link",
"options": "Lead",
"permlevel": 0,
"print_hide": 1,
"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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@@ -226,6 +196,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "customer.customer_name", "fetch_from": "customer.customer_name",
"fetch_if_empty": 0,
"fieldname": "customer_name", "fieldname": "customer_name",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
@@ -258,6 +229,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break1", "fieldname": "column_break1",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -290,6 +262,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "amended_from", "fieldname": "amended_from",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -326,6 +299,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "company", "fieldname": "company",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -362,6 +336,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "Today", "default": "Today",
"fetch_if_empty": 0,
"fieldname": "transaction_date", "fieldname": "transaction_date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0, "hidden": 0,
@@ -396,6 +371,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "valid_till", "fieldname": "valid_till",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0, "hidden": 0,
@@ -429,6 +405,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "Sales", "default": "Sales",
"fetch_if_empty": 0,
"fieldname": "order_type", "fieldname": "order_type",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -465,6 +442,7 @@
"collapsible_depends_on": "", "collapsible_depends_on": "",
"columns": 0, "columns": 0,
"depends_on": "eval:(doc.customer || doc.lead)", "depends_on": "eval:(doc.customer || doc.lead)",
"fetch_if_empty": 0,
"fieldname": "contact_section", "fieldname": "contact_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -497,6 +475,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "customer_address", "fieldname": "customer_address",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -529,6 +508,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "address_display", "fieldname": "address_display",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
@@ -563,6 +543,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.customer", "depends_on": "eval:doc.customer",
"fetch_if_empty": 0,
"fieldname": "contact_person", "fieldname": "contact_person",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -597,6 +578,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "contact_display", "fieldname": "contact_display",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
@@ -628,6 +610,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "contact_mobile", "fieldname": "contact_mobile",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
@@ -659,6 +642,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "contact_email", "fieldname": "contact_email",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
@@ -692,6 +676,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "customer", "depends_on": "customer",
"fetch_if_empty": 0,
"fieldname": "col_break98", "fieldname": "col_break98",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -723,6 +708,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "shipping_address_name", "fieldname": "shipping_address_name",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -755,6 +741,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "shipping_address", "fieldname": "shipping_address",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
@@ -788,6 +775,7 @@
"columns": 0, "columns": 0,
"depends_on": "customer", "depends_on": "customer",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "customer_group", "fieldname": "customer_group",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 1, "hidden": 1,
@@ -823,6 +811,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "territory", "fieldname": "territory",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -855,6 +844,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "currency_and_price_list", "fieldname": "currency_and_price_list",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -887,6 +877,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "currency", "fieldname": "currency",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -923,6 +914,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "Rate at which customer's currency is converted to company's base currency", "description": "Rate at which customer's currency is converted to company's base currency",
"fetch_if_empty": 0,
"fieldname": "conversion_rate", "fieldname": "conversion_rate",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -958,6 +950,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break2", "fieldname": "column_break2",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -989,6 +982,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "selling_price_list", "fieldname": "selling_price_list",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1024,6 +1018,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "price_list_currency", "fieldname": "price_list_currency",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1057,6 +1052,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "Rate at which Price list currency is converted to company's base currency", "description": "Rate at which Price list currency is converted to company's base currency",
"fetch_if_empty": 0,
"fieldname": "plc_conversion_rate", "fieldname": "plc_conversion_rate",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -1089,6 +1085,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "ignore_pricing_rule", "fieldname": "ignore_pricing_rule",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -1120,6 +1117,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "items_section", "fieldname": "items_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1153,6 +1151,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "items", "fieldname": "items",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -1188,6 +1187,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "sec_break23", "fieldname": "sec_break23",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1218,6 +1218,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "total_qty", "fieldname": "total_qty",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -1250,6 +1251,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_total", "fieldname": "base_total",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -1283,6 +1285,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_net_total", "fieldname": "base_net_total",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -1318,6 +1321,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_28", "fieldname": "column_break_28",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -1348,6 +1352,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "total", "fieldname": "total",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -1381,6 +1386,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "net_total", "fieldname": "net_total",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -1413,6 +1419,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "total_net_weight", "fieldname": "total_net_weight",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -1445,6 +1452,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "taxes_section", "fieldname": "taxes_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1478,6 +1486,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "taxes_and_charges", "fieldname": "taxes_and_charges",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1512,6 +1521,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_34", "fieldname": "column_break_34",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -1542,6 +1552,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "shipping_rule", "fieldname": "shipping_rule",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1575,6 +1586,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_36", "fieldname": "section_break_36",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1605,6 +1617,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "taxes", "fieldname": "taxes",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -1639,6 +1652,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "sec_tax_breakup", "fieldname": "sec_tax_breakup",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1671,6 +1685,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "other_charges_calculation", "fieldname": "other_charges_calculation",
"fieldtype": "Text", "fieldtype": "Text",
"hidden": 0, "hidden": 0,
@@ -1703,6 +1718,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_39", "fieldname": "section_break_39",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1733,6 +1749,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_total_taxes_and_charges", "fieldname": "base_total_taxes_and_charges",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -1767,6 +1784,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_42", "fieldname": "column_break_42",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -1797,6 +1815,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "total_taxes_and_charges", "fieldname": "total_taxes_and_charges",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -1830,6 +1849,7 @@
"collapsible": 1, "collapsible": 1,
"collapsible_depends_on": "discount_amount", "collapsible_depends_on": "discount_amount",
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_44", "fieldname": "section_break_44",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1863,6 +1883,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "Grand Total", "default": "Grand Total",
"fetch_if_empty": 0,
"fieldname": "apply_discount_on", "fieldname": "apply_discount_on",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -1896,6 +1917,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_discount_amount", "fieldname": "base_discount_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -1929,6 +1951,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_46", "fieldname": "column_break_46",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -1960,6 +1983,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "additional_discount_percentage", "fieldname": "additional_discount_percentage",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -1992,6 +2016,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "discount_amount", "fieldname": "discount_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -2024,6 +2049,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "totals", "fieldname": "totals",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -2057,6 +2083,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_grand_total", "fieldname": "base_grand_total",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -2092,6 +2119,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_rounding_adjustment", "fieldname": "base_rounding_adjustment",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -2126,6 +2154,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "In Words will be visible once you save the Quotation.", "description": "In Words will be visible once you save the Quotation.",
"fetch_if_empty": 0,
"fieldname": "base_in_words", "fieldname": "base_in_words",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -2160,6 +2189,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_rounded_total", "fieldname": "base_rounded_total",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -2195,6 +2225,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break3", "fieldname": "column_break3",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -2227,6 +2258,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "grand_total", "fieldname": "grand_total",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -2262,6 +2294,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "rounding_adjustment", "fieldname": "rounding_adjustment",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -2295,6 +2328,7 @@
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "rounded_total", "fieldname": "rounded_total",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -2330,6 +2364,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "in_words", "fieldname": "in_words",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -2366,6 +2401,7 @@
"collapsible_depends_on": "", "collapsible_depends_on": "",
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "payment_schedule_section", "fieldname": "payment_schedule_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -2398,6 +2434,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "payment_terms_template", "fieldname": "payment_terms_template",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2431,6 +2468,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "payment_schedule", "fieldname": "payment_schedule",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -2465,6 +2503,7 @@
"collapsible": 1, "collapsible": 1,
"collapsible_depends_on": "terms", "collapsible_depends_on": "terms",
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "terms_section_break", "fieldname": "terms_section_break",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -2498,6 +2537,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "tc_name", "fieldname": "tc_name",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2532,6 +2572,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "terms", "fieldname": "terms",
"fieldtype": "Text Editor", "fieldtype": "Text Editor",
"hidden": 0, "hidden": 0,
@@ -2565,6 +2606,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "print_settings", "fieldname": "print_settings",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -2597,6 +2639,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "letter_head", "fieldname": "letter_head",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2631,6 +2674,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "group_same_items", "fieldname": "group_same_items",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -2663,6 +2707,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_73", "fieldname": "column_break_73",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -2694,6 +2739,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "select_print_heading", "fieldname": "select_print_heading",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2728,6 +2774,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "language", "fieldname": "language",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -2760,6 +2807,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "subscription_section", "fieldname": "subscription_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -2792,6 +2840,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "auto_repeat", "fieldname": "auto_repeat",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2826,6 +2875,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval: doc.auto_repeat", "depends_on": "eval: doc.auto_repeat",
"fetch_if_empty": 0,
"fieldname": "update_auto_repeat_reference", "fieldname": "update_auto_repeat_reference",
"fieldtype": "Button", "fieldtype": "Button",
"hidden": 0, "hidden": 0,
@@ -2858,6 +2908,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "more_info", "fieldname": "more_info",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -2891,6 +2942,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "campaign", "fieldname": "campaign",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2925,6 +2977,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "source", "fieldname": "source",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2960,6 +3013,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.status===\"Lost\"", "depends_on": "eval:doc.status===\"Lost\"",
"fetch_if_empty": 0,
"fieldname": "order_lost_reason", "fieldname": "order_lost_reason",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
@@ -2993,6 +3047,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break4", "fieldname": "column_break4",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -3026,6 +3081,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "Draft", "default": "Draft",
"fetch_if_empty": 0,
"fieldname": "status", "fieldname": "status",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -3060,6 +3116,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "enq_det", "fieldname": "enq_det",
"fieldtype": "Text", "fieldtype": "Text",
"hidden": 1, "hidden": 1,
@@ -3093,6 +3150,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "supplier_quotation", "fieldname": "supplier_quotation",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -3126,6 +3184,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "opportunity", "fieldname": "opportunity",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -3165,7 +3224,7 @@
"istable": 0, "istable": 0,
"max_attachments": 1, "max_attachments": 1,
"menu_index": 0, "menu_index": 0,
"modified": "2019-01-07 16:51:55.604845", "modified": "2019-04-25 15:26:21.983298",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Selling", "module": "Selling",
"name": "Quotation", "name": "Quotation",
@@ -3331,11 +3390,11 @@
"quick_entry": 0, "quick_entry": 0,
"read_only": 0, "read_only": 0,
"read_only_onload": 1, "read_only_onload": 1,
"search_fields": "status,transaction_date,customer,lead,order_type", "search_fields": "status,transaction_date,party_name,order_type",
"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": "customer", "timeline_field": "party_name",
"title_field": "title", "title_field": "title",
"track_changes": 0, "track_changes": 0,
"track_seen": 0, "track_seen": 0,

View File

@@ -28,7 +28,6 @@ class Quotation(SellingController):
self.update_opportunity() self.update_opportunity()
self.validate_order_type() self.validate_order_type()
self.validate_uom_is_integer("stock_uom", "qty") self.validate_uom_is_integer("stock_uom", "qty")
self.validate_quotation_to()
self.validate_valid_till() self.validate_valid_till()
if self.items: if self.items:
self.with_items = 1 self.with_items = 1
@@ -43,16 +42,9 @@ class Quotation(SellingController):
def validate_order_type(self): def validate_order_type(self):
super(Quotation, self).validate_order_type() super(Quotation, self).validate_order_type()
def validate_quotation_to(self):
if self.customer:
self.quotation_to = "Customer"
self.lead = None
elif self.lead:
self.quotation_to = "Lead"
def update_lead(self): def update_lead(self):
if self.lead: if self.quotation_to == "Lead" and self.party_name:
frappe.get_doc("Lead", self.lead).set_status(update=True) frappe.get_doc("Lead", self.party_name).set_status(update=True)
def update_opportunity(self): def update_opportunity(self):
for opportunity in list(set([d.prevdoc_docname for d in self.get("items")])): for opportunity in list(set([d.prevdoc_docname for d in self.get("items")])):
@@ -212,9 +204,9 @@ def _make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
return doclist return doclist
def _make_customer(source_name, ignore_permissions=False): def _make_customer(source_name, ignore_permissions=False):
quotation = frappe.db.get_value("Quotation", source_name, ["lead", "order_type", "customer"]) quotation = frappe.db.get_value("Quotation", source_name, ["order_type", "party_name", "customer_name"])
if quotation and quotation[0] and not quotation[2]: if quotation and quotation[1] and not quotation[2]:
lead_name = quotation[0] lead_name = quotation[1]
customer_name = frappe.db.get_value("Customer", {"lead_name": lead_name}, customer_name = frappe.db.get_value("Customer", {"lead_name": lead_name},
["name", "customer_name"], as_dict=True) ["name", "customer_name"], as_dict=True)
if not customer_name: if not customer_name:
@@ -242,3 +234,5 @@ def _make_customer(source_name, ignore_permissions=False):
frappe.throw(_("Please create Customer from Lead {0}").format(lead_name)) frappe.throw(_("Please create Customer from Lead {0}").format(lead_name))
else: else:
return customer_name return customer_name
else:
return frappe.get_doc("Customer",quotation[2])

View File

@@ -203,15 +203,15 @@ class TestQuotation(unittest.TestCase):
test_records = frappe.get_test_records('Quotation') test_records = frappe.get_test_records('Quotation')
def get_quotation_dict(customer=None, item_code=None): def get_quotation_dict(party_name=None, item_code=None):
if not customer: if not party_name:
customer = '_Test Customer' party_name = '_Test Customer'
if not item_code: if not item_code:
item_code = '_Test Item' item_code = '_Test Item'
return { return {
'doctype': 'Quotation', 'doctype': 'Quotation',
'customer': customer, 'party_name': party_name,
'items': [ 'items': [
{ {
'item_code': item_code, 'item_code': item_code,
@@ -229,7 +229,7 @@ def make_quotation(**args):
qo.transaction_date = args.transaction_date qo.transaction_date = args.transaction_date
qo.company = args.company or "_Test Company" qo.company = args.company or "_Test Company"
qo.customer = args.customer or "_Test Customer" qo.party_name = args.party_name or "_Test Customer"
qo.currency = args.currency or "INR" qo.currency = args.currency or "INR"
if args.selling_price_list: if args.selling_price_list:
qo.selling_price_list = args.selling_price_list qo.selling_price_list = args.selling_price_list

View File

@@ -1,37 +1,37 @@
[ [
{ {
"company": "_Test Company", "company": "_Test Company",
"conversion_rate": 1.0, "conversion_rate": 1.0,
"currency": "INR", "currency": "INR",
"customer": "_Test Customer", "party_name": "_Test Customer",
"customer_group": "_Test Customer Group", "customer_group": "_Test Customer Group",
"customer_name": "_Test Customer", "customer_name": "_Test Customer",
"doctype": "Quotation", "doctype": "Quotation",
"base_grand_total": 1000.0, "base_grand_total": 1000.0,
"grand_total": 1000.0, "grand_total": 1000.0,
"order_type": "Sales", "order_type": "Sales",
"plc_conversion_rate": 1.0, "plc_conversion_rate": 1.0,
"price_list_currency": "INR", "price_list_currency": "INR",
"items": [ "items": [
{ {
"base_amount": 1000.0, "base_amount": 1000.0,
"base_rate": 100.0, "base_rate": 100.0,
"description": "CPU", "description": "CPU",
"doctype": "Quotation Item", "doctype": "Quotation Item",
"item_code": "_Test Item Home Desktop 100", "item_code": "_Test Item Home Desktop 100",
"item_name": "CPU", "item_name": "CPU",
"parentfield": "items", "parentfield": "items",
"qty": 10.0, "qty": 10.0,
"rate": 100.0, "rate": 100.0,
"uom": "_Test UOM 1", "uom": "_Test UOM 1",
"stock_uom": "_Test UOM 1", "stock_uom": "_Test UOM 1",
"conversion_factor": 1.0 "conversion_factor": 1.0
} }
], ],
"quotation_to": "Customer", "quotation_to": "Customer",
"selling_price_list": "_Test Price List", "selling_price_list": "_Test Price List",
"territory": "_Test Territory", "territory": "_Test Territory",
"transaction_date": "2013-02-21", "transaction_date": "2013-02-21",
"valid_till": "2013-03-21" "valid_till": "2013-03-21"
} }
] ]

View File

@@ -33,7 +33,7 @@ def make_sample_data(domains, make_dependent = False):
def make_opportunity(items, customer): def make_opportunity(items, customer):
b = frappe.get_doc({ b = frappe.get_doc({
"doctype": "Opportunity", "doctype": "Opportunity",
"enquiry_from": "Customer", "opportunity_from": "Customer",
"customer": customer, "customer": customer,
"opportunity_type": _("Sales"), "opportunity_type": _("Sales"),
"with_items": 1 "with_items": 1

View File

@@ -196,7 +196,7 @@ def _get_cart_quotation(party=None):
party = get_party() party = get_party()
quotation = frappe.get_all("Quotation", fields=["name"], filters= quotation = frappe.get_all("Quotation", fields=["name"], filters=
{party.doctype.lower(): party.name, "order_type": "Shopping Cart", "docstatus": 0}, {"party_name": party.name, "order_type": "Shopping Cart", "docstatus": 0},
order_by="modified desc", limit_page_length=1) order_by="modified desc", limit_page_length=1)
if quotation: if quotation:
@@ -211,7 +211,7 @@ def _get_cart_quotation(party=None):
"status": "Draft", "status": "Draft",
"docstatus": 0, "docstatus": 0,
"__islocal": 1, "__islocal": 1,
(party.doctype.lower()): party.name "party_name": party.name
}) })
qdoc.contact_person = frappe.db.get_value("Contact", {"email_id": frappe.session.user}) qdoc.contact_person = frappe.db.get_value("Contact", {"email_id": frappe.session.user})
@@ -291,9 +291,9 @@ def _set_price_list(quotation, cart_settings):
# check if customer price list exists # check if customer price list exists
selling_price_list = None selling_price_list = None
if quotation.customer: if quotation.party_name:
from erpnext.accounts.party import get_default_price_list from erpnext.accounts.party import get_default_price_list
selling_price_list = get_default_price_list(frappe.get_doc("Customer", quotation.customer)) selling_price_list = get_default_price_list(frappe.get_doc("Customer", quotation.party_name))
# else check for territory based price list # else check for territory based price list
if not selling_price_list: if not selling_price_list:
@@ -305,9 +305,9 @@ def set_taxes(quotation, cart_settings):
"""set taxes based on billing territory""" """set taxes based on billing territory"""
from erpnext.accounts.party import set_taxes from erpnext.accounts.party import set_taxes
customer_group = frappe.db.get_value("Customer", quotation.customer, "customer_group") customer_group = frappe.db.get_value("Customer", quotation.party_name, "customer_group")
quotation.taxes_and_charges = set_taxes(quotation.customer, "Customer", \ quotation.taxes_and_charges = set_taxes(quotation.party_name, "Customer", \
quotation.transaction_date, quotation.company, customer_group, None, \ quotation.transaction_date, quotation.company, customer_group, None, \
quotation.customer_address, quotation.shipping_address_name, 1) quotation.customer_address, quotation.shipping_address_name, 1)
# #

View File

@@ -33,7 +33,6 @@ class TestShoppingCart(unittest.TestCase):
self.assertEqual(quotation.quotation_to, "Customer") self.assertEqual(quotation.quotation_to, "Customer")
self.assertEqual(quotation.contact_person, self.assertEqual(quotation.contact_person,
frappe.db.get_value("Contact", dict(email_id="test_cart_user@example.com"))) frappe.db.get_value("Contact", dict(email_id="test_cart_user@example.com")))
self.assertEqual(quotation.lead, None)
self.assertEqual(quotation.contact_email, frappe.session.user) self.assertEqual(quotation.contact_email, frappe.session.user)
return quotation return quotation
@@ -44,8 +43,7 @@ class TestShoppingCart(unittest.TestCase):
# test if quotation with customer is fetched # test if quotation with customer is fetched
quotation = _get_cart_quotation() quotation = _get_cart_quotation()
self.assertEqual(quotation.quotation_to, "Customer") self.assertEqual(quotation.quotation_to, "Customer")
self.assertEqual(quotation.customer, "_Test Customer") self.assertEqual(quotation.party_name, "_Test Customer")
self.assertEqual(quotation.lead, None)
self.assertEqual(quotation.contact_email, frappe.session.user) self.assertEqual(quotation.contact_email, frappe.session.user)
return quotation return quotation
@@ -107,7 +105,7 @@ class TestShoppingCart(unittest.TestCase):
from erpnext.accounts.party import set_taxes from erpnext.accounts.party import set_taxes
tax_rule_master = set_taxes(quotation.customer, "Customer", \ tax_rule_master = set_taxes(quotation.party_name, "Customer", \
quotation.transaction_date, quotation.company, None, None, \ quotation.transaction_date, quotation.company, None, None, \
quotation.customer_address, quotation.shipping_address_name, 1) quotation.customer_address, quotation.shipping_address_name, 1)
self.assertEqual(quotation.taxes_and_charges, tax_rule_master) self.assertEqual(quotation.taxes_and_charges, tax_rule_master)
@@ -122,7 +120,7 @@ class TestShoppingCart(unittest.TestCase):
"doctype": "Quotation", "doctype": "Quotation",
"quotation_to": "Customer", "quotation_to": "Customer",
"order_type": "Shopping Cart", "order_type": "Shopping Cart",
"customer": get_party(frappe.session.user).name, "party_name": get_party(frappe.session.user).name,
"docstatus": 0, "docstatus": 0,
"contact_email": frappe.session.user, "contact_email": frappe.session.user,
"selling_price_list": "_Test Price List Rest of the World", "selling_price_list": "_Test Price List Rest of the World",

View File

@@ -407,7 +407,6 @@ def get_returned_qty_map(delivery_note):
@frappe.whitelist() @frappe.whitelist()
def make_sales_invoice(source_name, target_doc=None): def make_sales_invoice(source_name, target_doc=None):
doc = frappe.get_doc('Delivery Note', source_name) doc = frappe.get_doc('Delivery Note', source_name)
sales_orders = [d.against_sales_order for d in doc.items]
returned_qty_map = get_returned_qty_map(source_name) returned_qty_map = get_returned_qty_map(source_name)
invoiced_qty_map = get_invoiced_qty_map(source_name) invoiced_qty_map = get_invoiced_qty_map(source_name)
@@ -447,7 +446,7 @@ def make_sales_invoice(source_name, target_doc=None):
returned_qty = 0 returned_qty = 0
return pending_qty, returned_qty return pending_qty, returned_qty
doc = get_mapped_doc("Delivery Note", source_name, { doc = get_mapped_doc("Delivery Note", source_name, {
"Delivery Note": { "Delivery Note": {
"doctype": "Sales Invoice", "doctype": "Sales Invoice",
"validation": { "validation": {
@@ -465,7 +464,7 @@ def make_sales_invoice(source_name, target_doc=None):
"cost_center": "cost_center" "cost_center": "cost_center"
}, },
"postprocess": update_item, "postprocess": update_item,
"filter": lambda d: get_pending_qty(d)[0]<=0 "filter": lambda d: get_pending_qty(d)[0] <= 0 if not doc.get("is_return") else get_pending_qty(d)[0] > 0
}, },
"Sales Taxes and Charges": { "Sales Taxes and Charges": {
"doctype": "Sales Taxes and Charges", "doctype": "Sales Taxes and Charges",

View File

@@ -31,7 +31,7 @@ class PurchaseReceipt(BuyingController):
'target_parent_dt': 'Purchase Order', 'target_parent_dt': 'Purchase Order',
'target_parent_field': 'per_received', 'target_parent_field': 'per_received',
'target_ref_field': 'qty', 'target_ref_field': 'qty',
'source_field': 'qty', 'source_field': 'received_qty',
'percent_join_field': 'purchase_order', 'percent_join_field': 'purchase_order',
'overflow_type': 'receipt' 'overflow_type': 'receipt'
}, },
@@ -458,7 +458,7 @@ def make_purchase_invoice(source_name, target_doc=None):
"asset": "asset", "asset": "asset",
}, },
"postprocess": update_item, "postprocess": update_item,
"filter": lambda d: get_pending_qty(d)[0]<=0 "filter": lambda d: get_pending_qty(d)[0] <= 0 if not doc.get("is_return") else get_pending_qty(d)[0] > 0
}, },
"Purchase Taxes and Charges": { "Purchase Taxes and Charges": {
"doctype": "Purchase Taxes and Charges", "doctype": "Purchase Taxes and Charges",

View File

@@ -431,7 +431,7 @@ def insert_item_price(args):
def get_item_price(args, item_code, ignore_party=False): def get_item_price(args, item_code, ignore_party=False):
""" """
Get name, price_list_rate from Item Price based on conditions Get name, price_list_rate from Item Price based on conditions
Check if the Derised qty is within the increment of the packing list. Check if the desired qty is within the increment of the packing list.
:param args: dict (or frappe._dict) with mandatory fields price_list, uom :param args: dict (or frappe._dict) with mandatory fields price_list, uom
optional fields min_qty, transaction_date, customer, supplier optional fields min_qty, transaction_date, customer, supplier
:param item_code: str, Item Doctype field item_code :param item_code: str, Item Doctype field item_code
@@ -469,11 +469,11 @@ def get_price_list_rate_for(args, item_code):
for min_qty 9 and min_qty 20. It returns Item Price Rate for qty 9 as for min_qty 9 and min_qty 20. It returns Item Price Rate for qty 9 as
the best fit in the range of avaliable min_qtyies the best fit in the range of avaliable min_qtyies
:param customer: link to Customer DocType :param customer: link to Customer DocType
:param supplier: link to Supplier DocType :param supplier: link to Supplier DocType
:param price_list: str (Standard Buying or Standard Selling) :param price_list: str (Standard Buying or Standard Selling)
:param item_code: str, Item Doctype field item_code :param item_code: str, Item Doctype field item_code
:param qty: Derised Qty :param qty: Desired Qty
:param transaction_date: Date of the price :param transaction_date: Date of the price
""" """
item_price_args = { item_price_args = {
@@ -498,7 +498,7 @@ def get_price_list_rate_for(args, item_code):
general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party")) general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party"))
if not general_price_list_rate and args.get("uom") != args.get("stock_uom"): if not general_price_list_rate and args.get("uom") != args.get("stock_uom"):
item_price_args["args"] = args.get("stock_uom") item_price_args["uom"] = args.get("stock_uom")
general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party")) general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party"))
if general_price_list_rate: if general_price_list_rate:
@@ -514,11 +514,11 @@ def get_price_list_rate_for(args, item_code):
def check_packing_list(price_list_rate_name, desired_qty, item_code): def check_packing_list(price_list_rate_name, desired_qty, item_code):
""" """
Check if the Derised qty is within the increment of the packing list. Check if the desired qty is within the increment of the packing list.
:param price_list_rate_name: Name of Item Price :param price_list_rate_name: Name of Item Price
:param desired_qty: Derised Qt :param desired_qty: Desired Qt
:param item_code: str, Item Doctype field item_code :param item_code: str, Item Doctype field item_code
:param qty: Derised Qt :param qty: Desired Qt
""" """
flag = True flag = True

View File

@@ -0,0 +1,34 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Inactive Items"] = {
"filters": [
{
fieldname: "item",
label: __("Item"),
fieldtype: "Link",
options: "Item"
},
{
fieldname: "item_group",
label: __("Item Group"),
fieldtype: "Link",
options: "Item Group"
},
{
fieldname: "based_on",
label: __("Based On"),
fieldtype: "Select",
options: "Sales Order\nSales Invoice",
default: "Sales Order"
},
{
fieldname: "days",
label: __("Days Since Last order"),
fieldtype: "Select",
options: [30, 60, 90],
default: 30
},
]
}

View File

@@ -0,0 +1,31 @@
{
"add_total_row": 0,
"creation": "2019-04-16 16:05:00.647308",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Test Letter Head 1",
"modified": "2019-04-16 16:06:33.630043",
"modified_by": "Administrator",
"module": "Stock",
"name": "Inactive Items",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Sales Invoice",
"report_name": "Inactive Items",
"report_type": "Script Report",
"roles": [
{
"role": "Accounts User"
},
{
"role": "Accounts Manager"
},
{
"role": "Auditor"
}
]
}

View File

@@ -0,0 +1,148 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.utils import getdate, add_days, today, cint
from frappe import _
def execute(filters=None):
columns = get_columns()
data = get_data(filters)
return columns, data
def get_columns():
columns = [
{
"fieldname": "territory",
"fieldtype": "Link",
"label": _("Territory"),
"options": "Territory",
"width": 100
},
{
"fieldname": "item_group",
"fieldtype": "Link",
"label": _("Item Group"),
"options": "Item Group",
"width": 150
},
{
"fieldname": "item_name",
"fieldtype": "Link",
"options": "Item",
"label": "Item",
"width": 150
},
{
"fieldname": "item_name",
"fieldtype": "Data",
"label": _("Item Name"),
"width": 150
},
{
"fieldname": "customer",
"fieldtype": "Link",
"label": _("Customer"),
"options": "Customer",
"width": 100
},
{
"fieldname": "last_order_date",
"fieldtype": "Date",
"label": _("Last Order Date"),
"width": 100
},
{
"fieldname": "qty",
"fieldtype": "Float",
"label": _("Quantity"),
"width": 100
},
{
"fieldname": "days_since_last_order",
"fieldtype": "Int",
"label": _("Days Since Last Order"),
"width": 100
},
]
return columns
def get_data(filters):
data = []
items = get_items(filters)
sales_invoice_data = get_sales_details(filters)
for item in items:
if sales_invoice_data.get(item.name):
item_obj = sales_invoice_data[item.name]
if item_obj.days_since_last_order > cint(filters['days']):
row = {
"territory": item_obj.territory,
"item_group": item_obj.item_group,
"item": item_obj.name,
"item_name": item_obj.item_name,
"customer": item_obj.customer,
"last_order_date": item_obj.last_order_date,
"qty": item_obj.qty,
"days_since_last_order": item_obj.days_since_last_order
}
data.append(row)
else:
row = {
"item_group": item.item_group,
"item": item.name,
"item_name": item.item_name
}
data.append(row)
return data
def get_sales_details(filters):
data = []
item_details_map = {}
date_field = "s.transaction_date" if filters["based_on"] == "Sales Order" else "s.posting_date"
sales_data = frappe.db.sql("""
select s.territory, s.customer, si.item_group, si.item_name, si.qty, {date_field} as last_order_date,
DATEDIFF(CURDATE(), {date_field}) as days_since_last_order
from `tab{doctype}` s, `tab{doctype} Item` si
where s.name = si.parent and s.docstatus = 1
group by si.name order by days_since_last_order """ #nosec
.format(date_field = date_field, doctype = filters['based_on']), as_dict=1)
for d in sales_data:
item_details_map.setdefault(d.item_name, d)
return item_details_map
def get_items(filters):
filters_dict = {
"disabled": 0,
"is_stock_item": 1
}
if filters.get("item_group"):
filters_dict.update({
"item_group": filters["item_group"]
})
if filters.get("item"):
filters_dict.update({
"name": filters["item"]
})
items = frappe.get_all("Item", fields=["name", "item_group", "item_name"], filters=filters_dict, order_by="name")
return items

View File

@@ -151,10 +151,10 @@ def get_opening_balance(filters, columns):
"posting_date": filters.from_date, "posting_date": filters.from_date,
"posting_time": "00:00:00" "posting_time": "00:00:00"
}) })
row = [""]*len(columns) row = {}
row[1] = _("'Opening'") row["item_code"] = _("'Opening'")
for i, v in ((9, 'qty_after_transaction'), (11, 'valuation_rate'), (12, 'stock_value')): for dummy, v in ((9, 'qty_after_transaction'), (11, 'valuation_rate'), (12, 'stock_value')):
row[i] = last_entry.get(v, 0) row[v] = last_entry.get(v, 0)
return row return row

View File

@@ -28,7 +28,7 @@ def send_message(subject="Website Query", message="", sender="", status="Open"):
opportunity = frappe.get_doc(dict( opportunity = frappe.get_doc(dict(
doctype ='Opportunity', doctype ='Opportunity',
enquiry_from = 'Customer' if customer else 'Lead', opportunity_from = 'Customer' if customer else 'Lead',
status = 'Open', status = 'Open',
title = subject, title = subject,
contact_email = sender, contact_email = sender,