Reposting patch and earned leave rounding (#24783)
* fix: rounding of earned leave is optional (#24782) * fix: reposting patch fixes (#24775)
This commit is contained in:
parent
0e89d71d34
commit
d96be3f9f1
@ -18,7 +18,6 @@ class ValueMultiplierError(frappe.ValidationError): pass
|
|||||||
class LeaveAllocation(Document):
|
class LeaveAllocation(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_period()
|
self.validate_period()
|
||||||
self.validate_new_leaves_allocated_value()
|
|
||||||
self.validate_allocation_overlap()
|
self.validate_allocation_overlap()
|
||||||
self.validate_back_dated_allocation()
|
self.validate_back_dated_allocation()
|
||||||
self.set_total_leaves_allocated()
|
self.set_total_leaves_allocated()
|
||||||
@ -72,11 +71,6 @@ class LeaveAllocation(Document):
|
|||||||
if frappe.db.get_value("Leave Type", self.leave_type, "is_lwp"):
|
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))
|
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):
|
def validate_allocation_overlap(self):
|
||||||
leave_allocation = frappe.db.sql("""
|
leave_allocation = frappe.db.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -106,12 +106,14 @@
|
|||||||
"fieldname": "leaves_allocated",
|
"fieldname": "leaves_allocated",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"label": "Leaves Allocated"
|
"label": "Leaves Allocated",
|
||||||
|
"no_copy": 1,
|
||||||
|
"print_hide": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-12-31 16:43:30.695206",
|
"modified": "2021-03-01 17:54:01.014509",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Leave Policy Assignment",
|
"name": "Leave Policy Assignment",
|
||||||
|
@ -6,7 +6,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe import _, bold
|
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
|
from math import ceil
|
||||||
import json
|
import json
|
||||||
from six import string_types
|
from six import string_types
|
||||||
@ -84,17 +84,52 @@ class LeavePolicyAssignment(Document):
|
|||||||
return allocation.name, new_leaves_allocated
|
return allocation.name, new_leaves_allocated
|
||||||
|
|
||||||
def get_new_leaves(self, leave_type, new_leaves_allocated, leave_type_details, date_of_joining):
|
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
|
# 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))
|
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)
|
new_leaves_allocated = ceil(new_leaves_allocated * remaining_period)
|
||||||
|
|
||||||
# Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0
|
return flt(new_leaves_allocated, precision)
|
||||||
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
|
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
|
return new_leaves_allocated
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def grant_leave_for_multiple_employees(leave_policy_assignments):
|
def grant_leave_for_multiple_employees(leave_policy_assignments):
|
||||||
leave_policy_assignments = json.loads(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():
|
def get_leave_type_details():
|
||||||
leave_type_details = frappe._dict()
|
leave_type_details = frappe._dict()
|
||||||
leave_types = frappe.get_all("Leave Type",
|
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:
|
for d in leave_types:
|
||||||
leave_type_details.setdefault(d.name, d)
|
leave_type_details.setdefault(d.name, d)
|
||||||
return leave_type_details
|
return leave_type_details
|
||||||
|
@ -172,7 +172,7 @@
|
|||||||
"fieldname": "rounding",
|
"fieldname": "rounding",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Rounding",
|
"label": "Rounding",
|
||||||
"options": "0.5\n1.0"
|
"options": "\n0.25\n0.5\n1.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "is_carry_forward",
|
"depends_on": "is_carry_forward",
|
||||||
@ -197,6 +197,7 @@
|
|||||||
"label": "Based On Date Of Joining"
|
"label": "Based On Date Of Joining"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "0",
|
||||||
"depends_on": "eval:doc.is_lwp == 0",
|
"depends_on": "eval:doc.is_lwp == 0",
|
||||||
"fieldname": "is_ppl",
|
"fieldname": "is_ppl",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
@ -213,7 +214,7 @@
|
|||||||
"icon": "fa fa-flag",
|
"icon": "fa fa-flag",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-15 15:49:47.555105",
|
"modified": "2021-03-02 11:22:33.776320",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Leave Type",
|
"name": "Leave Type",
|
||||||
|
@ -316,13 +316,7 @@ def allocate_earned_leaves():
|
|||||||
update_previous_leave_allocation(allocation, annual_allocation, e_leave_type)
|
update_previous_leave_allocation(allocation, annual_allocation, e_leave_type)
|
||||||
|
|
||||||
def 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}
|
earned_leaves = get_monthly_earned_leave(annual_allocation, e_leave_type.earned_leave_frequency, e_leave_type.rounding)
|
||||||
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)
|
|
||||||
|
|
||||||
allocation = frappe.get_doc('Leave Allocation', allocation.name)
|
allocation = frappe.get_doc('Leave Allocation', allocation.name)
|
||||||
new_allocation = flt(allocation.total_leaves_allocated) + flt(earned_leaves)
|
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()
|
today_date = today()
|
||||||
create_additional_leave_ledger_entry(allocation, earned_leaves, today_date)
|
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):
|
def get_leave_allocations(date, leave_type):
|
||||||
return frappe.db.sql("""select name, employee, from_date, to_date, leave_policy_assignment, leave_policy
|
return frappe.db.sql("""select name, employee, from_date, to_date, leave_policy_assignment, leave_policy
|
||||||
|
@ -1,13 +1,24 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
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.stock.stock_ledger import update_entries_after
|
||||||
from erpnext.accounts.utils import update_gl_entries_after
|
from erpnext.accounts.utils import update_gl_entries_after
|
||||||
|
|
||||||
def execute():
|
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()
|
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('''
|
data = frappe.db.sql('''
|
||||||
SELECT
|
SELECT
|
||||||
@ -41,8 +52,6 @@ def execute():
|
|||||||
|
|
||||||
|
|
||||||
print("Reposting General Ledger Entries...")
|
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}):
|
for row in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
|
||||||
update_gl_entries_after(posting_date, posting_time, company=row.name)
|
update_gl_entries_after(posting_date, posting_time, company=row.name)
|
||||||
|
@ -324,10 +324,12 @@ class PurchaseReceipt(BuyingController):
|
|||||||
else:
|
else:
|
||||||
loss_account = self.get_company_default("default_expense_account")
|
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({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": loss_account,
|
"account": loss_account,
|
||||||
"against": warehouse_account[d.warehouse]["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"),
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
"debit": divisional_loss,
|
"debit": divisional_loss,
|
||||||
"project": d.project
|
"project": d.project
|
||||||
|
Loading…
x
Reference in New Issue
Block a user