Merge branch 'develop' into gst_invoice_validation
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index d3e8a44..b361c0c 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -695,6 +695,7 @@
refresh_field(['timesheets'])
}
})
+ frm.refresh();
},
onload: function(frm) {
@@ -810,6 +811,65 @@
},
refresh: function(frm) {
+ if (frm.doc.project) {
+ frm.add_custom_button(__('Fetch Timesheet'), function() {
+ let d = new frappe.ui.Dialog({
+ title: __('Fetch Timesheet'),
+ fields: [
+ {
+ "label" : "From",
+ "fieldname": "from_time",
+ "fieldtype": "Date",
+ "reqd": 1,
+ },
+ {
+ fieldtype: 'Column Break',
+ fieldname: 'col_break_1',
+ },
+ {
+ "label" : "To",
+ "fieldname": "to_time",
+ "fieldtype": "Date",
+ "reqd": 1,
+ }
+ ],
+ primary_action: function() {
+ let data = d.get_values();
+ frappe.call({
+ method: "erpnext.projects.doctype.timesheet.timesheet.get_projectwise_timesheet_data",
+ args: {
+ from_time: data.from_time,
+ to_time: data.to_time,
+ project: frm.doc.project
+ },
+ callback: function(r) {
+ if(!r.exc) {
+ if(r.message.length > 0) {
+ frm.clear_table('timesheets')
+ r.message.forEach((d) => {
+ frm.add_child('timesheets',{
+ 'time_sheet': d.parent,
+ 'billing_hours': d.billing_hours,
+ 'billing_amount': d.billing_amt,
+ 'timesheet_detail': d.name
+ });
+ });
+ frm.refresh_field('timesheets')
+ }
+ else {
+ frappe.msgprint(__('No Timesheet Found.'))
+ }
+ d.hide();
+ }
+ }
+ });
+ },
+ primary_action_label: __('Get Timesheets')
+ });
+ d.show();
+ })
+ }
+
if (frappe.boot.active_domains.includes("Healthcare")) {
frm.set_df_property("patient", "hidden", 0);
frm.set_df_property("patient_name", "hidden", 0);
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 38b2284..e01cb6e 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -617,6 +617,7 @@
FROM `tabGL Entry`
WHERE
party_type = %s and against_voucher is null
+ and is_cancelled = 0
and {1} GROUP BY party"""
.format(("credit") if party_type == "Customer" else "debit", cond) , party_type)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 5e3822e..69d605d 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -18,7 +18,6 @@
class LeaveAllocation(Document):
def validate(self):
self.validate_period()
- self.validate_new_leaves_allocated_value()
self.validate_allocation_overlap()
self.validate_back_dated_allocation()
self.set_total_leaves_allocated()
@@ -72,11 +71,6 @@
if frappe.db.get_value("Leave Type", self.leave_type, "is_lwp"):
frappe.throw(_("Leave Type {0} cannot be allocated since it is leave without pay").format(self.leave_type))
- def validate_new_leaves_allocated_value(self):
- """validate that leave allocation is in multiples of 0.5"""
- if flt(self.new_leaves_allocated) % 0.5:
- frappe.throw(_("Leaves must be allocated in multiples of 0.5"), ValueMultiplierError)
-
def validate_allocation_overlap(self):
leave_allocation = frappe.db.sql("""
SELECT
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
index a0327bd..3373350 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
@@ -106,12 +106,14 @@
"fieldname": "leaves_allocated",
"fieldtype": "Check",
"hidden": 1,
- "label": "Leaves Allocated"
+ "label": "Leaves Allocated",
+ "no_copy": 1,
+ "print_hide": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-12-31 16:43:30.695206",
+ "modified": "2021-03-01 17:54:01.014509",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Policy Assignment",
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
index a5068bc..4064c56 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
@@ -6,7 +6,7 @@
import frappe
from frappe.model.document import Document
from frappe import _, bold
-from frappe.utils import getdate, date_diff, comma_and, formatdate
+from frappe.utils import getdate, date_diff, comma_and, formatdate, get_datetime, flt
from math import ceil
import json
from six import string_types
@@ -84,17 +84,52 @@
return allocation.name, new_leaves_allocated
def get_new_leaves(self, leave_type, new_leaves_allocated, leave_type_details, date_of_joining):
+ from frappe.model.meta import get_field_precision
+ precision = get_field_precision(frappe.get_meta("Leave Allocation").get_field("new_leaves_allocated"))
+
+ # Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0
+ if leave_type_details.get(leave_type).is_compensatory == 1:
+ new_leaves_allocated = 0
+
+ elif leave_type_details.get(leave_type).is_earned_leave == 1:
+ if self.assignment_based_on == "Leave Period":
+ new_leaves_allocated = self.get_leaves_for_passed_months(leave_type, new_leaves_allocated, leave_type_details, date_of_joining)
+ else:
+ new_leaves_allocated = 0
# Calculate leaves at pro-rata basis for employees joining after the beginning of the given leave period
- if getdate(date_of_joining) > getdate(self.effective_from):
+ elif getdate(date_of_joining) > getdate(self.effective_from):
remaining_period = ((date_diff(self.effective_to, date_of_joining) + 1) / (date_diff(self.effective_to, self.effective_from) + 1))
new_leaves_allocated = ceil(new_leaves_allocated * remaining_period)
- # Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0
- if leave_type_details.get(leave_type).is_earned_leave == 1 or leave_type_details.get(leave_type).is_compensatory == 1:
- new_leaves_allocated = 0
+ return flt(new_leaves_allocated, precision)
+
+ def get_leaves_for_passed_months(self, leave_type, new_leaves_allocated, leave_type_details, date_of_joining):
+ from erpnext.hr.utils import get_monthly_earned_leave
+
+ current_month = get_datetime().month
+ current_year = get_datetime().year
+
+ from_date = frappe.db.get_value("Leave Period", self.leave_period, "from_date")
+ if getdate(date_of_joining) > getdate(from_date):
+ from_date = date_of_joining
+
+ from_date_month = get_datetime(from_date).month
+ from_date_year = get_datetime(from_date).year
+
+ months_passed = 0
+ if current_year == from_date_year and current_month > from_date_month:
+ months_passed = current_month - from_date_month
+ elif current_year > from_date_year:
+ months_passed = (12 - from_date_month) + current_month
+
+ if months_passed > 0:
+ monthly_earned_leave = get_monthly_earned_leave(new_leaves_allocated,
+ leave_type_details.get(leave_type).earned_leave_frequency, leave_type_details.get(leave_type).rounding)
+ new_leaves_allocated = monthly_earned_leave * months_passed
return new_leaves_allocated
+
@frappe.whitelist()
def grant_leave_for_multiple_employees(leave_policy_assignments):
leave_policy_assignments = json.loads(leave_policy_assignments)
@@ -156,7 +191,8 @@
def get_leave_type_details():
leave_type_details = frappe._dict()
leave_types = frappe.get_all("Leave Type",
- fields=["name", "is_lwp", "is_earned_leave", "is_compensatory", "is_carry_forward", "expire_carry_forwarded_leaves_after_days"])
+ fields=["name", "is_lwp", "is_earned_leave", "is_compensatory",
+ "is_carry_forward", "expire_carry_forwarded_leaves_after_days", "earned_leave_frequency", "rounding"])
for d in leave_types:
leave_type_details.setdefault(d.name, d)
return leave_type_details
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index a209291..fc577ef 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -172,7 +172,7 @@
"fieldname": "rounding",
"fieldtype": "Select",
"label": "Rounding",
- "options": "0.5\n1.0"
+ "options": "\n0.25\n0.5\n1.0"
},
{
"depends_on": "is_carry_forward",
@@ -197,6 +197,7 @@
"label": "Based On Date Of Joining"
},
{
+ "default": "0",
"depends_on": "eval:doc.is_lwp == 0",
"fieldname": "is_ppl",
"fieldtype": "Check",
@@ -213,7 +214,7 @@
"icon": "fa fa-flag",
"idx": 1,
"links": [],
- "modified": "2020-10-15 15:49:47.555105",
+ "modified": "2021-03-02 11:22:33.776320",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
diff --git a/erpnext/hr/doctype/skill/skill.json b/erpnext/hr/doctype/skill/skill.json
index a10381f..4c8a8c9 100644
--- a/erpnext/hr/doctype/skill/skill.json
+++ b/erpnext/hr/doctype/skill/skill.json
@@ -16,7 +16,7 @@
"fields": [
{
"allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
+ "allow_in_quick_entry": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -46,6 +46,12 @@
"set_only_once": 0,
"translatable": 0,
"unique": 1
+ },
+ {
+ "allow_in_quick_entry": 1,
+ "fieldname": "description",
+ "fieldtype": "Text",
+ "label": "Description"
}
],
"has_web_view": 0,
@@ -56,7 +62,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2021-02-24 09:55:00.536328",
+ "modified": "2021-02-26 10:55:00.536328",
"modified_by": "Administrator",
"module": "HR",
"name": "Skill",
diff --git a/erpnext/hr/page/team_updates/team_updates.js b/erpnext/hr/page/team_updates/team_updates.js
index 13d0074..3583297 100644
--- a/erpnext/hr/page/team_updates/team_updates.js
+++ b/erpnext/hr/page/team_updates/team_updates.js
@@ -36,7 +36,7 @@
start: me.start
},
callback: function(r) {
- if(r.message) {
+ if (r.message && r.message.length > 0) {
r.message.forEach(function(d) {
me.add_row(d);
});
@@ -75,6 +75,6 @@
}
me.last_feed_date = date;
- $(frappe.render_template('team_update_row', data)).appendTo(me.body)
+ $(frappe.render_template('team_update_row', data)).appendTo(me.body);
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index e2aa7a4..d57ef59 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -316,13 +316,7 @@
update_previous_leave_allocation(allocation, annual_allocation, e_leave_type)
def update_previous_leave_allocation(allocation, annual_allocation, e_leave_type):
- divide_by_frequency = {"Yearly": 1, "Half-Yearly": 6, "Quarterly": 4, "Monthly": 12}
- if annual_allocation:
- earned_leaves = flt(annual_allocation) / divide_by_frequency[e_leave_type.earned_leave_frequency]
- if e_leave_type.rounding == "0.5":
- earned_leaves = round(earned_leaves * 2) / 2
- else:
- earned_leaves = round(earned_leaves)
+ earned_leaves = get_monthly_earned_leave(annual_allocation, e_leave_type.earned_leave_frequency, e_leave_type.rounding)
allocation = frappe.get_doc('Leave Allocation', allocation.name)
new_allocation = flt(allocation.total_leaves_allocated) + flt(earned_leaves)
@@ -335,6 +329,21 @@
today_date = today()
create_additional_leave_ledger_entry(allocation, earned_leaves, today_date)
+def get_monthly_earned_leave(annual_leaves, frequency, rounding):
+ earned_leaves = 0.0
+ divide_by_frequency = {"Yearly": 1, "Half-Yearly": 6, "Quarterly": 4, "Monthly": 12}
+ if annual_leaves:
+ earned_leaves = flt(annual_leaves) / divide_by_frequency[frequency]
+ if rounding:
+ if rounding == "0.25":
+ earned_leaves = round(earned_leaves * 4) / 4
+ elif rounding == "0.5":
+ earned_leaves = round(earned_leaves * 2) / 2
+ else:
+ earned_leaves = round(earned_leaves)
+
+ return earned_leaves
+
def get_leave_allocations(date, leave_type):
return frappe.db.sql("""select name, employee, from_date, to_date, leave_policy_assignment, leave_policy
diff --git a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
index 3200363..d968e1f 100644
--- a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
+++ b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
@@ -1,13 +1,24 @@
import frappe
from frappe import _
-from frappe.utils import getdate, get_time
+from frappe.utils import getdate, get_time, today
from erpnext.stock.stock_ledger import update_entries_after
from erpnext.accounts.utils import update_gl_entries_after
def execute():
- frappe.reload_doc('stock', 'doctype', 'repost_item_valuation')
+ for doctype in ('repost_item_valuation', 'stock_entry_detail', 'purchase_receipt_item',
+ 'purchase_invoice_item', 'delivery_note_item', 'sales_invoice_item', 'packed_item'):
+ frappe.reload_doc('stock', 'doctype', doctype)
+ frappe.reload_doc('buying', 'doctype', 'purchase_receipt_item_supplied')
reposting_project_deployed_on = get_creation_time()
+ posting_date = getdate(reposting_project_deployed_on)
+ posting_time = get_time(reposting_project_deployed_on)
+
+ if posting_date == today():
+ return
+
+ frappe.clear_cache()
+ frappe.flags.warehouse_account_map = {}
data = frappe.db.sql('''
SELECT
@@ -41,8 +52,6 @@
print("Reposting General Ledger Entries...")
- posting_date = getdate(reposting_project_deployed_on)
- posting_time = get_time(reposting_project_deployed_on)
for row in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
update_gl_entries_after(posting_date, posting_time, company=row.name)
diff --git a/erpnext/payroll/doctype/payroll_settings/payroll_settings.json b/erpnext/payroll/doctype/payroll_settings/payroll_settings.json
index c47caa1..680e518 100644
--- a/erpnext/payroll/doctype/payroll_settings/payroll_settings.json
+++ b/erpnext/payroll/doctype/payroll_settings/payroll_settings.json
@@ -15,6 +15,7 @@
"daily_wages_fraction_for_half_day",
"email_salary_slip_to_employee",
"encrypt_salary_slips_in_emails",
+ "show_leave_balances_in_salary_slip",
"password_policy"
],
"fields": [
@@ -23,58 +24,44 @@
"fieldname": "payroll_based_on",
"fieldtype": "Select",
"label": "Calculate Payroll Working Days Based On",
- "options": "Leave\nAttendance",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Leave\nAttendance"
},
{
"fieldname": "max_working_hours_against_timesheet",
"fieldtype": "Float",
- "label": "Max working hours against Timesheet",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Max working hours against Timesheet"
},
{
"default": "0",
"description": "If checked, Total no. of Working Days will include holidays, and this will reduce the value of Salary Per Day",
"fieldname": "include_holidays_in_total_working_days",
"fieldtype": "Check",
- "label": "Include holidays in Total no. of Working Days",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Include holidays in Total no. of Working Days"
},
{
"default": "0",
"description": "If checked, hides and disables Rounded Total field in Salary Slips",
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
- "label": "Disable Rounded Total",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Disable Rounded Total"
},
{
"fieldname": "column_break_11",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"default": "0.5",
"description": "The fraction of daily wages to be paid for half-day attendance",
"fieldname": "daily_wages_fraction_for_half_day",
"fieldtype": "Float",
- "label": "Fraction of Daily Salary for Half Day",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Fraction of Daily Salary for Half Day"
},
{
"default": "1",
"description": "Emails salary slip to employee based on preferred email selected in Employee",
"fieldname": "email_salary_slip_to_employee",
"fieldtype": "Check",
- "label": "Email Salary Slip to Employee",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Email Salary Slip to Employee"
},
{
"default": "0",
@@ -82,9 +69,7 @@
"description": "The salary slip emailed to the employee will be password protected, the password will be generated based on the password policy.",
"fieldname": "encrypt_salary_slips_in_emails",
"fieldtype": "Check",
- "label": "Encrypt Salary Slips in Emails",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Encrypt Salary Slips in Emails"
},
{
"depends_on": "eval: doc.encrypt_salary_slips_in_emails == 1",
@@ -92,24 +77,27 @@
"fieldname": "password_policy",
"fieldtype": "Data",
"in_list_view": 1,
- "label": "Password Policy",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Password Policy"
},
{
"depends_on": "eval:doc.payroll_based_on == 'Attendance'",
"fieldname": "consider_unmarked_attendance_as",
"fieldtype": "Select",
"label": "Consider Unmarked Attendance As",
- "options": "Present\nAbsent",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Present\nAbsent"
+ },
+ {
+ "default": "0",
+ "fieldname": "show_leave_balances_in_salary_slip",
+ "fieldtype": "Check",
+ "label": "Show Leave Balances in Salary Slip"
}
],
"icon": "fa fa-cog",
+ "index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2020-06-22 17:00:58.408030",
+ "modified": "2021-02-19 11:07:55.873991",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Payroll Settings",
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.json b/erpnext/payroll/doctype/salary_slip/salary_slip.json
index 9f9691b..6688368 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.json
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.json
@@ -80,6 +80,8 @@
"total_in_words",
"column_break_69",
"base_total_in_words",
+ "leave_details_section",
+ "leave_details",
"section_break_75",
"amended_from"
],
@@ -612,13 +614,25 @@
"label": "Month To Date(Company Currency)",
"options": "Company:company:default_currency",
"read_only": 1
+ },
+ {
+ "fieldname": "leave_details_section",
+ "fieldtype": "Section Break",
+ "label": "Leave Details"
+ },
+ {
+ "fieldname": "leave_details",
+ "fieldtype": "Table",
+ "label": "Leave Details",
+ "options": "Salary Slip Leave",
+ "read_only": 1
}
],
"icon": "fa fa-file-text",
"idx": 9,
"is_submittable": 1,
"links": [],
- "modified": "2021-01-14 13:37:38.180920",
+ "modified": "2021-02-19 11:48:05.383945",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Salary Slip",
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index 60aff02..d9aadbf 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -19,6 +19,7 @@
from erpnext.payroll.doctype.employee_benefit_claim.employee_benefit_claim import get_benefit_claim_amount, get_last_payroll_period_benefits
from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts, create_repayment_entry
from erpnext.accounts.utils import get_fiscal_year
+from six import iteritems
class SalarySlip(TransactionBase):
def __init__(self, *args, **kwargs):
@@ -53,6 +54,7 @@
self.compute_year_to_date()
self.compute_month_to_date()
self.compute_component_wise_year_to_date()
+ self.add_leave_balances()
if frappe.db.get_single_value("Payroll Settings", "max_working_hours_against_timesheet"):
max_working_hours = frappe.db.get_single_value("Payroll Settings", "max_working_hours_against_timesheet")
@@ -1123,6 +1125,7 @@
#calculate total working hours, earnings based on hourly wages and totals
def calculate_total_for_salary_slip_based_on_timesheet(self):
if self.timesheets:
+ self.total_working_hours = 0
for timesheet in self.timesheets:
if timesheet.working_hours:
self.total_working_hours += timesheet.working_hours
@@ -1212,6 +1215,22 @@
return period_start_date, period_end_date
+ def add_leave_balances(self):
+ self.set('leave_details', [])
+
+ if frappe.db.get_single_value('Payroll Settings', 'show_leave_balances_in_salary_slip'):
+ from erpnext.hr.doctype.leave_application.leave_application import get_leave_details
+ leave_details = get_leave_details(self.employee, self.end_date)
+
+ for leave_type, leave_values in iteritems(leave_details['leave_allocation']):
+ self.append('leave_details', {
+ 'leave_type': leave_type,
+ 'total_allocated_leaves': flt(leave_values.get('total_leaves')),
+ 'expired_leaves': flt(leave_values.get('expired_leaves')),
+ 'used_leaves': flt(leave_values.get('leaves_taken')),
+ 'pending_leaves': flt(leave_values.get('pending_leaves')),
+ 'available_leaves': flt(leave_values.get('remaining_leaves'))
+ })
def unlink_ref_doc_from_salary_slip(ref_no):
linked_ss = frappe.db.sql_list("""select name from `tabSalary Slip`
diff --git a/erpnext/payroll/doctype/salary_slip_leave/__init__.py b/erpnext/payroll/doctype/salary_slip_leave/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/payroll/doctype/salary_slip_leave/__init__.py
diff --git a/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.json b/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.json
new file mode 100644
index 0000000..7ac453b
--- /dev/null
+++ b/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.json
@@ -0,0 +1,78 @@
+{
+ "actions": [],
+ "creation": "2021-02-19 11:45:18.173417",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "leave_type",
+ "total_allocated_leaves",
+ "expired_leaves",
+ "used_leaves",
+ "pending_leaves",
+ "available_leaves"
+ ],
+ "fields": [
+ {
+ "fieldname": "leave_type",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Leave Type",
+ "no_copy": 1,
+ "options": "Leave Type",
+ "read_only": 1
+ },
+ {
+ "fieldname": "total_allocated_leaves",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Total Allocated Leave",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "expired_leaves",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Expired Leave",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "used_leaves",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Used Leave",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "pending_leaves",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Pending Leave",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "available_leaves",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Available Leave",
+ "no_copy": 1,
+ "read_only": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-02-19 10:47:48.546724",
+ "modified_by": "Administrator",
+ "module": "Payroll",
+ "name": "Salary Slip Leave",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py b/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py
new file mode 100644
index 0000000..7a92bf1
--- /dev/null
+++ b/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class SalarySlipLeave(Document):
+ pass
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index ea81b3e..ed02f79 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -204,14 +204,16 @@
ts_detail.billing_rate = 0.0
@frappe.whitelist()
-def get_projectwise_timesheet_data(project, parent=None):
- cond = ''
+def get_projectwise_timesheet_data(project, parent=None, from_time=None, to_time=None):
+ condition = ''
if parent:
- cond = "and parent = %(parent)s"
+ condition = "AND parent = %(parent)s"
+ if from_time and to_time:
+ condition += "AND from_time BETWEEN %(from_time)s AND %(to_time)s"
return frappe.db.sql("""select name, parent, billing_hours, billing_amount as billing_amt
from `tabTimesheet Detail` where parenttype = 'Timesheet' and docstatus=1 and project = %(project)s {0} and billable = 1
- and sales_invoice is null""".format(cond), {'project': project, 'parent': parent}, as_dict=1)
+ and sales_invoice is null""".format(condition), {'project': project, 'parent': parent, 'from_time': from_time, 'to_time': to_time}, as_dict=1)
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
diff --git a/erpnext/quality_management/doctype/non_conformance/non_conformance.json b/erpnext/quality_management/doctype/non_conformance/non_conformance.json
index bfeb96b..8dfe2d6 100644
--- a/erpnext/quality_management/doctype/non_conformance/non_conformance.json
+++ b/erpnext/quality_management/doctype/non_conformance/non_conformance.json
@@ -70,18 +70,18 @@
},
{
"fieldname": "corrective_action",
- "fieldtype": "Text",
+ "fieldtype": "Text Editor",
"label": "Corrective Action"
},
{
"fieldname": "preventive_action",
- "fieldtype": "Text",
+ "fieldtype": "Text Editor",
"label": "Preventive Action"
}
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-10-26 15:27:47.247814",
+ "modified": "2021-02-26 15:27:47.247814",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Non Conformance",
@@ -115,4 +115,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index 36033d9..c041d26 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -140,7 +140,7 @@
doc: frm.doc,
freeze: true,
callback: function() {
- frappe.msgprint(__("Default tax templates for sales and purchase are created."));
+ frappe.msgprint(__("Default tax templates for sales, purchase and items are created."));
}
})
},
diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py
index e66fa76..c3c1593 100644
--- a/erpnext/setup/setup_wizard/operations/taxes_setup.py
+++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py
@@ -29,6 +29,7 @@
try:
if accounts:
make_sales_and_purchase_tax_templates(accounts, template_name)
+ make_item_tax_templates(accounts, template_name)
except frappe.NameError:
if frappe.message_log: frappe.message_log.pop()
except RootNotEditable:
@@ -84,6 +85,27 @@
doc = frappe.get_doc(purchase_tax_template)
doc.insert(ignore_permissions=True)
+def make_item_tax_templates(accounts, template_name=None):
+ if not template_name:
+ template_name = accounts[0].name
+
+ item_tax_template = {
+ "doctype": "Item Tax Template",
+ "title": template_name,
+ "company": accounts[0].company,
+ 'taxes': []
+ }
+
+
+ for account in accounts:
+ item_tax_template['taxes'].append({
+ "tax_type": account.name,
+ "tax_rate": account.tax_rate
+ })
+
+ # Items
+ frappe.get_doc(copy.deepcopy(item_tax_template)).insert(ignore_permissions=True)
+
def get_tax_account_group(company):
tax_group = frappe.db.get_value("Account",
{"account_name": "Duties and Taxes", "is_group": 1, "company": company})
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index c8424f1..8fdda56 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -93,7 +93,7 @@
if create_new_batch:
if batch_number_series:
- self.batch_id = make_autoname(batch_number_series)
+ self.batch_id = make_autoname(batch_number_series, doc=self)
elif batch_uses_naming_series():
self.batch_id = self.get_name_from_naming_series()
else:
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index d721014..70687bda 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -324,10 +324,12 @@
else:
loss_account = self.get_company_default("default_expense_account")
+ cost_center = d.cost_center or frappe.get_cached_value("Company", self.company, "cost_center")
+
gl_entries.append(self.get_gl_dict({
"account": loss_account,
"against": warehouse_account[d.warehouse]["account"],
- "cost_center": d.cost_center,
+ "cost_center": cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"debit": divisional_loss,
"project": d.project