Merge branch 'develop' into pos-fixes-9
This commit is contained in:
commit
73aaa1c275
@ -49,7 +49,15 @@ frappe.ui.form.on('Opening Invoice Creation Tool', {
|
|||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
btn: $(btn_primary),
|
btn: $(btn_primary),
|
||||||
method: "make_invoices",
|
method: "make_invoices",
|
||||||
freeze_message: __("Creating {0} Invoice", [frm.doc.invoice_type])
|
freeze: 1,
|
||||||
|
freeze_message: __("Creating {0} Invoice", [frm.doc.invoice_type]),
|
||||||
|
callback: function(r) {
|
||||||
|
if (r.message.length == 1) {
|
||||||
|
frappe.msgprint(__("{0} Invoice created successfully.", [frm.doc.invoice_type]));
|
||||||
|
} else if (r.message.length < 50) {
|
||||||
|
frappe.msgprint(__("{0} Invoices created successfully.", [frm.doc.invoice_type]));
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -216,7 +216,8 @@ def start_import(invoices):
|
|||||||
return names
|
return names
|
||||||
|
|
||||||
def publish(index, total, doctype):
|
def publish(index, total, doctype):
|
||||||
if total < 5: return
|
if total < 50:
|
||||||
|
return
|
||||||
frappe.publish_realtime(
|
frappe.publish_realtime(
|
||||||
"opening_invoice_creation_progress",
|
"opening_invoice_creation_progress",
|
||||||
dict(
|
dict(
|
||||||
@ -241,4 +242,3 @@ def get_temporary_opening_account(company=None):
|
|||||||
|
|
||||||
return accounts[0].name
|
return accounts[0].name
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ cur_frm.cscript.tax_table = "Advance Taxes and Charges";
|
|||||||
|
|
||||||
frappe.ui.form.on('Payment Entry', {
|
frappe.ui.form.on('Payment Entry', {
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
|
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice'];
|
||||||
|
|
||||||
if(frm.doc.__islocal) {
|
if(frm.doc.__islocal) {
|
||||||
if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null);
|
if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null);
|
||||||
if (!frm.doc.paid_to) frm.set_value("paid_to_account_currency", null);
|
if (!frm.doc.paid_to) frm.set_value("paid_to_account_currency", null);
|
||||||
|
@ -27,10 +27,6 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
company() {
|
|
||||||
erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
|
|
||||||
}
|
|
||||||
|
|
||||||
onload() {
|
onload() {
|
||||||
super.onload();
|
super.onload();
|
||||||
|
|
||||||
@ -569,5 +565,9 @@ frappe.ui.form.on("Purchase Invoice", {
|
|||||||
frm: frm,
|
frm: frm,
|
||||||
freeze_message: __("Creating Purchase Receipt ...")
|
freeze_message: __("Creating Purchase Receipt ...")
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
|
|
||||||
|
company: function(frm) {
|
||||||
|
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
@ -168,21 +168,24 @@ def get_columns(filters):
|
|||||||
"label": _("Income"),
|
"label": _("Income"),
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"options": "currency",
|
"options": "currency",
|
||||||
"width": 120
|
"width": 305
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "expense",
|
"fieldname": "expense",
|
||||||
"label": _("Expense"),
|
"label": _("Expense"),
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"options": "currency",
|
"options": "currency",
|
||||||
"width": 120
|
"width": 305
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "gross_profit_loss",
|
"fieldname": "gross_profit_loss",
|
||||||
"label": _("Gross Profit / Loss"),
|
"label": _("Gross Profit / Loss"),
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"options": "currency",
|
"options": "currency",
|
||||||
"width": 120
|
"width": 307
|
||||||
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -9,13 +9,14 @@
|
|||||||
"supp_master_name",
|
"supp_master_name",
|
||||||
"supplier_group",
|
"supplier_group",
|
||||||
"buying_price_list",
|
"buying_price_list",
|
||||||
|
"maintain_same_rate_action",
|
||||||
|
"role_to_override_stop_action",
|
||||||
"column_break_3",
|
"column_break_3",
|
||||||
"po_required",
|
"po_required",
|
||||||
"pr_required",
|
"pr_required",
|
||||||
"maintain_same_rate",
|
"maintain_same_rate",
|
||||||
"maintain_same_rate_action",
|
|
||||||
"role_to_override_stop_action",
|
|
||||||
"allow_multiple_items",
|
"allow_multiple_items",
|
||||||
|
"bill_for_rejected_quantity_in_purchase_invoice",
|
||||||
"subcontract",
|
"subcontract",
|
||||||
"backflush_raw_materials_of_subcontract_based_on",
|
"backflush_raw_materials_of_subcontract_based_on",
|
||||||
"column_break_11",
|
"column_break_11",
|
||||||
@ -108,6 +109,13 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Role Allowed to Override Stop Action",
|
"label": "Role Allowed to Override Stop Action",
|
||||||
"options": "Role"
|
"options": "Role"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "1",
|
||||||
|
"description": "If checked, Rejected Quantity will be included while making Purchase Invoice from Purchase Receipt.",
|
||||||
|
"fieldname": "bill_for_rejected_quantity_in_purchase_invoice",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Bill for Rejected Quantity in Purchase Invoice"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-cog",
|
"icon": "fa fa-cog",
|
||||||
@ -115,7 +123,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-04-04 20:01:44.087066",
|
"modified": "2021-06-23 19:40:00.120822",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Buying Settings",
|
"name": "Buying Settings",
|
||||||
|
@ -828,6 +828,12 @@ class AccountsController(TransactionBase):
|
|||||||
role_allowed_to_over_bill = frappe.db.get_single_value('Accounts Settings', 'role_allowed_to_over_bill')
|
role_allowed_to_over_bill = frappe.db.get_single_value('Accounts Settings', 'role_allowed_to_over_bill')
|
||||||
|
|
||||||
if total_billed_amt - max_allowed_amt > 0.01 and role_allowed_to_over_bill not in frappe.get_roles():
|
if total_billed_amt - max_allowed_amt > 0.01 and role_allowed_to_over_bill not in frappe.get_roles():
|
||||||
|
if self.doctype != "Purchase Invoice":
|
||||||
|
self.throw_overbill_exception(item, max_allowed_amt)
|
||||||
|
elif not cint(frappe.db.get_single_value("Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice")):
|
||||||
|
self.throw_overbill_exception(item, max_allowed_amt)
|
||||||
|
|
||||||
|
def throw_overbill_exception(self, item, max_allowed_amt):
|
||||||
frappe.throw(_("Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set allowance in Accounts Settings")
|
frappe.throw(_("Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set allowance in Accounts Settings")
|
||||||
.format(item.item_code, item.idx, max_allowed_amt))
|
.format(item.item_code, item.idx, max_allowed_amt))
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ def employee_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
fields = get_fields("Employee", ["name", "employee_name"])
|
fields = get_fields("Employee", ["name", "employee_name"])
|
||||||
|
|
||||||
return frappe.db.sql("""select {fields} from `tabEmployee`
|
return frappe.db.sql("""select {fields} from `tabEmployee`
|
||||||
where status = 'Active'
|
where status in ('Active', 'Suspended')
|
||||||
and docstatus < 2
|
and docstatus < 2
|
||||||
and ({key} like %(txt)s
|
and ({key} like %(txt)s
|
||||||
or employee_name like %(txt)s)
|
or employee_name like %(txt)s)
|
||||||
|
@ -22,10 +22,10 @@ frappe.query_reports["First Response Time for Opportunity"] = {
|
|||||||
get_chart_data: function (_columns, result) {
|
get_chart_data: function (_columns, result) {
|
||||||
return {
|
return {
|
||||||
data: {
|
data: {
|
||||||
labels: result.map(d => d[0]),
|
labels: result.map(d => d.creation_date),
|
||||||
datasets: [{
|
datasets: [{
|
||||||
name: "First Response Time",
|
name: "First Response Time",
|
||||||
values: result.map(d => d[1])
|
values: result.map(d => d.first_response_time)
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
type: "line",
|
type: "line",
|
||||||
@ -35,8 +35,7 @@ frappe.query_reports["First Response Time for Opportunity"] = {
|
|||||||
hide_days: 0,
|
hide_days: 0,
|
||||||
hide_seconds: 0
|
hide_seconds: 0
|
||||||
};
|
};
|
||||||
value = frappe.utils.get_formatted_duration(d, duration_options);
|
return frappe.utils.get_formatted_duration(d, duration_options);
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,7 +207,7 @@
|
|||||||
"label": "Status",
|
"label": "Status",
|
||||||
"oldfieldname": "status",
|
"oldfieldname": "status",
|
||||||
"oldfieldtype": "Select",
|
"oldfieldtype": "Select",
|
||||||
"options": "Active\nInactive\nLeft",
|
"options": "Active\nInactive\nSuspended\nLeft",
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 1
|
"search_index": 1
|
||||||
},
|
},
|
||||||
@ -813,7 +813,7 @@
|
|||||||
"idx": 24,
|
"idx": 24,
|
||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-06-12 11:31:37.730760",
|
"modified": "2021-06-17 11:31:37.730760",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Employee",
|
"name": "Employee",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
from frappe.utils import getdate, validate_email_address, today, add_years, format_datetime, cstr
|
from frappe.utils import getdate, validate_email_address, today, add_years, cstr
|
||||||
from frappe.model.naming import set_name_by_naming_series
|
from frappe.model.naming import set_name_by_naming_series
|
||||||
from frappe import throw, _, scrub
|
from frappe import throw, _, scrub
|
||||||
from frappe.permissions import add_user_permission, remove_user_permission, \
|
from frappe.permissions import add_user_permission, remove_user_permission, \
|
||||||
@ -12,7 +12,6 @@ from frappe.permissions import add_user_permission, remove_user_permission, \
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.utilities.transaction_base import delete_events
|
from erpnext.utilities.transaction_base import delete_events
|
||||||
from frappe.utils.nestedset import NestedSet
|
from frappe.utils.nestedset import NestedSet
|
||||||
from erpnext.hr.doctype.job_offer.job_offer import get_staffing_plan_detail
|
|
||||||
|
|
||||||
class EmployeeUserDisabledError(frappe.ValidationError): pass
|
class EmployeeUserDisabledError(frappe.ValidationError): pass
|
||||||
class EmployeeLeftValidationError(frappe.ValidationError): pass
|
class EmployeeLeftValidationError(frappe.ValidationError): pass
|
||||||
@ -37,7 +36,7 @@ class Employee(NestedSet):
|
|||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
from erpnext.controllers.status_updater import validate_status
|
from erpnext.controllers.status_updater import validate_status
|
||||||
validate_status(self.status, ["Active", "Inactive", "Left"])
|
validate_status(self.status, ["Active", "Inactive", "Suspended", "Left"])
|
||||||
|
|
||||||
self.employee = self.name
|
self.employee = self.name
|
||||||
self.set_employee_name()
|
self.set_employee_name()
|
||||||
|
@ -7,7 +7,8 @@ def get_data():
|
|||||||
'heatmap_message': _('This is based on the attendance of this Employee'),
|
'heatmap_message': _('This is based on the attendance of this Employee'),
|
||||||
'fieldname': 'employee',
|
'fieldname': 'employee',
|
||||||
'non_standard_fieldnames': {
|
'non_standard_fieldnames': {
|
||||||
'Bank Account': 'party'
|
'Bank Account': 'party',
|
||||||
|
'Employee Grievance': 'raised_by'
|
||||||
},
|
},
|
||||||
'transactions': [
|
'transactions': [
|
||||||
{
|
{
|
||||||
@ -20,7 +21,7 @@ def get_data():
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'label': _('Lifecycle'),
|
'label': _('Lifecycle'),
|
||||||
'items': ['Employee Transfer', 'Employee Promotion', 'Employee Separation']
|
'items': ['Employee Transfer', 'Employee Promotion', 'Employee Separation', 'Employee Grievance']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'label': _('Shift'),
|
'label': _('Shift'),
|
||||||
|
@ -3,7 +3,7 @@ frappe.listview_settings['Employee'] = {
|
|||||||
filters: [["status","=", "Active"]],
|
filters: [["status","=", "Active"]],
|
||||||
get_indicator: function(doc) {
|
get_indicator: function(doc) {
|
||||||
var indicator = [__(doc.status), frappe.utils.guess_colour(doc.status), "status,=," + doc.status];
|
var indicator = [__(doc.status), frappe.utils.guess_colour(doc.status), "status,=," + doc.status];
|
||||||
indicator[1] = {"Active": "green", "Inactive": "red", "Left": "gray"}[doc.status];
|
indicator[1] = {"Active": "green", "Inactive": "red", "Left": "gray", "Suspended": "orange"}[doc.status];
|
||||||
return indicator;
|
return indicator;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
0
erpnext/hr/doctype/employee_grievance/__init__.py
Normal file
0
erpnext/hr/doctype/employee_grievance/__init__.py
Normal file
39
erpnext/hr/doctype/employee_grievance/employee_grievance.js
Normal file
39
erpnext/hr/doctype/employee_grievance/employee_grievance.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on('Employee Grievance', {
|
||||||
|
setup: function(frm) {
|
||||||
|
frm.set_query('grievance_against_party', function() {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
name: ['in', [
|
||||||
|
'Company', 'Department', 'Employee Group', 'Employee Grade', 'Employee']
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
frm.set_query('associated_document_type', function() {
|
||||||
|
let ignore_modules = ["Setup", "Core", "Integrations", "Automation", "Website",
|
||||||
|
"Utilities", "Event Streaming", "Social", "Chat", "Data Migration", "Printing", "Desk", "Custom"];
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
istable: 0,
|
||||||
|
issingle: 0,
|
||||||
|
module: ["Not In", ignore_modules]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
grievance_against_party: function(frm) {
|
||||||
|
let filters = {};
|
||||||
|
if (frm.doc.grievance_against_party == 'Employee' && frm.doc.raised_by) {
|
||||||
|
filters.name = ["!=", frm.doc.raised_by];
|
||||||
|
}
|
||||||
|
frm.set_query('grievance_against', function() {
|
||||||
|
return {
|
||||||
|
filters: filters
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
261
erpnext/hr/doctype/employee_grievance/employee_grievance.json
Normal file
261
erpnext/hr/doctype/employee_grievance/employee_grievance.json
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"autoname": "HR-GRIEV-.YYYY.-.#####",
|
||||||
|
"creation": "2021-05-11 13:41:51.485295",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"subject",
|
||||||
|
"raised_by",
|
||||||
|
"employee_name",
|
||||||
|
"designation",
|
||||||
|
"column_break_3",
|
||||||
|
"date",
|
||||||
|
"status",
|
||||||
|
"reports_to",
|
||||||
|
"grievance_details_section",
|
||||||
|
"grievance_against_party",
|
||||||
|
"grievance_against",
|
||||||
|
"grievance_type",
|
||||||
|
"column_break_11",
|
||||||
|
"associated_document_type",
|
||||||
|
"associated_document",
|
||||||
|
"section_break_14",
|
||||||
|
"description",
|
||||||
|
"investigation_details_section",
|
||||||
|
"cause_of_grievance",
|
||||||
|
"resolution_details_section",
|
||||||
|
"resolved_by",
|
||||||
|
"resolution_date",
|
||||||
|
"employee_responsible",
|
||||||
|
"column_break_16",
|
||||||
|
"resolution_detail",
|
||||||
|
"amended_from"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "grievance_type",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Grievance Type",
|
||||||
|
"options": "Grievance Type",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_3",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Date ",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "Open",
|
||||||
|
"fieldname": "status",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Status",
|
||||||
|
"options": "Open\nInvestigated\nResolved\nInvalid",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "description",
|
||||||
|
"fieldtype": "Text",
|
||||||
|
"label": "Description",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "cause_of_grievance",
|
||||||
|
"fieldtype": "Text",
|
||||||
|
"label": "Cause of Grievance",
|
||||||
|
"mandatory_depends_on": "eval: doc.status == \"Investigated\" || doc.status == \"Resolved\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "resolution_details_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Resolution Details"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "resolved_by",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Resolved By",
|
||||||
|
"mandatory_depends_on": "eval: doc.status == \"Resolved\"",
|
||||||
|
"options": "User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "employee_responsible",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Employee Responsible ",
|
||||||
|
"options": "Employee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "resolution_detail",
|
||||||
|
"fieldtype": "Small Text",
|
||||||
|
"label": "Resolution Details",
|
||||||
|
"mandatory_depends_on": "eval: doc.status == \"Resolved\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_16",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "resolution_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "Resolution Date",
|
||||||
|
"mandatory_depends_on": "eval: doc.status == \"Resolved\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "grievance_against",
|
||||||
|
"fieldtype": "Dynamic Link",
|
||||||
|
"label": "Grievance Against",
|
||||||
|
"options": "grievance_against_party",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "raised_by",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Raised By",
|
||||||
|
"options": "Employee",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "amended_from",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Amended From",
|
||||||
|
"no_copy": 1,
|
||||||
|
"options": "Employee Grievance",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "raised_by.designation",
|
||||||
|
"fieldname": "designation",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Designation",
|
||||||
|
"options": "Designation",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "raised_by.reports_to",
|
||||||
|
"fieldname": "reports_to",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Reports To",
|
||||||
|
"options": "Employee",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "grievance_details_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Grievance Details"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_11",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_14",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "grievance_against_party",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Grievance Against Party",
|
||||||
|
"options": "DocType",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "associated_document_type",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Associated Document Type",
|
||||||
|
"options": "DocType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "associated_document",
|
||||||
|
"fieldtype": "Dynamic Link",
|
||||||
|
"label": "Associated Document",
|
||||||
|
"options": "associated_document_type"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "investigation_details_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Investigation Details"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "raised_by.employee_name",
|
||||||
|
"fieldname": "employee_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Employee Name",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "subject",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Subject",
|
||||||
|
"reqd": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"is_submittable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2021-06-21 12:51:01.499486",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "HR",
|
||||||
|
"name": "Employee Grievance",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"amend": 1,
|
||||||
|
"cancel": 1,
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"select": 1,
|
||||||
|
"share": 1,
|
||||||
|
"submit": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"amend": 1,
|
||||||
|
"cancel": 1,
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "HR Manager",
|
||||||
|
"select": 1,
|
||||||
|
"share": 1,
|
||||||
|
"submit": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "HR User",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"search_fields": "subject,raised_by,grievance_against_party",
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"title_field": "subject",
|
||||||
|
"track_changes": 1
|
||||||
|
}
|
15
erpnext/hr/doctype/employee_grievance/employee_grievance.py
Normal file
15
erpnext/hr/doctype/employee_grievance/employee_grievance.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from frappe import _, bold
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
class EmployeeGrievance(Document):
|
||||||
|
def on_submit(self):
|
||||||
|
if self.status not in ["Invalid", "Resolved"]:
|
||||||
|
frappe.throw(_("Only Employee Grievance with status {0} or {1} can be submitted").format(
|
||||||
|
bold("Invalid"),
|
||||||
|
bold("Resolved"))
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,12 @@
|
|||||||
|
frappe.listview_settings["Employee Grievance"] = {
|
||||||
|
has_indicator_for_draft: 1,
|
||||||
|
get_indicator: function(doc) {
|
||||||
|
var colors = {
|
||||||
|
"Open": "red",
|
||||||
|
"Investigated": "orange",
|
||||||
|
"Resolved": "green",
|
||||||
|
"Invalid": "grey"
|
||||||
|
};
|
||||||
|
return [__(doc.status), colors[doc.status], "status,=," + doc.status];
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,51 @@
|
|||||||
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# See license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
import unittest
|
||||||
|
from frappe.utils import today
|
||||||
|
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||||
|
class TestEmployeeGrievance(unittest.TestCase):
|
||||||
|
def test_create_employee_grievance(self):
|
||||||
|
create_employee_grievance()
|
||||||
|
|
||||||
|
def create_employee_grievance():
|
||||||
|
grievance_type = create_grievance_type()
|
||||||
|
emp_1 = make_employee("test_emp_grievance_@example.com", company="_Test Company")
|
||||||
|
emp_2 = make_employee("testculprit@example.com", company="_Test Company")
|
||||||
|
|
||||||
|
grievance = frappe.new_doc("Employee Grievance")
|
||||||
|
grievance.subject = "Test Employee Grievance"
|
||||||
|
grievance.raised_by = emp_1
|
||||||
|
grievance.date = today()
|
||||||
|
grievance.grievance_type = grievance_type
|
||||||
|
grievance.grievance_against_party = "Employee"
|
||||||
|
grievance.grievance_against = emp_2
|
||||||
|
grievance.description = "test descrip"
|
||||||
|
|
||||||
|
#set cause
|
||||||
|
grievance.cause_of_grievance = "test cause"
|
||||||
|
|
||||||
|
#resolution details
|
||||||
|
grievance.resolution_date = today()
|
||||||
|
grievance.resolution_detail = "test resolution detail"
|
||||||
|
grievance.resolved_by = "test_emp_grievance_@example.com"
|
||||||
|
grievance.employee_responsible = emp_2
|
||||||
|
grievance.status = "Resolved"
|
||||||
|
|
||||||
|
grievance.save()
|
||||||
|
grievance.submit()
|
||||||
|
|
||||||
|
return grievance
|
||||||
|
|
||||||
|
|
||||||
|
def create_grievance_type():
|
||||||
|
if frappe.db.exists("Grievance Type", "Employee Abuse"):
|
||||||
|
return frappe.get_doc("Grievance Type", "Employee Abuse")
|
||||||
|
grievance_type = frappe.new_doc("Grievance Type")
|
||||||
|
grievance_type.name = "Employee Abuse"
|
||||||
|
grievance_type.description = "Test"
|
||||||
|
grievance_type.save()
|
||||||
|
|
||||||
|
return grievance_type.name
|
||||||
|
|
0
erpnext/hr/doctype/grievance_type/__init__.py
Normal file
0
erpnext/hr/doctype/grievance_type/__init__.py
Normal file
8
erpnext/hr/doctype/grievance_type/grievance_type.js
Normal file
8
erpnext/hr/doctype/grievance_type/grievance_type.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on('Grievance Type', {
|
||||||
|
// refresh: function(frm) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
});
|
70
erpnext/hr/doctype/grievance_type/grievance_type.json
Normal file
70
erpnext/hr/doctype/grievance_type/grievance_type.json
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"autoname": "Prompt",
|
||||||
|
"creation": "2021-05-11 12:41:50.256071",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"section_break_5",
|
||||||
|
"description"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_5",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "description",
|
||||||
|
"fieldtype": "Text",
|
||||||
|
"label": "Description"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2021-06-21 12:54:37.764712",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "HR",
|
||||||
|
"name": "Grievance Type",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "HR Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "HR User",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC"
|
||||||
|
}
|
8
erpnext/hr/doctype/grievance_type/grievance_type.py
Normal file
8
erpnext/hr/doctype/grievance_type/grievance_type.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
class GrievanceType(Document):
|
||||||
|
pass
|
8
erpnext/hr/doctype/grievance_type/test_grievance_type.py
Normal file
8
erpnext/hr/doctype/grievance_type/test_grievance_type.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# See license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class TestGrievanceType(unittest.TestCase):
|
||||||
|
pass
|
@ -2,7 +2,7 @@
|
|||||||
// MIT License. See license.txt
|
// MIT License. See license.txt
|
||||||
|
|
||||||
frappe.listview_settings['Job Applicant'] = {
|
frappe.listview_settings['Job Applicant'] = {
|
||||||
add_fields: ["company", "designation", "job_applicant", "status"],
|
add_fields: ["status"],
|
||||||
get_indicator: function (doc) {
|
get_indicator: function (doc) {
|
||||||
if (doc.status == "Accepted") {
|
if (doc.status == "Accepted") {
|
||||||
return [__(doc.status), "green", "status,=," + doc.status];
|
return [__(doc.status), "green", "status,=," + doc.status];
|
||||||
|
@ -110,6 +110,7 @@
|
|||||||
"label": "Allocation"
|
"label": "Allocation"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_on_submit": 1,
|
||||||
"bold": 1,
|
"bold": 1,
|
||||||
"fieldname": "new_leaves_allocated",
|
"fieldname": "new_leaves_allocated",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
@ -235,7 +236,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-04-14 15:28:26.335104",
|
"modified": "2021-06-03 15:28:26.335104",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Leave Allocation",
|
"name": "Leave Allocation",
|
||||||
|
@ -8,6 +8,7 @@ from frappe import _
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.hr.utils import set_employee_name, get_leave_period
|
from erpnext.hr.utils import set_employee_name, get_leave_period
|
||||||
from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import expire_allocation, create_leave_ledger_entry
|
from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import expire_allocation, create_leave_ledger_entry
|
||||||
|
from erpnext.hr.doctype.leave_application.leave_application import get_approved_leaves_for_period
|
||||||
|
|
||||||
class OverlapError(frappe.ValidationError): pass
|
class OverlapError(frappe.ValidationError): pass
|
||||||
class BackDatedAllocationError(frappe.ValidationError): pass
|
class BackDatedAllocationError(frappe.ValidationError): pass
|
||||||
@ -55,6 +56,43 @@ class LeaveAllocation(Document):
|
|||||||
if self.carry_forward:
|
if self.carry_forward:
|
||||||
self.set_carry_forwarded_leaves_in_previous_allocation(on_cancel=True)
|
self.set_carry_forwarded_leaves_in_previous_allocation(on_cancel=True)
|
||||||
|
|
||||||
|
def on_update_after_submit(self):
|
||||||
|
if self.has_value_changed("new_leaves_allocated"):
|
||||||
|
self.validate_against_leave_applications()
|
||||||
|
leaves_to_be_added = self.new_leaves_allocated - self.get_existing_leave_count()
|
||||||
|
args = {
|
||||||
|
"leaves": leaves_to_be_added,
|
||||||
|
"from_date": self.from_date,
|
||||||
|
"to_date": self.to_date,
|
||||||
|
"is_carry_forward": 0
|
||||||
|
}
|
||||||
|
create_leave_ledger_entry(self, args, True)
|
||||||
|
|
||||||
|
def get_existing_leave_count(self):
|
||||||
|
ledger_entries = frappe.get_all("Leave Ledger Entry",
|
||||||
|
filters={
|
||||||
|
"transaction_type": "Leave Allocation",
|
||||||
|
"transaction_name": self.name,
|
||||||
|
"employee": self.employee,
|
||||||
|
"company": self.company,
|
||||||
|
"leave_type": self.leave_type
|
||||||
|
},
|
||||||
|
pluck="leaves")
|
||||||
|
total_existing_leaves = 0
|
||||||
|
for entry in ledger_entries:
|
||||||
|
total_existing_leaves += entry
|
||||||
|
|
||||||
|
return total_existing_leaves
|
||||||
|
|
||||||
|
def validate_against_leave_applications(self):
|
||||||
|
leaves_taken = get_approved_leaves_for_period(self.employee, self.leave_type,
|
||||||
|
self.from_date, self.to_date)
|
||||||
|
if flt(leaves_taken) > flt(self.total_leaves_allocated):
|
||||||
|
if frappe.db.get_value("Leave Type", self.leave_type, "allow_negative"):
|
||||||
|
frappe.msgprint(_("Note: Total allocated leaves {0} shouldn't be less than already approved leaves {1} for the period").format(self.total_leaves_allocated, leaves_taken))
|
||||||
|
else:
|
||||||
|
frappe.throw(_("Total allocated leaves {0} cannot be less than already approved leaves {1} for the period").format(self.total_leaves_allocated, leaves_taken), LessAllocationError)
|
||||||
|
|
||||||
def update_leave_policy_assignments_when_no_allocations_left(self):
|
def update_leave_policy_assignments_when_no_allocations_left(self):
|
||||||
allocations = frappe.db.get_list("Leave Allocation", filters = {
|
allocations = frappe.db.get_list("Leave Allocation", filters = {
|
||||||
"docstatus": 1,
|
"docstatus": 1,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
|
import erpnext
|
||||||
import unittest
|
import unittest
|
||||||
from frappe.utils import nowdate, add_months, getdate, add_days
|
from frappe.utils import nowdate, add_months, getdate, add_days
|
||||||
from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
|
from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
|
||||||
from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import process_expired_allocation, expire_allocation
|
from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import process_expired_allocation, expire_allocation
|
||||||
|
|
||||||
class TestLeaveAllocation(unittest.TestCase):
|
class TestLeaveAllocation(unittest.TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
@ -164,6 +164,53 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
leave_allocation.cancel()
|
leave_allocation.cancel()
|
||||||
self.assertFalse(frappe.db.exists("Leave Ledger Entry", {'transaction_name':leave_allocation.name}))
|
self.assertFalse(frappe.db.exists("Leave Ledger Entry", {'transaction_name':leave_allocation.name}))
|
||||||
|
|
||||||
|
|
||||||
|
def test_leave_addition_after_submit(self):
|
||||||
|
frappe.db.sql("delete from `tabLeave Allocation`")
|
||||||
|
frappe.db.sql("delete from `tabLeave Ledger Entry`")
|
||||||
|
|
||||||
|
leave_allocation = create_leave_allocation()
|
||||||
|
leave_allocation.submit()
|
||||||
|
self.assertTrue(leave_allocation.total_leaves_allocated, 15)
|
||||||
|
leave_allocation.new_leaves_allocated = 40
|
||||||
|
leave_allocation.submit()
|
||||||
|
self.assertTrue(leave_allocation.total_leaves_allocated, 40)
|
||||||
|
|
||||||
|
def test_leave_subtraction_after_submit(self):
|
||||||
|
frappe.db.sql("delete from `tabLeave Allocation`")
|
||||||
|
frappe.db.sql("delete from `tabLeave Ledger Entry`")
|
||||||
|
|
||||||
|
leave_allocation = create_leave_allocation()
|
||||||
|
leave_allocation.submit()
|
||||||
|
self.assertTrue(leave_allocation.total_leaves_allocated, 15)
|
||||||
|
leave_allocation.new_leaves_allocated = 10
|
||||||
|
leave_allocation.submit()
|
||||||
|
self.assertTrue(leave_allocation.total_leaves_allocated, 10)
|
||||||
|
|
||||||
|
def test_against_leave_application_validation_after_submit(self):
|
||||||
|
frappe.db.sql("delete from `tabLeave Allocation`")
|
||||||
|
frappe.db.sql("delete from `tabLeave Ledger Entry`")
|
||||||
|
|
||||||
|
leave_allocation = create_leave_allocation()
|
||||||
|
leave_allocation.submit()
|
||||||
|
self.assertTrue(leave_allocation.total_leaves_allocated, 15)
|
||||||
|
employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
|
||||||
|
leave_application = frappe.get_doc({
|
||||||
|
"doctype": 'Leave Application',
|
||||||
|
"employee": employee.name,
|
||||||
|
"leave_type": "_Test Leave Type",
|
||||||
|
"from_date": nowdate(),
|
||||||
|
"to_date": add_days(nowdate(), 10),
|
||||||
|
"company": erpnext.get_default_company() or "_Test Company",
|
||||||
|
"docstatus": 1,
|
||||||
|
"status": "Approved",
|
||||||
|
"leave_approver": 'test@example.com'
|
||||||
|
})
|
||||||
|
leave_application.submit()
|
||||||
|
leave_allocation.new_leaves_allocated = 8
|
||||||
|
leave_allocation.total_leaves_allocated = 8
|
||||||
|
self.assertRaises(frappe.ValidationError, leave_allocation.submit)
|
||||||
|
|
||||||
def create_leave_allocation(**args):
|
def create_leave_allocation(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|
||||||
|
@ -103,4 +103,4 @@ var set_total_estimated_budget = function(frm) {
|
|||||||
})
|
})
|
||||||
frm.set_value('total_estimated_budget', estimated_budget);
|
frm.set_value('total_estimated_budget', estimated_budget);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
@ -41,7 +41,7 @@ class StaffingPlan(Document):
|
|||||||
|
|
||||||
detail.total_estimated_cost = 0
|
detail.total_estimated_cost = 0
|
||||||
if detail.number_of_positions > 0:
|
if detail.number_of_positions > 0:
|
||||||
if detail.vacancies > 0 and detail.estimated_cost_per_position:
|
if detail.vacancies and detail.estimated_cost_per_position:
|
||||||
detail.total_estimated_cost = cint(detail.vacancies) * flt(detail.estimated_cost_per_position)
|
detail.total_estimated_cost = cint(detail.vacancies) * flt(detail.estimated_cost_per_position)
|
||||||
|
|
||||||
self.total_estimated_budget += detail.total_estimated_cost
|
self.total_estimated_budget += detail.total_estimated_cost
|
||||||
@ -76,12 +76,12 @@ class StaffingPlan(Document):
|
|||||||
if cint(staffing_plan_detail.vacancies) > cint(parent_plan_details[0].vacancies) or \
|
if cint(staffing_plan_detail.vacancies) > cint(parent_plan_details[0].vacancies) or \
|
||||||
flt(staffing_plan_detail.total_estimated_cost) > flt(parent_plan_details[0].total_estimated_cost):
|
flt(staffing_plan_detail.total_estimated_cost) > flt(parent_plan_details[0].total_estimated_cost):
|
||||||
frappe.throw(_("You can only plan for upto {0} vacancies and budget {1} \
|
frappe.throw(_("You can only plan for upto {0} vacancies and budget {1} \
|
||||||
for {2} as per staffing plan {3} for parent company {4}."
|
for {2} as per staffing plan {3} for parent company {4}.").format(
|
||||||
.format(cint(parent_plan_details[0].vacancies),
|
cint(parent_plan_details[0].vacancies),
|
||||||
parent_plan_details[0].total_estimated_cost,
|
parent_plan_details[0].total_estimated_cost,
|
||||||
frappe.bold(staffing_plan_detail.designation),
|
frappe.bold(staffing_plan_detail.designation),
|
||||||
parent_plan_details[0].name,
|
parent_plan_details[0].name,
|
||||||
parent_company)), ParentCompanyError)
|
parent_company), ParentCompanyError)
|
||||||
|
|
||||||
#Get vacanices already planned for all companies down the hierarchy of Parent Company
|
#Get vacanices already planned for all companies down the hierarchy of Parent Company
|
||||||
lft, rgt = frappe.get_cached_value('Company', parent_company, ["lft", "rgt"])
|
lft, rgt = frappe.get_cached_value('Company', parent_company, ["lft", "rgt"])
|
||||||
@ -98,14 +98,14 @@ class StaffingPlan(Document):
|
|||||||
(flt(parent_plan_details[0].total_estimated_cost) < \
|
(flt(parent_plan_details[0].total_estimated_cost) < \
|
||||||
(flt(staffing_plan_detail.total_estimated_cost) + flt(all_sibling_details.total_estimated_cost))):
|
(flt(staffing_plan_detail.total_estimated_cost) + flt(all_sibling_details.total_estimated_cost))):
|
||||||
frappe.throw(_("{0} vacancies and {1} budget for {2} already planned for subsidiary companies of {3}. \
|
frappe.throw(_("{0} vacancies and {1} budget for {2} already planned for subsidiary companies of {3}. \
|
||||||
You can only plan for upto {4} vacancies and and budget {5} as per staffing plan {6} for parent company {3}."
|
You can only plan for upto {4} vacancies and and budget {5} as per staffing plan {6} for parent company {3}.").format(
|
||||||
.format(cint(all_sibling_details.vacancies),
|
cint(all_sibling_details.vacancies),
|
||||||
all_sibling_details.total_estimated_cost,
|
all_sibling_details.total_estimated_cost,
|
||||||
frappe.bold(staffing_plan_detail.designation),
|
frappe.bold(staffing_plan_detail.designation),
|
||||||
parent_company,
|
parent_company,
|
||||||
cint(parent_plan_details[0].vacancies),
|
cint(parent_plan_details[0].vacancies),
|
||||||
parent_plan_details[0].total_estimated_cost,
|
parent_plan_details[0].total_estimated_cost,
|
||||||
parent_plan_details[0].name)))
|
parent_plan_details[0].name))
|
||||||
|
|
||||||
def validate_with_subsidiary_plans(self, staffing_plan_detail):
|
def validate_with_subsidiary_plans(self, staffing_plan_detail):
|
||||||
#Valdate this plan with all child company plan
|
#Valdate this plan with all child company plan
|
||||||
@ -121,11 +121,11 @@ class StaffingPlan(Document):
|
|||||||
cint(staffing_plan_detail.vacancies) < cint(children_details.vacancies) or \
|
cint(staffing_plan_detail.vacancies) < cint(children_details.vacancies) or \
|
||||||
flt(staffing_plan_detail.total_estimated_cost) < flt(children_details.total_estimated_cost):
|
flt(staffing_plan_detail.total_estimated_cost) < flt(children_details.total_estimated_cost):
|
||||||
frappe.throw(_("Subsidiary companies have already planned for {1} vacancies at a budget of {2}. \
|
frappe.throw(_("Subsidiary companies have already planned for {1} vacancies at a budget of {2}. \
|
||||||
Staffing Plan for {0} should allocate more vacancies and budget for {3} than planned for its subsidiary companies"
|
Staffing Plan for {0} should allocate more vacancies and budget for {3} than planned for its subsidiary companies").format(
|
||||||
.format(self.company,
|
self.company,
|
||||||
cint(children_details.vacancies),
|
cint(children_details.vacancies),
|
||||||
children_details.total_estimated_cost,
|
children_details.total_estimated_cost,
|
||||||
frappe.bold(staffing_plan_detail.designation))), SubsidiaryCompanyError)
|
frappe.bold(staffing_plan_detail.designation)), SubsidiaryCompanyError)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_designation_counts(designation, company):
|
def get_designation_counts(designation, company):
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
"event": "Submit",
|
"event": "Submit",
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"is_standard": 1,
|
"is_standard": 1,
|
||||||
"message": "<table class=\"panel-header\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n <tr height=\"10\"></tr>\n <tr>\n <td width=\"15\"></td>\n <td>\n <div class=\"text-medium text-muted\">\n <span>{{_(\"Training Event:\")}} {{ doc.event_name }}</span>\n </div>\n </td>\n <td width=\"15\"></td>\n </tr>\n <tr height=\"10\"></tr>\n</table>\n\n<table class=\"panel-body\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n <tr height=\"10\"></tr>\n <tr>\n <td width=\"15\"></td>\n <td>\n <div>\n {{ doc.introduction }}\n <ul class=\"list-unstyled\" style=\"line-height: 1.7\">\n <li>{{_(\"Event Location\")}}: <b>{{ doc.location }}</b></li>\n {% set start = frappe.utils.get_datetime(doc.start_time) %}\n {% set end = frappe.utils.get_datetime(doc.end_time) %}\n {% if start.date() == end.date() %}\n <li>{{_(\"Date\")}}: <b>{{ start.strftime(\"%A, %d %b %Y\") }}</b></li>\n <li>\n {{_(\"Timing\")}}: <b>{{ start.strftime(\"%I:%M %p\") + ' to ' + end.strftime(\"%I:%M %p\") }}</b>\n </li>\n {% else %}\n <li>{{_(\"Start Time\")}}: <b>{{ start.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b>\n </li>\n <li>{{_(\"End Time\")}}: <b>{{ end.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b>\n </li>\n {% endif %}\n <li>{{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}</li>\n {% if doc.is_mandatory %}\n <li>Note: This Training Event is mandatory</li>\n {% endif %}\n </ul>\n </div>\n </td>\n <td width=\"15\"></td>\n </tr>\n <tr height=\"10\"></tr>\n</table>",
|
"message": "<table class=\"panel-header\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n <tr height=\"10\"></tr>\n <tr>\n <td width=\"15\"></td>\n <td>\n <div class=\"text-medium text-muted\">\n <span>{{_(\"Training Event:\")}} {{ doc.event_name }}</span>\n </div>\n </td>\n <td width=\"15\"></td>\n </tr>\n <tr height=\"10\"></tr>\n</table>\n\n<table class=\"panel-body\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n <tr height=\"10\"></tr>\n <tr>\n <td width=\"15\"></td>\n <td>\n <div>\n {{ doc.introduction }}\n <ul class=\"list-unstyled\" style=\"line-height: 1.7\">\n <li>{{_(\"Event Location\")}}: <b>{{ doc.location }}</b></li>\n {% set start = frappe.utils.get_datetime(doc.start_time) %}\n {% set end = frappe.utils.get_datetime(doc.end_time) %}\n {% if start.date() == end.date() %}\n <li>{{_(\"Date\")}}: <b>{{ start.strftime(\"%A, %d %b %Y\") }}</b></li>\n <li>\n {{_(\"Timing\")}}: <b>{{ start.strftime(\"%I:%M %p\") + ' to ' + end.strftime(\"%I:%M %p\") }}</b>\n </li>\n {% else %}\n <li>\n {{_(\"Start Time\")}}: <b>{{ start.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b>\n </li>\n <li>{{_(\"End Time\")}}: <b>{{ end.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b></li>\n {% endif %}\n <li>{{ _(\"Event Link\") }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}</li>\n {% if doc.is_mandatory %}\n <li>{{ _(\"Note: This Training Event is mandatory\") }}</li>\n {% endif %}\n </ul>\n </div>\n </td>\n <td width=\"15\"></td>\n </tr>\n <tr height=\"10\"></tr>\n</table>",
|
||||||
"modified": "2021-05-24 16:29:13.165930",
|
"modified": "2021-06-16 14:08:12.933367",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Training Scheduled",
|
"name": "Training Scheduled",
|
||||||
|
@ -29,14 +29,14 @@
|
|||||||
{{_("Timing")}}: <b>{{ start.strftime("%I:%M %p") + ' to ' + end.strftime("%I:%M %p") }}</b>
|
{{_("Timing")}}: <b>{{ start.strftime("%I:%M %p") + ' to ' + end.strftime("%I:%M %p") }}</b>
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li>{{_("Start Time")}}: <b>{{ start.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
|
<li>
|
||||||
</li>
|
{{_("Start Time")}}: <b>{{ start.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
|
||||||
<li>{{_("End Time")}}: <b>{{ end.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
|
|
||||||
</li>
|
</li>
|
||||||
|
<li>{{_("End Time")}}: <b>{{ end.strftime("%A, %d %b %Y at %I:%M %p") }}</b></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li>{{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}</li>
|
<li>{{ _("Event Link") }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}</li>
|
||||||
{% if doc.is_mandatory %}
|
{% if doc.is_mandatory %}
|
||||||
<li>Note: This Training Event is mandatory</li>
|
<li>{{ _("Note: This Training Event is mandatory") }}</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -178,7 +178,7 @@ def get_allocated_and_expired_leaves(from_date, to_date, employee, leave_type):
|
|||||||
is_carry_forward, is_expired
|
is_carry_forward, is_expired
|
||||||
FROM `tabLeave Ledger Entry`
|
FROM `tabLeave Ledger Entry`
|
||||||
WHERE employee=%(employee)s AND leave_type=%(leave_type)s
|
WHERE employee=%(employee)s AND leave_type=%(leave_type)s
|
||||||
AND docstatus=1 AND leaves>0
|
AND docstatus=1
|
||||||
AND (from_date between %(from_date)s AND %(to_date)s
|
AND (from_date between %(from_date)s AND %(to_date)s
|
||||||
OR to_date between %(from_date)s AND %(to_date)s
|
OR to_date between %(from_date)s AND %(to_date)s
|
||||||
OR (from_date < %(from_date)s AND to_date > %(to_date)s))
|
OR (from_date < %(from_date)s AND to_date > %(to_date)s))
|
||||||
|
@ -153,6 +153,24 @@
|
|||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Grievance Type",
|
||||||
|
"link_to": "Grievance Type",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Employee Grievance",
|
||||||
|
"link_to": "Employee Grievance",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"dependencies": "Employee",
|
"dependencies": "Employee",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -823,7 +841,7 @@
|
|||||||
"type": "Link"
|
"type": "Link"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2021-04-26 13:36:15.413819",
|
"modified": "2021-05-13 17:19:40.524444",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "HR",
|
"name": "HR",
|
||||||
|
@ -704,6 +704,8 @@ erpnext.work_order = {
|
|||||||
stop_work_order: function(frm, status) {
|
stop_work_order: function(frm, status) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.manufacturing.doctype.work_order.work_order.stop_unstop",
|
method: "erpnext.manufacturing.doctype.work_order.work_order.stop_unstop",
|
||||||
|
freeze: true,
|
||||||
|
freeze_message: __("Updating Work Order status"),
|
||||||
args: {
|
args: {
|
||||||
work_order: frm.doc.name,
|
work_order: frm.doc.name,
|
||||||
status: status
|
status: status
|
||||||
|
@ -288,4 +288,5 @@ execute:frappe.rename_doc("Workspace", "Loan Management", "Loans", force=True)
|
|||||||
erpnext.patches.v13_0.update_timesheet_changes
|
erpnext.patches.v13_0.update_timesheet_changes
|
||||||
erpnext.patches.v13_0.add_doctype_to_sla #14-06-2021
|
erpnext.patches.v13_0.add_doctype_to_sla #14-06-2021
|
||||||
erpnext.patches.v13_0.set_training_event_attendance
|
erpnext.patches.v13_0.set_training_event_attendance
|
||||||
|
erpnext.patches.v13_0.bill_for_rejected_quantity_in_purchase_invoice
|
||||||
erpnext.patches.v13_0.rename_issue_status_hold_to_on_hold
|
erpnext.patches.v13_0.rename_issue_status_hold_to_on_hold
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doctype("Buying Settings")
|
||||||
|
buying_settings = frappe.get_single("Buying Settings")
|
||||||
|
buying_settings.bill_for_rejected_quantity_in_purchase_invoice = 0
|
||||||
|
buying_settings.save()
|
@ -12,8 +12,12 @@ frappe.ui.form.on('Additional Salary', {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
frm.trigger('set_earning_component');
|
onload: function(frm) {
|
||||||
|
if (frm.doc.type) {
|
||||||
|
frm.trigger('set_component_query');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
employee: function(frm) {
|
employee: function(frm) {
|
||||||
@ -46,14 +50,19 @@ frappe.ui.form.on('Additional Salary', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
company: function(frm) {
|
company: function(frm) {
|
||||||
frm.trigger('set_earning_component');
|
frm.set_value("type", "");
|
||||||
|
frm.trigger('set_component_query');
|
||||||
},
|
},
|
||||||
|
|
||||||
set_earning_component: function(frm) {
|
set_component_query: function(frm) {
|
||||||
if (!frm.doc.company) return;
|
if (!frm.doc.company) return;
|
||||||
|
let filters = {company: frm.doc.company};
|
||||||
|
if (frm.doc.type) {
|
||||||
|
filters.type = frm.doc.type;
|
||||||
|
}
|
||||||
frm.set_query("salary_component", function() {
|
frm.set_query("salary_component", function() {
|
||||||
return {
|
return {
|
||||||
filters: {type: ["in", ["earning", "deduction"]], company: frm.doc.company}
|
filters: filters
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -11,6 +11,7 @@ from frappe import _
|
|||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
||||||
from frappe.desk.reportview import get_match_cond, get_filters_cond
|
from frappe.desk.reportview import get_match_cond, get_filters_cond
|
||||||
|
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||||
|
|
||||||
class PayrollEntry(Document):
|
class PayrollEntry(Document):
|
||||||
def onload(self):
|
def onload(self):
|
||||||
@ -211,7 +212,7 @@ class PayrollEntry(Document):
|
|||||||
return account_dict
|
return account_dict
|
||||||
|
|
||||||
def make_accrual_jv_entry(self):
|
def make_accrual_jv_entry(self):
|
||||||
self.check_permission('write')
|
self.check_permission("write")
|
||||||
earnings = self.get_salary_component_total(component_type = "earnings") or {}
|
earnings = self.get_salary_component_total(component_type = "earnings") or {}
|
||||||
deductions = self.get_salary_component_total(component_type = "deductions") or {}
|
deductions = self.get_salary_component_total(component_type = "deductions") or {}
|
||||||
payroll_payable_account = self.payroll_payable_account
|
payroll_payable_account = self.payroll_payable_account
|
||||||
@ -219,12 +220,13 @@ class PayrollEntry(Document):
|
|||||||
precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
|
precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
|
||||||
|
|
||||||
if earnings or deductions:
|
if earnings or deductions:
|
||||||
journal_entry = frappe.new_doc('Journal Entry')
|
journal_entry = frappe.new_doc("Journal Entry")
|
||||||
journal_entry.voucher_type = 'Journal Entry'
|
journal_entry.voucher_type = "Journal Entry"
|
||||||
journal_entry.user_remark = _('Accrual Journal Entry for salaries from {0} to {1}')\
|
journal_entry.user_remark = _("Accrual Journal Entry for salaries from {0} to {1}")\
|
||||||
.format(self.start_date, self.end_date)
|
.format(self.start_date, self.end_date)
|
||||||
journal_entry.company = self.company
|
journal_entry.company = self.company
|
||||||
journal_entry.posting_date = self.posting_date
|
journal_entry.posting_date = self.posting_date
|
||||||
|
accounting_dimensions = get_accounting_dimensions() or []
|
||||||
|
|
||||||
accounts = []
|
accounts = []
|
||||||
currencies = []
|
currencies = []
|
||||||
@ -236,37 +238,34 @@ class PayrollEntry(Document):
|
|||||||
for acc_cc, amount in earnings.items():
|
for acc_cc, amount in earnings.items():
|
||||||
exchange_rate, amt = self.get_amount_and_exchange_rate_for_journal_entry(acc_cc[0], amount, company_currency, currencies)
|
exchange_rate, amt = self.get_amount_and_exchange_rate_for_journal_entry(acc_cc[0], amount, company_currency, currencies)
|
||||||
payable_amount += flt(amount, precision)
|
payable_amount += flt(amount, precision)
|
||||||
accounts.append({
|
accounts.append(self.update_accounting_dimensions({
|
||||||
"account": acc_cc[0],
|
"account": acc_cc[0],
|
||||||
"debit_in_account_currency": flt(amt, precision),
|
"debit_in_account_currency": flt(amt, precision),
|
||||||
"exchange_rate": flt(exchange_rate),
|
"exchange_rate": flt(exchange_rate),
|
||||||
"party_type": '',
|
|
||||||
"cost_center": acc_cc[1] or self.cost_center,
|
"cost_center": acc_cc[1] or self.cost_center,
|
||||||
"project": self.project
|
"project": self.project
|
||||||
})
|
}, accounting_dimensions))
|
||||||
|
|
||||||
# Deductions
|
# Deductions
|
||||||
for acc_cc, amount in deductions.items():
|
for acc_cc, amount in deductions.items():
|
||||||
exchange_rate, amt = self.get_amount_and_exchange_rate_for_journal_entry(acc_cc[0], amount, company_currency, currencies)
|
exchange_rate, amt = self.get_amount_and_exchange_rate_for_journal_entry(acc_cc[0], amount, company_currency, currencies)
|
||||||
payable_amount -= flt(amount, precision)
|
payable_amount -= flt(amount, precision)
|
||||||
accounts.append({
|
accounts.append(self.update_accounting_dimensions({
|
||||||
"account": acc_cc[0],
|
"account": acc_cc[0],
|
||||||
"credit_in_account_currency": flt(amt, precision),
|
"credit_in_account_currency": flt(amt, precision),
|
||||||
"exchange_rate": flt(exchange_rate),
|
"exchange_rate": flt(exchange_rate),
|
||||||
"cost_center": acc_cc[1] or self.cost_center,
|
"cost_center": acc_cc[1] or self.cost_center,
|
||||||
"party_type": '',
|
|
||||||
"project": self.project
|
"project": self.project
|
||||||
})
|
}, accounting_dimensions))
|
||||||
|
|
||||||
# Payable amount
|
# Payable amount
|
||||||
exchange_rate, payable_amt = self.get_amount_and_exchange_rate_for_journal_entry(payroll_payable_account, payable_amount, company_currency, currencies)
|
exchange_rate, payable_amt = self.get_amount_and_exchange_rate_for_journal_entry(payroll_payable_account, payable_amount, company_currency, currencies)
|
||||||
accounts.append({
|
accounts.append(self.update_accounting_dimensions({
|
||||||
"account": payroll_payable_account,
|
"account": payroll_payable_account,
|
||||||
"credit_in_account_currency": flt(payable_amt, precision),
|
"credit_in_account_currency": flt(payable_amt, precision),
|
||||||
"exchange_rate": flt(exchange_rate),
|
"exchange_rate": flt(exchange_rate),
|
||||||
"party_type": '',
|
|
||||||
"cost_center": self.cost_center
|
"cost_center": self.cost_center
|
||||||
})
|
}, accounting_dimensions))
|
||||||
|
|
||||||
journal_entry.set("accounts", accounts)
|
journal_entry.set("accounts", accounts)
|
||||||
if len(currencies) > 1:
|
if len(currencies) > 1:
|
||||||
@ -286,6 +285,12 @@ class PayrollEntry(Document):
|
|||||||
|
|
||||||
return jv_name
|
return jv_name
|
||||||
|
|
||||||
|
def update_accounting_dimensions(self, row, accounting_dimensions):
|
||||||
|
for dimension in accounting_dimensions:
|
||||||
|
row.update({dimension: self.get(dimension)})
|
||||||
|
|
||||||
|
return row
|
||||||
|
|
||||||
def get_amount_and_exchange_rate_for_journal_entry(self, account, amount, company_currency, currencies):
|
def get_amount_and_exchange_rate_for_journal_entry(self, account, amount, company_currency, currencies):
|
||||||
conversion_rate = 1
|
conversion_rate = 1
|
||||||
exchange_rate = self.exchange_rate
|
exchange_rate = self.exchange_rate
|
||||||
|
@ -481,6 +481,7 @@ def make_employee_salary_slip(user, payroll_frequency, salary_structure=None):
|
|||||||
if not salary_structure:
|
if not salary_structure:
|
||||||
salary_structure = payroll_frequency + " Salary Structure Test for Salary Slip"
|
salary_structure = payroll_frequency + " Salary Structure Test for Salary Slip"
|
||||||
|
|
||||||
|
|
||||||
employee = frappe.db.get_value("Employee", {"user_id": user})
|
employee = frappe.db.get_value("Employee", {"user_id": user})
|
||||||
salary_structure_doc = make_salary_structure(salary_structure, payroll_frequency, employee=employee)
|
salary_structure_doc = make_salary_structure(salary_structure, payroll_frequency, employee=employee)
|
||||||
salary_slip_name = frappe.db.get_value("Salary Slip", {"employee": frappe.db.get_value("Employee", {"user_id": user})})
|
salary_slip_name = frappe.db.get_value("Salary Slip", {"employee": frappe.db.get_value("Employee", {"user_id": user})})
|
||||||
|
@ -124,8 +124,8 @@ def make_salary_structure(salary_structure, payroll_frequency, employee=None,
|
|||||||
"doctype": "Salary Structure",
|
"doctype": "Salary Structure",
|
||||||
"name": salary_structure,
|
"name": salary_structure,
|
||||||
"company": company or erpnext.get_default_company(),
|
"company": company or erpnext.get_default_company(),
|
||||||
"earnings": make_earning_salary_component(test_tax=test_tax, company_list=["_Test Company"]),
|
"earnings": make_earning_salary_component(setup=True, test_tax=test_tax, company_list=["_Test Company"]),
|
||||||
"deductions": make_deduction_salary_component(test_tax=test_tax, company_list=["_Test Company"]),
|
"deductions": make_deduction_salary_component(setup=True, test_tax=test_tax, company_list=["_Test Company"]),
|
||||||
"payroll_frequency": payroll_frequency,
|
"payroll_frequency": payroll_frequency,
|
||||||
"payment_account": get_random("Account", filters={'account_currency': currency}),
|
"payment_account": get_random("Account", filters={'account_currency': currency}),
|
||||||
"currency": currency
|
"currency": currency
|
||||||
|
@ -888,9 +888,6 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.frm.doc.posting_date) var date = this.frm.doc.posting_date;
|
|
||||||
else var date = this.frm.doc.transaction_date;
|
|
||||||
|
|
||||||
if (frappe.meta.get_docfield(this.frm.doctype, "shipping_address") &&
|
if (frappe.meta.get_docfield(this.frm.doctype, "shipping_address") &&
|
||||||
in_list(['Purchase Order', 'Purchase Receipt', 'Purchase Invoice'], this.frm.doctype)) {
|
in_list(['Purchase Order', 'Purchase Receipt', 'Purchase Invoice'], this.frm.doctype)) {
|
||||||
erpnext.utils.get_shipping_address(this.frm, function(){
|
erpnext.utils.get_shipping_address(this.frm, function(){
|
||||||
|
@ -59,7 +59,7 @@ def get_data(conditions, filters):
|
|||||||
IF(so.status in ('Completed','To Bill'), 0, (SELECT delay_days)) as delay,
|
IF(so.status in ('Completed','To Bill'), 0, (SELECT delay_days)) as delay,
|
||||||
soi.qty, soi.delivered_qty,
|
soi.qty, soi.delivered_qty,
|
||||||
(soi.qty - soi.delivered_qty) AS pending_qty,
|
(soi.qty - soi.delivered_qty) AS pending_qty,
|
||||||
IFNULL(sii.qty, 0) as billed_qty,
|
IFNULL(SUM(sii.qty), 0) as billed_qty,
|
||||||
soi.base_amount as amount,
|
soi.base_amount as amount,
|
||||||
(soi.delivered_qty * soi.base_rate) as delivered_qty_amount,
|
(soi.delivered_qty * soi.base_rate) as delivered_qty_amount,
|
||||||
(soi.billed_amt * IFNULL(so.conversion_rate, 1)) as billed_amount,
|
(soi.billed_amt * IFNULL(so.conversion_rate, 1)) as billed_amount,
|
||||||
|
@ -581,7 +581,6 @@ def update_billing_percentage(pr_doc, update_modified=True):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_purchase_invoice(source_name, target_doc=None):
|
def make_purchase_invoice(source_name, target_doc=None):
|
||||||
from frappe.model.mapper import get_mapped_doc
|
|
||||||
from erpnext.accounts.party import get_payment_terms_template
|
from erpnext.accounts.party import get_payment_terms_template
|
||||||
|
|
||||||
doc = frappe.get_doc('Purchase Receipt', source_name)
|
doc = frappe.get_doc('Purchase Receipt', source_name)
|
||||||
@ -601,11 +600,16 @@ def make_purchase_invoice(source_name, target_doc=None):
|
|||||||
|
|
||||||
def update_item(source_doc, target_doc, source_parent):
|
def update_item(source_doc, target_doc, source_parent):
|
||||||
target_doc.qty, returned_qty = get_pending_qty(source_doc)
|
target_doc.qty, returned_qty = get_pending_qty(source_doc)
|
||||||
|
if frappe.db.get_single_value("Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice"):
|
||||||
|
target_doc.rejected_qty = 0
|
||||||
target_doc.stock_qty = flt(target_doc.qty) * flt(target_doc.conversion_factor, target_doc.precision("conversion_factor"))
|
target_doc.stock_qty = flt(target_doc.qty) * flt(target_doc.conversion_factor, target_doc.precision("conversion_factor"))
|
||||||
returned_qty_map[source_doc.name] = returned_qty
|
returned_qty_map[source_doc.name] = returned_qty
|
||||||
|
|
||||||
def get_pending_qty(item_row):
|
def get_pending_qty(item_row):
|
||||||
pending_qty = item_row.qty - invoiced_qty_map.get(item_row.name, 0)
|
qty = item_row.qty
|
||||||
|
if frappe.db.get_single_value("Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice"):
|
||||||
|
qty = item_row.received_qty
|
||||||
|
pending_qty = qty - invoiced_qty_map.get(item_row.name, 0)
|
||||||
returned_qty = flt(returned_qty_map.get(item_row.name, 0))
|
returned_qty = flt(returned_qty_map.get(item_row.name, 0))
|
||||||
if returned_qty:
|
if returned_qty:
|
||||||
if returned_qty >= pending_qty:
|
if returned_qty >= pending_qty:
|
||||||
|
@ -421,11 +421,18 @@ class TestPurchaseReceipt(unittest.TestCase):
|
|||||||
self.assertEqual(return_pr_2.items[0].qty, -3)
|
self.assertEqual(return_pr_2.items[0].qty, -3)
|
||||||
|
|
||||||
# Make PI against unreturned amount
|
# Make PI against unreturned amount
|
||||||
|
buying_settings = frappe.get_single("Buying Settings")
|
||||||
|
buying_settings.bill_for_rejected_quantity_in_purchase_invoice = 0
|
||||||
|
buying_settings.save()
|
||||||
|
|
||||||
pi = make_purchase_invoice(pr.name)
|
pi = make_purchase_invoice(pr.name)
|
||||||
pi.submit()
|
pi.submit()
|
||||||
|
|
||||||
self.assertEqual(pi.items[0].qty, 3)
|
self.assertEqual(pi.items[0].qty, 3)
|
||||||
|
|
||||||
|
buying_settings.bill_for_rejected_quantity_in_purchase_invoice = 1
|
||||||
|
buying_settings.save()
|
||||||
|
|
||||||
pr.load_from_db()
|
pr.load_from_db()
|
||||||
# PR should be completed on billing all unreturned amount
|
# PR should be completed on billing all unreturned amount
|
||||||
self.assertEqual(pr.items[0].billed_amt, 150)
|
self.assertEqual(pr.items[0].billed_amt, 150)
|
||||||
@ -767,8 +774,8 @@ class TestPurchaseReceipt(unittest.TestCase):
|
|||||||
pr1.items[0].purchase_receipt_item = pr.items[0].name
|
pr1.items[0].purchase_receipt_item = pr.items[0].name
|
||||||
pr1.submit()
|
pr1.submit()
|
||||||
|
|
||||||
pi = make_purchase_invoice(pr.name)
|
pi1 = make_purchase_invoice(pr.name)
|
||||||
self.assertEqual(pi.items[0].qty, 3)
|
self.assertEqual(pi1.items[0].qty, 3)
|
||||||
|
|
||||||
pr1.cancel()
|
pr1.cancel()
|
||||||
pr.reload()
|
pr.reload()
|
||||||
|
@ -22,10 +22,10 @@ frappe.query_reports["First Response Time for Issues"] = {
|
|||||||
get_chart_data: function(_columns, result) {
|
get_chart_data: function(_columns, result) {
|
||||||
return {
|
return {
|
||||||
data: {
|
data: {
|
||||||
labels: result.map(d => d[0]),
|
labels: result.map(d => d.creation_date),
|
||||||
datasets: [{
|
datasets: [{
|
||||||
name: 'First Response Time',
|
name: 'First Response Time',
|
||||||
values: result.map(d => d[1])
|
values: result.map(d => d.first_response_time)
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
type: "line",
|
type: "line",
|
||||||
@ -35,8 +35,7 @@ frappe.query_reports["First Response Time for Issues"] = {
|
|||||||
hide_days: 0,
|
hide_days: 0,
|
||||||
hide_seconds: 0
|
hide_seconds: 0
|
||||||
};
|
};
|
||||||
value = frappe.utils.get_formatted_duration(d, duration_options);
|
return frappe.utils.get_formatted_duration(d, duration_options);
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user