Merge branch 'develop' into iff-invoicing
This commit is contained in:
commit
d5971d3c59
@ -135,7 +135,7 @@ var create_import_button = function(frm) {
|
|||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if(!r.exc) {
|
if(!r.exc) {
|
||||||
clearInterval(frm.page["interval"]);
|
clearInterval(frm.page["interval"]);
|
||||||
frm.page.set_indicator(__('Import Successfull'), 'blue');
|
frm.page.set_indicator(__('Import Successful'), 'blue');
|
||||||
create_reset_button(frm);
|
create_reset_button(frm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import frappe, erpnext
|
|||||||
from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency
|
from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import (flt, getdate, get_first_day, add_months, add_days, formatdate, cstr)
|
from frappe.utils import (flt, getdate, get_first_day, add_months, add_days, formatdate, cstr, cint)
|
||||||
|
|
||||||
from six import itervalues
|
from six import itervalues
|
||||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children
|
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children
|
||||||
@ -46,7 +46,7 @@ def get_period_list(from_fiscal_year, to_fiscal_year, period_start_date, period_
|
|||||||
start_date = year_start_date
|
start_date = year_start_date
|
||||||
months = get_months(year_start_date, year_end_date)
|
months = get_months(year_start_date, year_end_date)
|
||||||
|
|
||||||
for i in range(math.ceil(months / months_to_add)):
|
for i in range(cint(math.ceil(months / months_to_add))):
|
||||||
period = frappe._dict({
|
period = frappe._dict({
|
||||||
"from_date": start_date
|
"from_date": start_date
|
||||||
})
|
})
|
||||||
|
@ -497,24 +497,18 @@ def warehouse_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
conditions, bin_conditions = [], []
|
conditions, bin_conditions = [], []
|
||||||
filter_dict = get_doctype_wise_filters(filters)
|
filter_dict = get_doctype_wise_filters(filters)
|
||||||
|
|
||||||
sub_query = """ select round(`tabBin`.actual_qty, 2) from `tabBin`
|
|
||||||
where `tabBin`.warehouse = `tabWarehouse`.name
|
|
||||||
{bin_conditions} """.format(
|
|
||||||
bin_conditions=get_filters_cond(doctype, filter_dict.get("Bin"),
|
|
||||||
bin_conditions, ignore_permissions=True))
|
|
||||||
|
|
||||||
query = """select `tabWarehouse`.name,
|
query = """select `tabWarehouse`.name,
|
||||||
CONCAT_WS(" : ", "Actual Qty", ifnull( ({sub_query}), 0) ) as actual_qty
|
CONCAT_WS(" : ", "Actual Qty", ifnull(round(`tabBin`.actual_qty, 2), 0 )) actual_qty
|
||||||
from `tabWarehouse`
|
from `tabWarehouse` left join `tabBin`
|
||||||
|
on `tabBin`.warehouse = `tabWarehouse`.name {bin_conditions}
|
||||||
where
|
where
|
||||||
`tabWarehouse`.`{key}` like {txt}
|
`tabWarehouse`.`{key}` like {txt}
|
||||||
{fcond} {mcond}
|
{fcond} {mcond}
|
||||||
order by
|
order by ifnull(`tabBin`.actual_qty, 0) desc
|
||||||
`tabWarehouse`.name desc
|
|
||||||
limit
|
limit
|
||||||
{start}, {page_len}
|
{start}, {page_len}
|
||||||
""".format(
|
""".format(
|
||||||
sub_query=sub_query,
|
bin_conditions=get_filters_cond(doctype, filter_dict.get("Bin"),bin_conditions, ignore_permissions=True),
|
||||||
key=searchfield,
|
key=searchfield,
|
||||||
fcond=get_filters_cond(doctype, filter_dict.get("Warehouse"), conditions),
|
fcond=get_filters_cond(doctype, filter_dict.get("Warehouse"), conditions),
|
||||||
mcond=get_match_cond(doctype),
|
mcond=get_match_cond(doctype),
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
"payroll_cost_center",
|
"payroll_cost_center",
|
||||||
"column_break_9",
|
"column_break_9",
|
||||||
"leave_block_list",
|
"leave_block_list",
|
||||||
"leave_section",
|
"approvers",
|
||||||
"leave_approvers",
|
"leave_approvers",
|
||||||
"expense_section",
|
|
||||||
"expense_approvers",
|
"expense_approvers",
|
||||||
|
"shift_request_approver",
|
||||||
"lft",
|
"lft",
|
||||||
"rgt",
|
"rgt",
|
||||||
"old_parent"
|
"old_parent"
|
||||||
@ -33,14 +33,18 @@
|
|||||||
"label": "Department",
|
"label": "Department",
|
||||||
"oldfieldname": "department_name",
|
"oldfieldname": "department_name",
|
||||||
"oldfieldtype": "Data",
|
"oldfieldtype": "Data",
|
||||||
"reqd": 1
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "parent_department",
|
"fieldname": "parent_department",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Parent Department",
|
"label": "Parent Department",
|
||||||
"options": "Department"
|
"options": "Department",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
@ -48,7 +52,9 @@
|
|||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Company",
|
"label": "Company",
|
||||||
"options": "Company",
|
"options": "Company",
|
||||||
"reqd": 1
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"bold": 1,
|
"bold": 1,
|
||||||
@ -56,17 +62,23 @@
|
|||||||
"fieldname": "is_group",
|
"fieldname": "is_group",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Is Group"
|
"label": "Is Group",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "disabled",
|
"fieldname": "disabled",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Disabled"
|
"label": "Disabled",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "section_break_4",
|
"fieldname": "section_break_4",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Days for which Holidays are blocked for this department.",
|
"description": "Days for which Holidays are blocked for this department.",
|
||||||
@ -74,31 +86,25 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Leave Block List",
|
"label": "Leave Block List",
|
||||||
"options": "Leave Block List"
|
"options": "Leave Block List",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "leave_section",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"label": "Leave Approvers"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "The first Leave Approver in the list will be set as the default Leave Approver.",
|
|
||||||
"fieldname": "leave_approvers",
|
"fieldname": "leave_approvers",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Leave Approver",
|
"label": "Leave Approver",
|
||||||
"options": "Department Approver"
|
"options": "Department Approver",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "expense_section",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"label": "Expense Approvers"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "The first Expense Approver in the list will be set as the default Expense Approver.",
|
|
||||||
"fieldname": "expense_approvers",
|
"fieldname": "expense_approvers",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Expense Approver",
|
"label": "Expense Approver",
|
||||||
"options": "Department Approver"
|
"options": "Department Approver",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "lft",
|
"fieldname": "lft",
|
||||||
@ -106,7 +112,9 @@
|
|||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"label": "lft",
|
"label": "lft",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "rgt",
|
"fieldname": "rgt",
|
||||||
@ -114,7 +122,9 @@
|
|||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"label": "rgt",
|
"label": "rgt",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "old_parent",
|
"fieldname": "old_parent",
|
||||||
@ -122,28 +132,52 @@
|
|||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"ignore_user_permissions": 1,
|
"ignore_user_permissions": 1,
|
||||||
"label": "Old Parent",
|
"label": "Old Parent",
|
||||||
"print_hide": 1
|
"print_hide": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_3",
|
"fieldname": "column_break_3",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "payroll_cost_center",
|
"fieldname": "payroll_cost_center",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Payroll Cost Center",
|
"label": "Payroll Cost Center",
|
||||||
"options": "Cost Center"
|
"options": "Cost Center",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_9",
|
"fieldname": "column_break_9",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "The first Approver in the list will be set as the default Approver.",
|
||||||
|
"fieldname": "approvers",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Approvers",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "shift_request_approver",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"label": "Shift Request Approver",
|
||||||
|
"options": "Department Approver",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-sitemap",
|
"icon": "fa fa-sitemap",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"is_tree": 1,
|
"is_tree": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-05-05 18:49:28.503931",
|
"modified": "2020-06-23 15:42:00.563272",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Department",
|
"name": "Department",
|
||||||
|
@ -15,12 +15,12 @@ class DepartmentApprover(Document):
|
|||||||
def get_approvers(doctype, txt, searchfield, start, page_len, filters):
|
def get_approvers(doctype, txt, searchfield, start, page_len, filters):
|
||||||
|
|
||||||
if not filters.get("employee"):
|
if not filters.get("employee"):
|
||||||
frappe.throw(_("Please select Employee Record first."))
|
frappe.throw(_("Please select Employee first."))
|
||||||
|
|
||||||
approvers = []
|
approvers = []
|
||||||
department_details = {}
|
department_details = {}
|
||||||
department_list = []
|
department_list = []
|
||||||
employee = frappe.get_value("Employee", filters.get("employee"), ["department", "leave_approver", "expense_approver"], as_dict=True)
|
employee = frappe.get_value("Employee", filters.get("employee"), ["department", "leave_approver", "expense_approver", "shift_request_approver"], as_dict=True)
|
||||||
|
|
||||||
employee_department = filters.get("department") or employee.department
|
employee_department = filters.get("department") or employee.department
|
||||||
if employee_department:
|
if employee_department:
|
||||||
@ -37,13 +37,18 @@ def get_approvers(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
if filters.get("doctype") == "Expense Claim" and employee.expense_approver:
|
if filters.get("doctype") == "Expense Claim" and employee.expense_approver:
|
||||||
approvers.append(frappe.db.get_value("User", employee.expense_approver, ['name', 'first_name', 'last_name']))
|
approvers.append(frappe.db.get_value("User", employee.expense_approver, ['name', 'first_name', 'last_name']))
|
||||||
|
|
||||||
|
if filters.get("doctype") == "Shift Request" and employee.shift_request_approver:
|
||||||
|
approvers.append(frappe.db.get_value("User", employee.shift_request_approver, ['name', 'first_name', 'last_name']))
|
||||||
|
|
||||||
if filters.get("doctype") == "Leave Application":
|
if filters.get("doctype") == "Leave Application":
|
||||||
parentfield = "leave_approvers"
|
parentfield = "leave_approvers"
|
||||||
field_name = "Leave Approver"
|
field_name = "Leave Approver"
|
||||||
else:
|
elif filters.get("doctype") == "Expense Claim":
|
||||||
parentfield = "expense_approvers"
|
parentfield = "expense_approvers"
|
||||||
field_name = "Expense Approver"
|
field_name = "Expense Approver"
|
||||||
|
elif filters.get("doctype") == "Shift Request":
|
||||||
|
parentfield = "shift_request_approver"
|
||||||
|
field_name = "Shift Request Approver"
|
||||||
if department_list:
|
if department_list:
|
||||||
for d in department_list:
|
for d in department_list:
|
||||||
approvers += frappe.db.sql("""select user.name, user.first_name, user.last_name from
|
approvers += frappe.db.sql("""select user.name, user.first_name, user.last_name from
|
||||||
|
@ -51,10 +51,14 @@
|
|||||||
"column_break_31",
|
"column_break_31",
|
||||||
"grade",
|
"grade",
|
||||||
"branch",
|
"branch",
|
||||||
|
"approvers_section",
|
||||||
|
"expense_approver",
|
||||||
|
"leave_approver",
|
||||||
|
"column_break_45",
|
||||||
|
"shift_request_approver",
|
||||||
"attendance_and_leave_details",
|
"attendance_and_leave_details",
|
||||||
"leave_policy",
|
"leave_policy",
|
||||||
"attendance_device_id",
|
"attendance_device_id",
|
||||||
"leave_approver",
|
|
||||||
"column_break_44",
|
"column_break_44",
|
||||||
"holiday_list",
|
"holiday_list",
|
||||||
"default_shift",
|
"default_shift",
|
||||||
@ -62,7 +66,6 @@
|
|||||||
"salary_mode",
|
"salary_mode",
|
||||||
"payroll_cost_center",
|
"payroll_cost_center",
|
||||||
"column_break_52",
|
"column_break_52",
|
||||||
"expense_approver",
|
|
||||||
"bank_name",
|
"bank_name",
|
||||||
"bank_ac_no",
|
"bank_ac_no",
|
||||||
"health_insurance_section",
|
"health_insurance_section",
|
||||||
@ -806,14 +809,37 @@
|
|||||||
"fieldname": "expense_approver",
|
"fieldname": "expense_approver",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Expense Approver",
|
"label": "Expense Approver",
|
||||||
"options": "User"
|
"options": "User",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "approvers_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Approvers",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_45",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "shift_request_approver",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Shift Request Approver",
|
||||||
|
"options": "User",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-user",
|
"icon": "fa fa-user",
|
||||||
"idx": 24,
|
"idx": 24,
|
||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-07-03 21:28:04.109189",
|
"modified": "2020-07-28 01:36:04.109189",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Employee",
|
"name": "Employee",
|
||||||
|
@ -10,9 +10,11 @@
|
|||||||
"employee",
|
"employee",
|
||||||
"employee_name",
|
"employee_name",
|
||||||
"shift_type",
|
"shift_type",
|
||||||
|
"status",
|
||||||
"column_break_3",
|
"column_break_3",
|
||||||
"company",
|
"company",
|
||||||
"date",
|
"start_date",
|
||||||
|
"end_date",
|
||||||
"shift_request",
|
"shift_request",
|
||||||
"department",
|
"department",
|
||||||
"amended_from"
|
"amended_from"
|
||||||
@ -59,12 +61,6 @@
|
|||||||
"options": "Company",
|
"options": "Company",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "date",
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"in_list_view": 1,
|
|
||||||
"label": "Date"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "shift_request",
|
"fieldname": "shift_request",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -80,11 +76,36 @@
|
|||||||
"options": "Shift Assignment",
|
"options": "Shift Assignment",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "start_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Start Date",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 1,
|
||||||
|
"fieldname": "end_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "End Date",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 1,
|
||||||
|
"default": "Active",
|
||||||
|
"fieldname": "status",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Status",
|
||||||
|
"options": "Active\nInactive",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2019-12-12 15:49:06.956901",
|
"modified": "2020-06-15 14:27:54.310773",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Shift Assignment",
|
"name": "Shift Assignment",
|
||||||
|
@ -11,38 +11,63 @@ from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
|||||||
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
|
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
|
||||||
from datetime import timedelta, datetime
|
from datetime import timedelta, datetime
|
||||||
|
|
||||||
class OverlapError(frappe.ValidationError): pass
|
|
||||||
|
|
||||||
class ShiftAssignment(Document):
|
class ShiftAssignment(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_overlapping_dates()
|
self.validate_overlapping_dates()
|
||||||
|
|
||||||
|
if self.end_date and self.end_date <= self.start_date:
|
||||||
|
frappe.throw(_("End Date must not be lesser than Start Date"))
|
||||||
|
|
||||||
def validate_overlapping_dates(self):
|
def validate_overlapping_dates(self):
|
||||||
if not self.name:
|
if not self.name:
|
||||||
self.name = "New Shift Assignment"
|
self.name = "New Shift Assignment"
|
||||||
|
|
||||||
d = frappe.db.sql("""
|
condition = """and (
|
||||||
select
|
end_date is null
|
||||||
name, shift_type, date
|
or
|
||||||
|
%(start_date)s between start_date and end_date
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.end_date:
|
||||||
|
condition += """ or
|
||||||
|
%(end_date)s between start_date and end_date
|
||||||
|
or
|
||||||
|
start_date between %(start_date)s and %(end_date)s
|
||||||
|
) """
|
||||||
|
else:
|
||||||
|
condition += """ ) """
|
||||||
|
|
||||||
|
assigned_shifts = frappe.db.sql("""
|
||||||
|
select name, shift_type, start_date ,end_date, docstatus, status
|
||||||
from `tabShift Assignment`
|
from `tabShift Assignment`
|
||||||
where employee = %(employee)s and docstatus < 2
|
where
|
||||||
and date = %(date)s
|
employee=%(employee)s and docstatus = 1
|
||||||
and name != %(name)s""", {
|
and name != %(name)s
|
||||||
|
and status = "Active"
|
||||||
|
{0}
|
||||||
|
""".format(condition), {
|
||||||
"employee": self.employee,
|
"employee": self.employee,
|
||||||
"shift_type": self.shift_type,
|
"shift_type": self.shift_type,
|
||||||
"date": self.date,
|
"start_date": self.start_date,
|
||||||
|
"end_date": self.end_date,
|
||||||
"name": self.name
|
"name": self.name
|
||||||
}, as_dict = 1)
|
}, as_dict = 1)
|
||||||
|
|
||||||
for date_overlap in d:
|
if len(assigned_shifts):
|
||||||
if date_overlap['name']:
|
self.throw_overlap_error(assigned_shifts[0])
|
||||||
self.throw_overlap_error(date_overlap)
|
|
||||||
|
|
||||||
def throw_overlap_error(self, d):
|
def throw_overlap_error(self, shift_details):
|
||||||
msg = _("Employee {0} has already applied for {1} on {2} : ").format(self.employee,
|
shift_details = frappe._dict(shift_details)
|
||||||
d['shift_type'], formatdate(d['date'])) \
|
if shift_details.docstatus == 1 and shift_details.status == "Active":
|
||||||
+ """ <b><a href="#Form/Shift Assignment/{0}">{0}</a></b>""".format(d["name"])
|
msg = _("Employee {0} already has Active Shift {1}: {2}").format(frappe.bold(self.employee), frappe.bold(self.shift_type), frappe.bold(shift_details.name))
|
||||||
frappe.throw(msg, OverlapError)
|
if shift_details.start_date:
|
||||||
|
msg += _(" from {0}").format(getdate(self.start_date).strftime("%d-%m-%Y"))
|
||||||
|
title = "Ongoing Shift"
|
||||||
|
if shift_details.end_date:
|
||||||
|
msg += _(" to {0}").format(getdate(self.end_date).strftime("%d-%m-%Y"))
|
||||||
|
title = "Active Shift"
|
||||||
|
if msg:
|
||||||
|
frappe.throw(msg, title=title)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_events(start, end, filters=None):
|
def get_events(start, end, filters=None):
|
||||||
@ -62,19 +87,22 @@ def get_events(start, end, filters=None):
|
|||||||
return events
|
return events
|
||||||
|
|
||||||
def add_assignments(events, start, end, conditions=None):
|
def add_assignments(events, start, end, conditions=None):
|
||||||
query = """select name, date, employee_name,
|
query = """select name, start_date, end_date, employee_name,
|
||||||
employee, docstatus
|
employee, docstatus
|
||||||
from `tabShift Assignment` where
|
from `tabShift Assignment` where
|
||||||
date <= %(date)s
|
start_date >= %(start_date)s
|
||||||
and docstatus < 2"""
|
or end_date <= %(end_date)s
|
||||||
|
or (%(start_date)s between start_date and end_date and %(end_date)s between start_date and end_date)
|
||||||
|
and docstatus = 1"""
|
||||||
if conditions:
|
if conditions:
|
||||||
query += conditions
|
query += conditions
|
||||||
|
|
||||||
for d in frappe.db.sql(query, {"date":start, "date":end}, as_dict=True):
|
for d in frappe.db.sql(query, {"start_date":start, "end_date":end}, as_dict=True):
|
||||||
e = {
|
e = {
|
||||||
"name": d.name,
|
"name": d.name,
|
||||||
"doctype": "Shift Assignment",
|
"doctype": "Shift Assignment",
|
||||||
"date": d.date,
|
"start_date": d.start_date,
|
||||||
|
"end_date": d.end_date if d.end_date else nowdate(),
|
||||||
"title": cstr(d.employee_name) + \
|
"title": cstr(d.employee_name) + \
|
||||||
cstr(d.shift_type),
|
cstr(d.shift_type),
|
||||||
"docstatus": d.docstatus
|
"docstatus": d.docstatus
|
||||||
@ -92,7 +120,16 @@ def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=Fals
|
|||||||
:param next_shift_direction: One of: None, 'forward', 'reverse'. Direction to look for next shift if shift not found on given date.
|
:param next_shift_direction: One of: None, 'forward', 'reverse'. Direction to look for next shift if shift not found on given date.
|
||||||
"""
|
"""
|
||||||
default_shift = frappe.db.get_value('Employee', employee, 'default_shift')
|
default_shift = frappe.db.get_value('Employee', employee, 'default_shift')
|
||||||
shift_type_name = frappe.db.get_value('Shift Assignment', {'employee':employee, 'date': for_date, 'docstatus': '1'}, 'shift_type')
|
shift_type_name = None
|
||||||
|
shift_assignment_details = frappe.db.get_value('Shift Assignment', {'employee':employee, 'start_date':('<=', for_date), 'docstatus': '1', 'status': "Active"}, ['shift_type', 'end_date'])
|
||||||
|
|
||||||
|
if shift_assignment_details:
|
||||||
|
shift_type_name = shift_assignment_details[0]
|
||||||
|
|
||||||
|
# if end_date present means that shift is over after end_date else it is a ongoing shift.
|
||||||
|
if shift_assignment_details[1] and for_date >= shift_assignment_details[1] :
|
||||||
|
shift_type_name = None
|
||||||
|
|
||||||
if not shift_type_name and consider_default_shift:
|
if not shift_type_name and consider_default_shift:
|
||||||
shift_type_name = default_shift
|
shift_type_name = default_shift
|
||||||
if shift_type_name:
|
if shift_type_name:
|
||||||
@ -117,11 +154,15 @@ def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=Fals
|
|||||||
direction = '<' if next_shift_direction == 'reverse' else '>'
|
direction = '<' if next_shift_direction == 'reverse' else '>'
|
||||||
sort_order = 'desc' if next_shift_direction == 'reverse' else 'asc'
|
sort_order = 'desc' if next_shift_direction == 'reverse' else 'asc'
|
||||||
dates = frappe.db.get_all('Shift Assignment',
|
dates = frappe.db.get_all('Shift Assignment',
|
||||||
'date',
|
['start_date', 'end_date'],
|
||||||
{'employee':employee, 'date':(direction, for_date), 'docstatus': '1'},
|
{'employee':employee, 'start_date':(direction, for_date), 'docstatus': '1', "status": "Active"},
|
||||||
as_list=True,
|
as_list=True,
|
||||||
limit=MAX_DAYS, order_by="date "+sort_order)
|
limit=MAX_DAYS, order_by="start_date "+sort_order)
|
||||||
|
|
||||||
|
if dates:
|
||||||
for date in dates:
|
for date in dates:
|
||||||
|
if date[1] and date[1] < for_date:
|
||||||
|
continue
|
||||||
shift_details = get_employee_shift(employee, date[0], consider_default_shift, None)
|
shift_details = get_employee_shift(employee, date[0], consider_default_shift, None)
|
||||||
if shift_details:
|
if shift_details:
|
||||||
shift_type_name = shift_details.shift_type.name
|
shift_type_name = shift_details.shift_type.name
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
frappe.views.calendar["Shift Assignment"] = {
|
frappe.views.calendar["Shift Assignment"] = {
|
||||||
field_map: {
|
field_map: {
|
||||||
"start": "date",
|
"start": "start_date",
|
||||||
"end": "date",
|
"end": "end_date",
|
||||||
"id": "name",
|
"id": "name",
|
||||||
"docstatus": 1
|
"docstatus": 1
|
||||||
},
|
},
|
||||||
|
@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
from frappe.utils import nowdate
|
from frappe.utils import nowdate, add_days
|
||||||
|
|
||||||
test_dependencies = ["Shift Type"]
|
test_dependencies = ["Shift Type"]
|
||||||
|
|
||||||
@ -20,8 +20,61 @@ class TestShiftAssignment(unittest.TestCase):
|
|||||||
"shift_type": "Day Shift",
|
"shift_type": "Day Shift",
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"employee": "_T-Employee-00001",
|
"employee": "_T-Employee-00001",
|
||||||
"date": nowdate()
|
"start_date": nowdate()
|
||||||
}).insert()
|
}).insert()
|
||||||
shift_assignment.submit()
|
shift_assignment.submit()
|
||||||
|
|
||||||
self.assertEqual(shift_assignment.docstatus, 1)
|
self.assertEqual(shift_assignment.docstatus, 1)
|
||||||
|
|
||||||
|
def test_overlapping_for_ongoing_shift(self):
|
||||||
|
# shift should be Ongoing if Only start_date is present and status = Active
|
||||||
|
|
||||||
|
shift_assignment_1 = frappe.get_doc({
|
||||||
|
"doctype": "Shift Assignment",
|
||||||
|
"shift_type": "Day Shift",
|
||||||
|
"company": "_Test Company",
|
||||||
|
"employee": "_T-Employee-00001",
|
||||||
|
"start_date": nowdate(),
|
||||||
|
"status": 'Active'
|
||||||
|
}).insert()
|
||||||
|
shift_assignment_1.submit()
|
||||||
|
|
||||||
|
self.assertEqual(shift_assignment_1.docstatus, 1)
|
||||||
|
|
||||||
|
shift_assignment = frappe.get_doc({
|
||||||
|
"doctype": "Shift Assignment",
|
||||||
|
"shift_type": "Day Shift",
|
||||||
|
"company": "_Test Company",
|
||||||
|
"employee": "_T-Employee-00001",
|
||||||
|
"start_date": add_days(nowdate(), 2)
|
||||||
|
})
|
||||||
|
|
||||||
|
self.assertRaises(frappe.ValidationError, shift_assignment.save)
|
||||||
|
|
||||||
|
def test_overlapping_for_fixed_period_shift(self):
|
||||||
|
# shift should is for Fixed period if Only start_date and end_date both are present and status = Active
|
||||||
|
|
||||||
|
shift_assignment_1 = frappe.get_doc({
|
||||||
|
"doctype": "Shift Assignment",
|
||||||
|
"shift_type": "Day Shift",
|
||||||
|
"company": "_Test Company",
|
||||||
|
"employee": "_T-Employee-00001",
|
||||||
|
"start_date": nowdate(),
|
||||||
|
"end_date": add_days(nowdate(), 30),
|
||||||
|
"status": 'Active'
|
||||||
|
}).insert()
|
||||||
|
shift_assignment_1.submit()
|
||||||
|
|
||||||
|
|
||||||
|
# it should not allowed within period of any shift.
|
||||||
|
shift_assignment_3 = frappe.get_doc({
|
||||||
|
"doctype": "Shift Assignment",
|
||||||
|
"shift_type": "Day Shift",
|
||||||
|
"company": "_Test Company",
|
||||||
|
"employee": "_T-Employee-00001",
|
||||||
|
"start_date":add_days(nowdate(), 10),
|
||||||
|
"end_date": add_days(nowdate(), 35),
|
||||||
|
"status": 'Active'
|
||||||
|
})
|
||||||
|
|
||||||
|
self.assertRaises(frappe.ValidationError, shift_assignment_3.save)
|
@ -2,7 +2,16 @@
|
|||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
|
|
||||||
frappe.ui.form.on('Shift Request', {
|
frappe.ui.form.on('Shift Request', {
|
||||||
refresh: function(frm) {
|
setup: function(frm) {
|
||||||
|
frm.set_query("approver", function() {
|
||||||
|
return {
|
||||||
|
query: "erpnext.hr.doctype.department_approver.department_approver.get_approvers",
|
||||||
|
filters: {
|
||||||
|
employee: frm.doc.employee,
|
||||||
|
doctype: frm.doc.doctype
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
frm.set_query("employee", erpnext.queries.employee);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,347 +1,123 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
|
||||||
"autoname": "HR-SHR-.YY.-.MM.-.#####",
|
"autoname": "HR-SHR-.YY.-.MM.-.#####",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2018-04-13 16:32:27.974273",
|
"creation": "2018-04-13 16:32:27.974273",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"shift_type",
|
||||||
|
"employee",
|
||||||
|
"employee_name",
|
||||||
|
"department",
|
||||||
|
"status",
|
||||||
|
"column_break_4",
|
||||||
|
"company",
|
||||||
|
"approver",
|
||||||
|
"from_date",
|
||||||
|
"to_date",
|
||||||
|
"amended_from"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "shift_type",
|
"fieldname": "shift_type",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Shift Type",
|
"label": "Shift Type",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Shift Type",
|
"options": "Shift Type",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"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": "employee",
|
"fieldname": "employee",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Employee",
|
"label": "Employee",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Employee",
|
"options": "Employee",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"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.employee_name",
|
"fetch_from": "employee.employee_name",
|
||||||
"fieldname": "employee_name",
|
"fieldname": "employee_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"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": "Employee Name",
|
"label": "Employee Name",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"no_copy": 0,
|
|
||||||
"options": "",
|
|
||||||
"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_from": "employee.department",
|
"fetch_from": "employee.department",
|
||||||
"fieldname": "department",
|
"fieldname": "department",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Department",
|
"label": "Department",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Department",
|
"options": "Department",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"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,
|
|
||||||
"fieldname": "column_break_4",
|
"fieldname": "column_break_4",
|
||||||
"fieldtype": "Column Break",
|
"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": "company",
|
"fieldname": "company",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Company",
|
"label": "Company",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company",
|
"options": "Company",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"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": "from_date",
|
"fieldname": "from_date",
|
||||||
"fieldtype": "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": "From Date",
|
"label": "From Date",
|
||||||
"length": 0,
|
"reqd": 1
|
||||||
"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": "to_date",
|
"fieldname": "to_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
"label": "To Date"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "To 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": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "amended_from",
|
"fieldname": "amended_from",
|
||||||
"fieldtype": "Link",
|
"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": "Amended From",
|
"label": "Amended From",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Shift Request",
|
"options": "Shift Request",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"read_only": 1
|
||||||
"read_only": 1,
|
},
|
||||||
"remember_last_selected_value": 0,
|
{
|
||||||
"report_hide": 0,
|
"default": "Draft",
|
||||||
"reqd": 0,
|
"fieldname": "status",
|
||||||
"search_index": 0,
|
"fieldtype": "Select",
|
||||||
"set_only_once": 0,
|
"label": "Status",
|
||||||
"translatable": 0,
|
"options": "Draft\nApproved\nRejected",
|
||||||
"unique": 0
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "employee.shift_request_approver",
|
||||||
|
"fetch_if_empty": 1,
|
||||||
|
"fieldname": "approver",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Approver",
|
||||||
|
"options": "User",
|
||||||
|
"reqd": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"links": [],
|
||||||
"istable": 0,
|
"modified": "2020-08-10 17:59:31.550558",
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-08-21 16:15:36.577448",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Shift Request",
|
"name": "Shift Request",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 0,
|
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Employee",
|
"role": "Employee",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -351,46 +127,29 @@
|
|||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "HR Manager",
|
"role": "HR Manager",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 0,
|
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "HR User",
|
"role": "HR User",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"title_field": "employee_name",
|
"title_field": "employee_name",
|
||||||
"track_changes": 1,
|
"track_changes": 1
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
@ -14,19 +14,26 @@ class ShiftRequest(Document):
|
|||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_dates()
|
self.validate_dates()
|
||||||
self.validate_shift_request_overlap_dates()
|
self.validate_shift_request_overlap_dates()
|
||||||
|
self.validate_approver()
|
||||||
|
self.validate_default_shift()
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
date_list = self.get_working_days(self.from_date, self.to_date)
|
if self.status not in ["Approved", "Rejected"]:
|
||||||
for date in date_list:
|
frappe.throw(_("Only Shift Request with status 'Approved' and 'Rejected' can be submitted"))
|
||||||
|
if self.status == "Approved":
|
||||||
assignment_doc = frappe.new_doc("Shift Assignment")
|
assignment_doc = frappe.new_doc("Shift Assignment")
|
||||||
assignment_doc.company = self.company
|
assignment_doc.company = self.company
|
||||||
assignment_doc.shift_type = self.shift_type
|
assignment_doc.shift_type = self.shift_type
|
||||||
assignment_doc.employee = self.employee
|
assignment_doc.employee = self.employee
|
||||||
assignment_doc.date = date
|
assignment_doc.start_date = self.from_date
|
||||||
|
if self.to_date:
|
||||||
|
assignment_doc.end_date = self.to_date
|
||||||
assignment_doc.shift_request = self.name
|
assignment_doc.shift_request = self.name
|
||||||
assignment_doc.insert()
|
assignment_doc.insert()
|
||||||
assignment_doc.submit()
|
assignment_doc.submit()
|
||||||
|
|
||||||
|
frappe.msgprint(_("Shift Assignment: {0} created for Employee: {1}").format(frappe.bold(assignment_doc.name), frappe.bold(self.employee)))
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
shift_assignment_list = frappe.get_list("Shift Assignment", {'employee': self.employee, 'shift_request': self.name})
|
shift_assignment_list = frappe.get_list("Shift Assignment", {'employee': self.employee, 'shift_request': self.name})
|
||||||
if shift_assignment_list:
|
if shift_assignment_list:
|
||||||
@ -34,6 +41,19 @@ class ShiftRequest(Document):
|
|||||||
shift_assignment_doc = frappe.get_doc("Shift Assignment", shift['name'])
|
shift_assignment_doc = frappe.get_doc("Shift Assignment", shift['name'])
|
||||||
shift_assignment_doc.cancel()
|
shift_assignment_doc.cancel()
|
||||||
|
|
||||||
|
def validate_default_shift(self):
|
||||||
|
default_shift = frappe.get_value("Employee", self.employee, "default_shift")
|
||||||
|
if self.shift_type == default_shift:
|
||||||
|
frappe.throw(_("You can not request for your Default Shift: {0}").format(frappe.bold(self.shift_type)))
|
||||||
|
|
||||||
|
def validate_approver(self):
|
||||||
|
department = frappe.get_value("Employee", self.employee, "department")
|
||||||
|
shift_approver = frappe.get_value("Employee", self.employee, "shift_request_approver")
|
||||||
|
approvers = frappe.db.sql("""select approver from `tabDepartment Approver` where parent= %s and parentfield = 'shift_request_approver'""", (department))
|
||||||
|
approvers = [approver[0] for approver in approvers]
|
||||||
|
approvers.append(shift_approver)
|
||||||
|
if self.approver not in approvers:
|
||||||
|
frappe.throw(_("Only Approvers can Approve this Request."))
|
||||||
|
|
||||||
def validate_dates(self):
|
def validate_dates(self):
|
||||||
if self.from_date and self.to_date and (getdate(self.to_date) < getdate(self.from_date)):
|
if self.from_date and self.to_date and (getdate(self.to_date) < getdate(self.from_date)):
|
||||||
@ -69,27 +89,3 @@ class ShiftRequest(Document):
|
|||||||
d['shift_type'], formatdate(d['from_date']), formatdate(d['to_date'])) \
|
d['shift_type'], formatdate(d['from_date']), formatdate(d['to_date'])) \
|
||||||
+ """ <b><a href="#Form/Shift Request/{0}">{0}</a></b>""".format(d["name"])
|
+ """ <b><a href="#Form/Shift Request/{0}">{0}</a></b>""".format(d["name"])
|
||||||
frappe.throw(msg, OverlapError)
|
frappe.throw(msg, OverlapError)
|
||||||
|
|
||||||
def get_working_days(self, start_date, end_date):
|
|
||||||
start_date, end_date = getdate(start_date), getdate(end_date)
|
|
||||||
|
|
||||||
from datetime import timedelta
|
|
||||||
|
|
||||||
date_list = []
|
|
||||||
employee_holiday_list = []
|
|
||||||
|
|
||||||
employee_holidays = frappe.db.sql("""select holiday_date from `tabHoliday`
|
|
||||||
where parent in (select holiday_list from `tabEmployee`
|
|
||||||
where name = %s)""",self.employee,as_dict=1)
|
|
||||||
|
|
||||||
for d in employee_holidays:
|
|
||||||
employee_holiday_list.append(d.holiday_date)
|
|
||||||
|
|
||||||
reference_date = start_date
|
|
||||||
|
|
||||||
while reference_date <= end_date:
|
|
||||||
if reference_date not in employee_holiday_list:
|
|
||||||
date_list.append(reference_date)
|
|
||||||
reference_date += timedelta(days=1)
|
|
||||||
|
|
||||||
return date_list
|
|
@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
from frappe.utils import nowdate
|
from frappe.utils import nowdate, add_days
|
||||||
|
|
||||||
class TestShiftRequest(unittest.TestCase):
|
class TestShiftRequest(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -13,14 +13,20 @@ class TestShiftRequest(unittest.TestCase):
|
|||||||
frappe.db.sql("delete from `tab{doctype}`".format(doctype=doctype))
|
frappe.db.sql("delete from `tab{doctype}`".format(doctype=doctype))
|
||||||
|
|
||||||
def test_make_shift_request(self):
|
def test_make_shift_request(self):
|
||||||
|
department = frappe.get_value("Employee", "_T-Employee-00001", 'department')
|
||||||
|
set_shift_approver(department)
|
||||||
|
approver = frappe.db.sql("""select approver from `tabDepartment Approver` where parent= %s and parentfield = 'shift_request_approver'""", (department))[0][0]
|
||||||
|
|
||||||
shift_request = frappe.get_doc({
|
shift_request = frappe.get_doc({
|
||||||
"doctype": "Shift Request",
|
"doctype": "Shift Request",
|
||||||
"shift_type": "Day Shift",
|
"shift_type": "Day Shift",
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"employee": "_T-Employee-00001",
|
"employee": "_T-Employee-00001",
|
||||||
"employee_name": "_Test Employee",
|
"employee_name": "_Test Employee",
|
||||||
"start_date": nowdate(),
|
"from_date": nowdate(),
|
||||||
"end_date": nowdate()
|
"to_date": add_days(nowdate(), 10),
|
||||||
|
"approver": approver,
|
||||||
|
"status": "Approved"
|
||||||
})
|
})
|
||||||
shift_request.insert()
|
shift_request.insert()
|
||||||
shift_request.submit()
|
shift_request.submit()
|
||||||
@ -35,3 +41,9 @@ class TestShiftRequest(unittest.TestCase):
|
|||||||
shift_request.cancel()
|
shift_request.cancel()
|
||||||
shift_assignment_doc = frappe.get_doc("Shift Assignment", {"shift_request": d.get('shift_request')})
|
shift_assignment_doc = frappe.get_doc("Shift Assignment", {"shift_request": d.get('shift_request')})
|
||||||
self.assertEqual(shift_assignment_doc.docstatus, 2)
|
self.assertEqual(shift_assignment_doc.docstatus, 2)
|
||||||
|
|
||||||
|
def set_shift_approver(department):
|
||||||
|
department_doc = frappe.get_doc("Department", department)
|
||||||
|
department_doc.append('shift_request_approver',{'approver': "test1@example.com"})
|
||||||
|
department_doc.save()
|
||||||
|
department_doc.reload()
|
@ -4,7 +4,7 @@
|
|||||||
frappe.ui.form.on('Shift Type', {
|
frappe.ui.form.on('Shift Type', {
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
frm.add_custom_button(
|
frm.add_custom_button(
|
||||||
'Mark Auto Attendance',
|
'Mark Attendance',
|
||||||
() => frm.call({
|
() => frm.call({
|
||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
method: 'process_auto_attendance',
|
method: 'process_auto_attendance',
|
||||||
|
@ -79,9 +79,10 @@ class ShiftType(Document):
|
|||||||
mark_attendance(employee, date, 'Absent', self.name)
|
mark_attendance(employee, date, 'Absent', self.name)
|
||||||
|
|
||||||
def get_assigned_employee(self, from_date=None, consider_default_shift=False):
|
def get_assigned_employee(self, from_date=None, consider_default_shift=False):
|
||||||
filters = {'date':('>=', from_date), 'shift_type': self.name, 'docstatus': '1'}
|
filters = {'start_date':('>', from_date), 'shift_type': self.name, 'docstatus': '1'}
|
||||||
if not from_date:
|
if not from_date:
|
||||||
del filters['date']
|
del filters["start_date"]
|
||||||
|
|
||||||
assigned_employees = frappe.get_all('Shift Assignment', 'employee', filters, as_list=True)
|
assigned_employees = frappe.get_all('Shift Assignment', 'employee', filters, as_list=True)
|
||||||
assigned_employees = [x[0] for x in assigned_employees]
|
assigned_employees = [x[0] for x in assigned_employees]
|
||||||
|
|
||||||
|
@ -722,3 +722,4 @@ erpnext.patches.v13_0.stock_entry_enhancements
|
|||||||
erpnext.patches.v12_0.update_state_code_for_daman_and_diu
|
erpnext.patches.v12_0.update_state_code_for_daman_and_diu
|
||||||
erpnext.patches.v12_0.rename_lost_reason_detail
|
erpnext.patches.v12_0.rename_lost_reason_detail
|
||||||
erpnext.patches.v13_0.drop_razorpay_payload_column
|
erpnext.patches.v13_0.drop_razorpay_payload_column
|
||||||
|
erpnext.patches.v13_0.update_start_end_date_for_old_shift_assignment
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
# Copyright (c) 2019, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doc('hr', 'doctype', 'shift_assignment')
|
||||||
|
frappe.db.sql("update `tabShift Assignment` set end_date=date, start_date=date where date IS NOT NULL and start_date IS NULL and end_date IS NULL;")
|
@ -1,6 +1,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, re, json
|
import frappe, re, json
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
import erpnext
|
||||||
from frappe.utils import cstr, flt, date_diff, nowdate, round_based_on_smallest_currency_fraction, money_in_words
|
from frappe.utils import cstr, flt, date_diff, nowdate, round_based_on_smallest_currency_fraction, money_in_words
|
||||||
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
|
||||||
@ -673,25 +674,34 @@ def update_grand_total_for_rcm(doc, method):
|
|||||||
if country != 'India':
|
if country != 'India':
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if not doc.total_taxes_and_charges:
|
||||||
|
return
|
||||||
|
|
||||||
if doc.reverse_charge == 'Y':
|
if doc.reverse_charge == 'Y':
|
||||||
gst_accounts = get_gst_accounts(doc.company)
|
gst_accounts = get_gst_accounts(doc.company)
|
||||||
gst_account_list = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
|
gst_account_list = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
|
||||||
+ gst_accounts.get('igst_account')
|
+ gst_accounts.get('igst_account')
|
||||||
|
|
||||||
|
base_gst_tax = 0
|
||||||
gst_tax = 0
|
gst_tax = 0
|
||||||
|
|
||||||
for tax in doc.get('taxes'):
|
for tax in doc.get('taxes'):
|
||||||
if tax.category not in ("Total", "Valuation and Total"):
|
if tax.category not in ("Total", "Valuation and Total"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in gst_account_list:
|
if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in gst_account_list:
|
||||||
gst_tax += tax.base_tax_amount_after_discount_amount
|
base_gst_tax += tax.base_tax_amount_after_discount_amount
|
||||||
|
gst_tax += tax.tax_amount_after_discount_amount
|
||||||
|
|
||||||
doc.taxes_and_charges_added -= gst_tax
|
doc.taxes_and_charges_added -= gst_tax
|
||||||
doc.total_taxes_and_charges -= gst_tax
|
doc.total_taxes_and_charges -= gst_tax
|
||||||
|
doc.base_taxes_and_charges_added -= base_gst_tax
|
||||||
|
doc.base_total_taxes_and_charges -= base_gst_tax
|
||||||
|
|
||||||
update_totals(gst_tax, doc)
|
update_totals(gst_tax, base_gst_tax, doc)
|
||||||
|
|
||||||
def update_totals(gst_tax, doc):
|
def update_totals(gst_tax, base_gst_tax, doc):
|
||||||
|
doc.base_grand_total -= base_gst_tax
|
||||||
doc.grand_total -= gst_tax
|
doc.grand_total -= gst_tax
|
||||||
|
|
||||||
if doc.meta.get_field("rounded_total"):
|
if doc.meta.get_field("rounded_total"):
|
||||||
@ -707,13 +717,17 @@ def update_totals(gst_tax, doc):
|
|||||||
doc.outstanding_amount = doc.rounded_total or doc.grand_total
|
doc.outstanding_amount = doc.rounded_total or doc.grand_total
|
||||||
|
|
||||||
doc.in_words = money_in_words(doc.grand_total, doc.currency)
|
doc.in_words = money_in_words(doc.grand_total, doc.currency)
|
||||||
|
doc.base_in_words = money_in_words(doc.base_grand_total, erpnext.get_company_currency(doc.company))
|
||||||
doc.set_payment_schedule()
|
doc.set_payment_schedule()
|
||||||
|
|
||||||
def make_regional_gl_entries(gl_entries, doc):
|
def make_regional_gl_entries(gl_entries, doc):
|
||||||
country = frappe.get_cached_value('Company', doc.company, 'country')
|
country = frappe.get_cached_value('Company', doc.company, 'country')
|
||||||
|
|
||||||
if country != 'India':
|
if country != 'India':
|
||||||
return
|
return gl_entries
|
||||||
|
|
||||||
|
if not doc.total_taxes_and_charges:
|
||||||
|
return gl_entries
|
||||||
|
|
||||||
if doc.reverse_charge == 'Y':
|
if doc.reverse_charge == 'Y':
|
||||||
gst_accounts = get_gst_accounts(doc.company)
|
gst_accounts = get_gst_accounts(doc.company)
|
||||||
|
@ -7,6 +7,8 @@ from frappe import _
|
|||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
from frappe.model.meta import get_field_precision
|
from frappe.model.meta import get_field_precision
|
||||||
from frappe.utils.xlsxutils import handle_html
|
from frappe.utils.xlsxutils import handle_html
|
||||||
|
from six import iteritems
|
||||||
|
import json
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
return _execute(filters)
|
return _execute(filters)
|
||||||
@ -21,21 +23,24 @@ def _execute(filters=None):
|
|||||||
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency)
|
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency)
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
|
added_item = []
|
||||||
for d in item_list:
|
for d in item_list:
|
||||||
|
if (d.parent, d.item_code) not in added_item:
|
||||||
row = [d.gst_hsn_code, d.description, d.stock_uom, d.stock_qty]
|
row = [d.gst_hsn_code, d.description, d.stock_uom, d.stock_qty]
|
||||||
total_tax = 0
|
total_tax = 0
|
||||||
for tax in tax_columns:
|
for tax in tax_columns:
|
||||||
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
item_tax = itemised_tax.get((d.parent, d.item_code), {}).get(tax, {})
|
||||||
total_tax += flt(item_tax.get("tax_amount"))
|
total_tax += flt(item_tax.get("tax_amount", 0))
|
||||||
|
|
||||||
row += [d.base_net_amount + total_tax]
|
row += [d.base_net_amount + total_tax]
|
||||||
row += [d.base_net_amount]
|
row += [d.base_net_amount]
|
||||||
|
|
||||||
for tax in tax_columns:
|
for tax in tax_columns:
|
||||||
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
item_tax = itemised_tax.get((d.parent, d.item_code), {}).get(tax, {})
|
||||||
row += [item_tax.get("tax_amount", 0)]
|
row += [item_tax.get("tax_amount", 0)]
|
||||||
|
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
added_item.append((d.parent, d.item_code))
|
||||||
if data:
|
if data:
|
||||||
data = get_merged_data(columns, data) # merge same hsn code data
|
data = get_merged_data(columns, data) # merge same hsn code data
|
||||||
return columns, data
|
return columns, data
|
||||||
@ -103,7 +108,7 @@ def get_items(filters):
|
|||||||
match_conditions = " and {0} ".format(match_conditions)
|
match_conditions = " and {0} ".format(match_conditions)
|
||||||
|
|
||||||
|
|
||||||
return frappe.db.sql("""
|
items = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
`tabSales Invoice Item`.name, `tabSales Invoice Item`.base_price_list_rate,
|
`tabSales Invoice Item`.name, `tabSales Invoice Item`.base_price_list_rate,
|
||||||
`tabSales Invoice Item`.gst_hsn_code, `tabSales Invoice Item`.stock_qty,
|
`tabSales Invoice Item`.gst_hsn_code, `tabSales Invoice Item`.stock_qty,
|
||||||
@ -118,10 +123,9 @@ def get_items(filters):
|
|||||||
|
|
||||||
""" % (conditions, match_conditions), filters, as_dict=1)
|
""" % (conditions, match_conditions), filters, as_dict=1)
|
||||||
|
|
||||||
|
return items
|
||||||
|
|
||||||
def get_tax_accounts(item_list, columns, company_currency,
|
def get_tax_accounts(item_list, columns, company_currency, doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"):
|
||||||
doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"):
|
|
||||||
import json
|
|
||||||
item_row_map = {}
|
item_row_map = {}
|
||||||
tax_columns = []
|
tax_columns = []
|
||||||
invoice_item_row = {}
|
invoice_item_row = {}
|
||||||
@ -171,7 +175,7 @@ def get_tax_accounts(item_list, columns, company_currency,
|
|||||||
for d in item_row_map.get(parent, {}).get(item_code, []):
|
for d in item_row_map.get(parent, {}).get(item_code, []):
|
||||||
item_tax_amount = tax_amount
|
item_tax_amount = tax_amount
|
||||||
if item_tax_amount:
|
if item_tax_amount:
|
||||||
itemised_tax.setdefault(d.name, {})[description] = frappe._dict({
|
itemised_tax.setdefault((parent, item_code), {})[description] = frappe._dict({
|
||||||
"tax_amount": flt(item_tax_amount, tax_amount_precision)
|
"tax_amount": flt(item_tax_amount, tax_amount_precision)
|
||||||
})
|
})
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -179,42 +183,32 @@ def get_tax_accounts(item_list, columns, company_currency,
|
|||||||
|
|
||||||
tax_columns.sort()
|
tax_columns.sort()
|
||||||
for desc in tax_columns:
|
for desc in tax_columns:
|
||||||
columns.append(desc + " Amount:Currency/currency:160")
|
columns.append({
|
||||||
|
"label": desc,
|
||||||
|
"fieldname": frappe.scrub(desc),
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"width": 110
|
||||||
|
})
|
||||||
|
|
||||||
# columns += ["Total Amount:Currency/currency:110"]
|
|
||||||
return itemised_tax, tax_columns
|
return itemised_tax, tax_columns
|
||||||
|
|
||||||
def get_merged_data(columns, data):
|
def get_merged_data(columns, data):
|
||||||
merged_hsn_dict = {} # to group same hsn under one key and perform row addition
|
merged_hsn_dict = {} # to group same hsn under one key and perform row addition
|
||||||
add_column_index = [] # store index of columns that needs to be added
|
result = []
|
||||||
tax_col = len(get_columns())
|
|
||||||
fields_to_merge = ["stock_qty", "total_amount", "taxable_amount"] # columns for which index needs to be found
|
|
||||||
|
|
||||||
for i,d in enumerate(columns):
|
|
||||||
# check if fieldname in to_merge list and ignore tax-columns
|
|
||||||
if i < tax_col and d["fieldname"] in fields_to_merge:
|
|
||||||
add_column_index.append(i)
|
|
||||||
|
|
||||||
for row in data:
|
for row in data:
|
||||||
if row[0] in merged_hsn_dict:
|
merged_hsn_dict.setdefault(row[0], {})
|
||||||
to_add_row = merged_hsn_dict.get(row[0])
|
for i, d in enumerate(columns):
|
||||||
|
if d['fieldtype'] not in ('Int', 'Float', 'Currency'):
|
||||||
# add columns from the add_column_index table
|
merged_hsn_dict[row[0]][d['fieldname']] = row[i]
|
||||||
for k in add_column_index:
|
|
||||||
to_add_row[k] += row[k]
|
|
||||||
|
|
||||||
# add tax columns
|
|
||||||
for k in range(len(columns)):
|
|
||||||
if tax_col <= k < len(columns):
|
|
||||||
to_add_row[k] += row[k]
|
|
||||||
|
|
||||||
# update hsn dict with the newly added data
|
|
||||||
merged_hsn_dict[row[0]] = to_add_row
|
|
||||||
else:
|
else:
|
||||||
merged_hsn_dict[row[0]] = row
|
if merged_hsn_dict.get(row[0], {}).get(d['fieldname'], ''):
|
||||||
|
merged_hsn_dict[row[0]][d['fieldname']] += row[i]
|
||||||
|
else:
|
||||||
|
merged_hsn_dict[row[0]][d['fieldname']] = row[i]
|
||||||
|
|
||||||
# extract data rows to be displayed in report
|
for key, value in iteritems(merged_hsn_dict):
|
||||||
data = [merged_hsn_dict[d] for d in merged_hsn_dict]
|
result.append(value)
|
||||||
|
|
||||||
return data
|
return result
|
||||||
|
|
||||||
|
@ -110,7 +110,10 @@ erpnext.PointOfSale.PastOrderSummary = class {
|
|||||||
{fieldname:'print', fieldtype:'Data', label:'Print Preview'}
|
{fieldname:'print', fieldtype:'Data', label:'Print Preview'}
|
||||||
],
|
],
|
||||||
primary_action: () => {
|
primary_action: () => {
|
||||||
this.events.get_frm().print_preview.printit(true);
|
const frm = this.events.get_frm();
|
||||||
|
frm.doc = this.doc;
|
||||||
|
frm.print_preview.lang_code = frm.doc.language;
|
||||||
|
frm.print_preview.printit(true);
|
||||||
},
|
},
|
||||||
primary_action_label: __('Print'),
|
primary_action_label: __('Print'),
|
||||||
});
|
});
|
||||||
@ -271,6 +274,7 @@ erpnext.PointOfSale.PastOrderSummary = class {
|
|||||||
// this.print_dialog.show();
|
// this.print_dialog.show();
|
||||||
const frm = this.events.get_frm();
|
const frm = this.events.get_frm();
|
||||||
frm.doc = this.doc;
|
frm.doc = this.doc;
|
||||||
|
frm.print_preview.lang_code = frm.doc.language;
|
||||||
frm.print_preview.printit(true);
|
frm.print_preview.printit(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user