diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index d3e8a4474d..b361c0c345 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -695,6 +695,7 @@ frappe.ui.form.on('Sales Invoice', { refresh_field(['timesheets']) } }) + frm.refresh(); }, onload: function(frm) { @@ -810,6 +811,65 @@ frappe.ui.form.on('Sales Invoice', { }, 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 38b228477f..e01cb6e151 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -617,6 +617,7 @@ def get_partywise_advanced_payment_amount(party_type, posting_date = None, futur 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 5e3822e2da..69d605d063 100755 --- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py +++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py @@ -18,7 +18,6 @@ class ValueMultiplierError(frappe.ValidationError): pass 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 @@ class LeaveAllocation(Document): 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 a0327bdaa0..3373350e73 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 a5068bc26d..4064c56e44 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 @@ from __future__ import unicode_literals 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 @@ class LeavePolicyAssignment(Document): 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 automatically_allocate_leaves_based_on_leave_policy(): 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 a2092919f8..fc577ef1d3 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 a10381fac1..4c8a8c92c1 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 13d0074660..358329748e 100644 --- a/erpnext/hr/page/team_updates/team_updates.js +++ b/erpnext/hr/page/team_updates/team_updates.js @@ -36,7 +36,7 @@ frappe.team_updates = { 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 @@ frappe.team_updates = { } 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 e2aa7a4e72..d57ef5955d 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -316,13 +316,7 @@ def allocate_earned_leaves(): 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 @@ def update_previous_leave_allocation(allocation, annual_allocation, e_leave_type 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 3200363e01..d968e1fb76 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 @@ def execute(): 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 c47caa1227..680e518ca0 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 9f9691b59d..6688368262 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 60aff02b38..d9aadbf3aa 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_application.employee_benefit_appli 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 @@ class SalarySlip(TransactionBase): 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 @@ class SalarySlip(TransactionBase): #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 @@ class SalarySlip(TransactionBase): 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 0000000000..e69de29bb2 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 0000000000..7ac453b3c3 --- /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 0000000000..7a92bf18f7 --- /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 ea81b3eb64..ed02f79c2d 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -204,14 +204,16 @@ class Timesheet(Document): 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 bfeb96bcaf..8dfe2d6859 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 36033d9dae..c041d269a7 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -140,7 +140,7 @@ frappe.ui.form.on("Company", { 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 e66fa76f93..c3c1593c04 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -29,6 +29,7 @@ def make_tax_account_and_template(company, account_name, tax_rate, template_name 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 @@ def make_sales_and_purchase_tax_templates(accounts, template_name=None): 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 c8424f13e1..8fdda565d2 100644 --- a/erpnext/stock/doctype/batch/batch.py +++ b/erpnext/stock/doctype/batch/batch.py @@ -93,7 +93,7 @@ class Batch(Document): 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 d72101412e..70687bdac2 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -324,10 +324,12 @@ class PurchaseReceipt(BuyingController): 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