Merge branch 'develop' into sla-enhancements
This commit is contained in:
commit
bf26b10df4
@ -14,6 +14,9 @@ frappe.treeview_settings["Account"] = {
|
|||||||
on_change: function() {
|
on_change: function() {
|
||||||
var me = frappe.treeview_settings['Account'].treeview;
|
var me = frappe.treeview_settings['Account'].treeview;
|
||||||
var company = me.page.fields_dict.company.get_value();
|
var company = me.page.fields_dict.company.get_value();
|
||||||
|
if (!company) {
|
||||||
|
frappe.throw(__("Please set a Company"));
|
||||||
|
}
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.accounts.doctype.account.account.get_root_company",
|
method: "erpnext.accounts.doctype.account.account.get_root_company",
|
||||||
args: {
|
args: {
|
||||||
|
@ -349,9 +349,10 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"in_create": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-05-08 10:23:02.815237",
|
"modified": "2020-05-29 17:38:49.392713",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Request",
|
"name": "Payment Request",
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -582,14 +582,14 @@ class SalesInvoice(SellingController):
|
|||||||
|
|
||||||
def validate_item_code(self):
|
def validate_item_code(self):
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if not d.item_code:
|
if not d.item_code and self.is_opening == "No":
|
||||||
msgprint(_("Item Code required at Row No {0}").format(d.idx), raise_exception=True)
|
msgprint(_("Item Code required at Row No {0}").format(d.idx), raise_exception=True)
|
||||||
|
|
||||||
def validate_warehouse(self):
|
def validate_warehouse(self):
|
||||||
super(SalesInvoice, self).validate_warehouse()
|
super(SalesInvoice, self).validate_warehouse()
|
||||||
|
|
||||||
for d in self.get_item_list():
|
for d in self.get_item_list():
|
||||||
if not d.warehouse and frappe.get_cached_value("Item", d.item_code, "is_stock_item"):
|
if not d.warehouse and d.item_code and frappe.get_cached_value("Item", d.item_code, "is_stock_item"):
|
||||||
frappe.throw(_("Warehouse required for stock Item {0}").format(d.item_code))
|
frappe.throw(_("Warehouse required for stock Item {0}").format(d.item_code))
|
||||||
|
|
||||||
def validate_delivery_note(self):
|
def validate_delivery_note(self):
|
||||||
|
@ -56,9 +56,8 @@ def get_period_list(from_fiscal_year, to_fiscal_year, period_start_date, period_
|
|||||||
to_date = add_months(start_date, months_to_add)
|
to_date = add_months(start_date, months_to_add)
|
||||||
start_date = to_date
|
start_date = to_date
|
||||||
|
|
||||||
if to_date == get_first_day(to_date):
|
# Subtract one day from to_date, as it may be first day in next fiscal year or month
|
||||||
# if to_date is the first day, get the last day of previous month
|
to_date = add_days(to_date, -1)
|
||||||
to_date = add_days(to_date, -1)
|
|
||||||
|
|
||||||
if to_date <= year_end_date:
|
if to_date <= year_end_date:
|
||||||
# the normal case
|
# the normal case
|
||||||
@ -406,6 +405,7 @@ def set_gl_entries_by_account(
|
|||||||
FROM `tabDistributed Cost Center`
|
FROM `tabDistributed Cost Center`
|
||||||
WHERE cost_center IN %(cost_center)s
|
WHERE cost_center IN %(cost_center)s
|
||||||
AND parent NOT IN %(cost_center)s
|
AND parent NOT IN %(cost_center)s
|
||||||
|
AND is_cancelled = 0
|
||||||
GROUP BY parent
|
GROUP BY parent
|
||||||
) as DCC_allocation
|
) as DCC_allocation
|
||||||
WHERE company=%(company)s
|
WHERE company=%(company)s
|
||||||
@ -418,6 +418,7 @@ def set_gl_entries_by_account(
|
|||||||
where company=%(company)s
|
where company=%(company)s
|
||||||
{additional_conditions}
|
{additional_conditions}
|
||||||
and posting_date <= %(to_date)s
|
and posting_date <= %(to_date)s
|
||||||
|
and is_cancelled = 0
|
||||||
{distributed_cost_center_query}
|
{distributed_cost_center_query}
|
||||||
order by account, posting_date""".format(
|
order by account, posting_date""".format(
|
||||||
additional_conditions=additional_conditions,
|
additional_conditions=additional_conditions,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,8 @@ class QualityInspectionNotSubmittedError(frappe.ValidationError): pass
|
|||||||
class StockController(AccountsController):
|
class StockController(AccountsController):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
super(StockController, self).validate()
|
super(StockController, self).validate()
|
||||||
self.validate_inspection()
|
if not self.get('is_return'):
|
||||||
|
self.validate_inspection()
|
||||||
self.validate_serialized_batch()
|
self.validate_serialized_batch()
|
||||||
self.validate_customer_provided_item()
|
self.validate_customer_provided_item()
|
||||||
|
|
||||||
|
@ -3,11 +3,7 @@ from frappe import _
|
|||||||
|
|
||||||
def get_data():
|
def get_data():
|
||||||
return {
|
return {
|
||||||
'fieldname': 'prevdoc_docname',
|
'fieldname': 'opportunity',
|
||||||
'non_standard_fieldnames': {
|
|
||||||
'Supplier Quotation': 'opportunity',
|
|
||||||
'Quotation': 'opportunity'
|
|
||||||
},
|
|
||||||
'transactions': [
|
'transactions': [
|
||||||
{
|
{
|
||||||
'items': ['Quotation', 'Supplier Quotation']
|
'items': ['Quotation', 'Supplier Quotation']
|
||||||
|
@ -30,24 +30,32 @@
|
|||||||
"fieldname": "text",
|
"fieldname": "text",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Tweet",
|
"label": "Tweet",
|
||||||
"mandatory_depends_on": "eval:doc.twitter ==1"
|
"mandatory_depends_on": "eval:doc.twitter ==1",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "image",
|
"fieldname": "image",
|
||||||
"fieldtype": "Attach Image",
|
"fieldtype": "Attach Image",
|
||||||
"label": "Image"
|
"label": "Image",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "twitter",
|
"fieldname": "twitter",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Twitter"
|
"label": "Twitter",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "linkedin",
|
"fieldname": "linkedin",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "LinkedIn"
|
"label": "LinkedIn",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "amended_from",
|
"fieldname": "amended_from",
|
||||||
@ -56,13 +64,17 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Social Media Post",
|
"options": "Social Media Post",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.twitter ==1",
|
"depends_on": "eval:doc.twitter ==1",
|
||||||
"fieldname": "content",
|
"fieldname": "content",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Twitter"
|
"label": "Twitter",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
@ -70,7 +82,9 @@
|
|||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Post Status",
|
"label": "Post Status",
|
||||||
"options": "\nScheduled\nPosted\nError",
|
"options": "\nScheduled\nPosted\nError",
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
@ -78,7 +92,9 @@
|
|||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"label": "Twitter Post Id",
|
"label": "Twitter Post Id",
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
@ -86,68 +102,89 @@
|
|||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"label": "LinkedIn Post Id",
|
"label": "LinkedIn Post Id",
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "campaign_name",
|
"fieldname": "campaign_name",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Campaign",
|
"label": "Campaign",
|
||||||
"options": "Campaign"
|
"options": "Campaign",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_6",
|
"fieldname": "column_break_6",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"label": "Share On"
|
"label": "Share On",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_14",
|
"fieldname": "column_break_14",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "tweet_preview",
|
"fieldname": "tweet_preview",
|
||||||
"fieldtype": "HTML"
|
"fieldtype": "HTML",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"depends_on": "eval:doc.linkedin==1",
|
"depends_on": "eval:doc.linkedin==1",
|
||||||
"fieldname": "linkedin_section",
|
"fieldname": "linkedin_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "LinkedIn"
|
"label": "LinkedIn",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "attachments_section",
|
"fieldname": "attachments_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Attachments"
|
"label": "Attachments",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "linkedin_post",
|
"fieldname": "linkedin_post",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Text",
|
||||||
"label": "Post",
|
"label": "Post",
|
||||||
"mandatory_depends_on": "eval:doc.linkedin ==1"
|
"mandatory_depends_on": "eval:doc.linkedin ==1",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_15",
|
"fieldname": "column_break_15",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"fieldname": "scheduled_time",
|
"fieldname": "scheduled_time",
|
||||||
"fieldtype": "Datetime",
|
"fieldtype": "Datetime",
|
||||||
"label": "Scheduled Time",
|
"label": "Scheduled Time",
|
||||||
"read_only_depends_on": "eval:doc.post_status == \"Posted\""
|
"read_only_depends_on": "eval:doc.post_status == \"Posted\"",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-04-21 15:10:04.953713",
|
"modified": "2020-06-14 10:31:33.961381",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Social Media Post",
|
"name": "Social Media Post",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
@ -157,6 +194,35 @@
|
|||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "System Manager",
|
"role": "System Manager",
|
||||||
"share": 1,
|
"share": 1,
|
||||||
|
"submit": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cancel": 1,
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Sales User",
|
||||||
|
"share": 1,
|
||||||
|
"submit": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cancel": 1,
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Sales Manager",
|
||||||
|
"share": 1,
|
||||||
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -19,11 +19,15 @@
|
|||||||
"attendance_date",
|
"attendance_date",
|
||||||
"company",
|
"company",
|
||||||
"department",
|
"department",
|
||||||
"shift",
|
|
||||||
"attendance_request",
|
"attendance_request",
|
||||||
"amended_from",
|
"details_section",
|
||||||
|
"shift",
|
||||||
|
"in_time",
|
||||||
|
"out_time",
|
||||||
|
"column_break_18",
|
||||||
"late_entry",
|
"late_entry",
|
||||||
"early_exit"
|
"early_exit",
|
||||||
|
"amended_from"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -172,13 +176,36 @@
|
|||||||
"fieldname": "early_exit",
|
"fieldname": "early_exit",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Early Exit"
|
"label": "Early Exit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "details_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Details"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "shift",
|
||||||
|
"fieldname": "in_time",
|
||||||
|
"fieldtype": "Datetime",
|
||||||
|
"label": "In Time",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "shift",
|
||||||
|
"fieldname": "out_time",
|
||||||
|
"fieldtype": "Datetime",
|
||||||
|
"label": "Out Time",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_18",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-ok",
|
"icon": "fa fa-ok",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-04-11 11:40:14.319496",
|
"modified": "2020-05-29 13:51:37.177231",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Attendance",
|
"name": "Attendance",
|
||||||
|
@ -139,13 +139,13 @@ frappe.ui.form.on('Employee Advance', {
|
|||||||
employee: function (frm) {
|
employee: function (frm) {
|
||||||
if (frm.doc.employee) {
|
if (frm.doc.employee) {
|
||||||
return frappe.call({
|
return frappe.call({
|
||||||
method: "erpnext.hr.doctype.employee_advance.employee_advance.get_due_advance_amount",
|
method: "erpnext.hr.doctype.employee_advance.employee_advance.get_pending_amount",
|
||||||
args: {
|
args: {
|
||||||
"employee": frm.doc.employee,
|
"employee": frm.doc.employee,
|
||||||
"posting_date": frm.doc.posting_date
|
"posting_date": frm.doc.posting_date
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
frm.set_value("due_advance_amount",r.message);
|
frm.set_value("pending_amount",r.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
"column_break_11",
|
"column_break_11",
|
||||||
"advance_amount",
|
"advance_amount",
|
||||||
"paid_amount",
|
"paid_amount",
|
||||||
"due_advance_amount",
|
"pending_amount",
|
||||||
"claimed_amount",
|
"claimed_amount",
|
||||||
"return_amount",
|
"return_amount",
|
||||||
"section_break_7",
|
"section_break_7",
|
||||||
@ -102,14 +102,6 @@
|
|||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"depends_on": "eval:cur_frm.doc.employee",
|
|
||||||
"fieldname": "due_advance_amount",
|
|
||||||
"fieldtype": "Currency",
|
|
||||||
"label": "Due Advance Amount",
|
|
||||||
"options": "Company:company:default_currency",
|
|
||||||
"read_only": 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "claimed_amount",
|
"fieldname": "claimed_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
@ -177,11 +169,19 @@
|
|||||||
"fieldname": "repay_unclaimed_amount_from_salary",
|
"fieldname": "repay_unclaimed_amount_from_salary",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Repay unclaimed amount from salary"
|
"label": "Repay unclaimed amount from salary"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:cur_frm.doc.employee",
|
||||||
|
"fieldname": "pending_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Pending Amount",
|
||||||
|
"options": "Company:company:default_currency",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-03-06 15:11:33.747535",
|
"modified": "2020-06-12 12:42:39.833818",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Employee Advance",
|
"name": "Employee Advance",
|
||||||
|
@ -95,7 +95,7 @@ class EmployeeAdvance(Document):
|
|||||||
frappe.db.set_value("Employee Advance", self.name, "status", self.status)
|
frappe.db.set_value("Employee Advance", self.name, "status", self.status)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_due_advance_amount(employee, posting_date):
|
def get_pending_amount(employee, posting_date):
|
||||||
employee_due_amount = frappe.get_all("Employee Advance", \
|
employee_due_amount = frappe.get_all("Employee Advance", \
|
||||||
filters = {"employee":employee, "docstatus":1, "posting_date":("<=", posting_date)}, \
|
filters = {"employee":employee, "docstatus":1, "posting_date":("<=", posting_date)}, \
|
||||||
fields = ["advance_amount", "paid_amount"])
|
fields = ["advance_amount", "paid_amount"])
|
||||||
|
@ -72,7 +72,7 @@ def add_log_based_on_employee_field(employee_field_value, timestamp, device_id=N
|
|||||||
return doc
|
return doc
|
||||||
|
|
||||||
|
|
||||||
def mark_attendance_and_link_log(logs, attendance_status, attendance_date, working_hours=None, late_entry=False, early_exit=False, shift=None):
|
def mark_attendance_and_link_log(logs, attendance_status, attendance_date, working_hours=None, late_entry=False, early_exit=False, in_time=None, out_time=None, shift=None):
|
||||||
"""Creates an attendance and links the attendance to the Employee Checkin.
|
"""Creates an attendance and links the attendance to the Employee Checkin.
|
||||||
Note: If attendance is already present for the given date, the logs are marked as skipped and no exception is thrown.
|
Note: If attendance is already present for the given date, the logs are marked as skipped and no exception is thrown.
|
||||||
|
|
||||||
@ -100,7 +100,9 @@ def mark_attendance_and_link_log(logs, attendance_status, attendance_date, worki
|
|||||||
'company': employee_doc.company,
|
'company': employee_doc.company,
|
||||||
'shift': shift,
|
'shift': shift,
|
||||||
'late_entry': late_entry,
|
'late_entry': late_entry,
|
||||||
'early_exit': early_exit
|
'early_exit': early_exit,
|
||||||
|
'in_time': in_time,
|
||||||
|
'out_time': out_time
|
||||||
}
|
}
|
||||||
attendance = frappe.get_doc(doc_dict).insert()
|
attendance = frappe.get_doc(doc_dict).insert()
|
||||||
attendance.submit()
|
attendance.submit()
|
||||||
|
@ -46,6 +46,7 @@ frappe.ui.form.on("Leave Application", {
|
|||||||
|
|
||||||
make_dashboard: function(frm) {
|
make_dashboard: function(frm) {
|
||||||
var leave_details;
|
var leave_details;
|
||||||
|
let lwps;
|
||||||
if (frm.doc.employee) {
|
if (frm.doc.employee) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.hr.doctype.leave_application.leave_application.get_leave_details",
|
method: "erpnext.hr.doctype.leave_application.leave_application.get_leave_details",
|
||||||
@ -61,6 +62,7 @@ frappe.ui.form.on("Leave Application", {
|
|||||||
if (!r.exc && r.message['leave_approver']) {
|
if (!r.exc && r.message['leave_approver']) {
|
||||||
frm.set_value('leave_approver', r.message['leave_approver']);
|
frm.set_value('leave_approver', r.message['leave_approver']);
|
||||||
}
|
}
|
||||||
|
lwps = r.message["lwps"];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$("div").remove(".form-dashboard-section.custom");
|
$("div").remove(".form-dashboard-section.custom");
|
||||||
@ -70,12 +72,17 @@ frappe.ui.form.on("Leave Application", {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
frm.dashboard.show();
|
frm.dashboard.show();
|
||||||
|
let allowed_leave_types = Object.keys(leave_details);
|
||||||
|
|
||||||
|
// lwps should be allowed, lwps don't have any allocation
|
||||||
|
allowed_leave_types = allowed_leave_types.concat(lwps);
|
||||||
|
|
||||||
frm.set_query('leave_type', function(){
|
frm.set_query('leave_type', function(){
|
||||||
return {
|
return {
|
||||||
filters : [
|
filters : [
|
||||||
['leave_type_name', 'in', Object.keys(leave_details)]
|
['leave_type_name', 'in', allowed_leave_types]
|
||||||
]
|
]
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -19,7 +19,6 @@ class NotAnOptionalHoliday(frappe.ValidationError): pass
|
|||||||
|
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
class LeaveApplication(Document):
|
class LeaveApplication(Document):
|
||||||
|
|
||||||
def get_feed(self):
|
def get_feed(self):
|
||||||
return _("{0}: From {0} of type {1}").format(self.employee_name, self.leave_type)
|
return _("{0}: From {0} of type {1}").format(self.employee_name, self.leave_type)
|
||||||
|
|
||||||
@ -463,9 +462,14 @@ def get_leave_details(employee, date):
|
|||||||
"pending_leaves": leaves_pending,
|
"pending_leaves": leaves_pending,
|
||||||
"remaining_leaves": remaining_leaves}
|
"remaining_leaves": remaining_leaves}
|
||||||
|
|
||||||
|
#is used in set query
|
||||||
|
lwps = frappe.get_list("Leave Type", filters = {"is_lwp": 1})
|
||||||
|
lwps = [lwp.name for lwp in lwps]
|
||||||
|
|
||||||
ret = {
|
ret = {
|
||||||
'leave_allocation': leave_allocation,
|
'leave_allocation': leave_allocation,
|
||||||
'leave_approver': get_leave_approver(employee)
|
'leave_approver': get_leave_approver(employee),
|
||||||
|
'lwps': lwps
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
@ -28,13 +28,14 @@ class ShiftType(Document):
|
|||||||
logs = frappe.db.get_list('Employee Checkin', fields="*", filters=filters, order_by="employee,time")
|
logs = frappe.db.get_list('Employee Checkin', fields="*", filters=filters, order_by="employee,time")
|
||||||
for key, group in itertools.groupby(logs, key=lambda x: (x['employee'], x['shift_actual_start'])):
|
for key, group in itertools.groupby(logs, key=lambda x: (x['employee'], x['shift_actual_start'])):
|
||||||
single_shift_logs = list(group)
|
single_shift_logs = list(group)
|
||||||
attendance_status, working_hours, late_entry, early_exit = self.get_attendance(single_shift_logs)
|
attendance_status, working_hours, late_entry, early_exit, in_time, out_time = self.get_attendance(single_shift_logs)
|
||||||
mark_attendance_and_link_log(single_shift_logs, attendance_status, key[1].date(), working_hours, late_entry, early_exit, self.name)
|
mark_attendance_and_link_log(single_shift_logs, attendance_status, key[1].date(), working_hours, late_entry, early_exit, in_time, out_time, self.name)
|
||||||
for employee in self.get_assigned_employee(self.process_attendance_after, True):
|
for employee in self.get_assigned_employee(self.process_attendance_after, True):
|
||||||
self.mark_absent_for_dates_with_no_attendance(employee)
|
self.mark_absent_for_dates_with_no_attendance(employee)
|
||||||
|
|
||||||
def get_attendance(self, logs):
|
def get_attendance(self, logs):
|
||||||
"""Return attendance_status, working_hours for a set of logs belonging to a single shift.
|
"""Return attendance_status, working_hours, late_entry, early_exit, in_time, out_time
|
||||||
|
for a set of logs belonging to a single shift.
|
||||||
Assumtion:
|
Assumtion:
|
||||||
1. These logs belongs to an single shift, single employee and is not in a holiday date.
|
1. These logs belongs to an single shift, single employee and is not in a holiday date.
|
||||||
2. Logs are in chronological order
|
2. Logs are in chronological order
|
||||||
@ -48,10 +49,10 @@ class ShiftType(Document):
|
|||||||
early_exit = True
|
early_exit = True
|
||||||
|
|
||||||
if self.working_hours_threshold_for_absent and total_working_hours < self.working_hours_threshold_for_absent:
|
if self.working_hours_threshold_for_absent and total_working_hours < self.working_hours_threshold_for_absent:
|
||||||
return 'Absent', total_working_hours, late_entry, early_exit
|
return 'Absent', total_working_hours, late_entry, early_exit, in_time, out_time
|
||||||
if self.working_hours_threshold_for_half_day and total_working_hours < self.working_hours_threshold_for_half_day:
|
if self.working_hours_threshold_for_half_day and total_working_hours < self.working_hours_threshold_for_half_day:
|
||||||
return 'Half Day', total_working_hours, late_entry, early_exit
|
return 'Half Day', total_working_hours, late_entry, early_exit, in_time, out_time
|
||||||
return 'Present', total_working_hours, late_entry, early_exit
|
return 'Present', total_working_hours, late_entry, early_exit, in_time, out_time
|
||||||
|
|
||||||
def mark_absent_for_dates_with_no_attendance(self, employee):
|
def mark_absent_for_dates_with_no_attendance(self, employee):
|
||||||
"""Marks Absents for the given employee on working days in this shift which have no attendance marked.
|
"""Marks Absents for the given employee on working days in this shift which have no attendance marked.
|
||||||
|
@ -77,6 +77,7 @@ def create_customer(user_details):
|
|||||||
customer = frappe.new_doc("Customer")
|
customer = frappe.new_doc("Customer")
|
||||||
customer.customer_name = user_details.fullname
|
customer.customer_name = user_details.fullname
|
||||||
customer.customer_type = "Individual"
|
customer.customer_type = "Individual"
|
||||||
|
customer.flags.ignore_mandatory = True
|
||||||
customer.insert(ignore_permissions=True)
|
customer.insert(ignore_permissions=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -91,7 +92,11 @@ def create_customer(user_details):
|
|||||||
"link_name": customer.name
|
"link_name": customer.name
|
||||||
})
|
})
|
||||||
|
|
||||||
contact.insert()
|
contact.save()
|
||||||
|
|
||||||
|
except frappe.DuplicateEntryError:
|
||||||
|
return customer.name
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
frappe.log_error(frappe.get_traceback(), _("Contact Creation Failed"))
|
frappe.log_error(frappe.get_traceback(), _("Contact Creation Failed"))
|
||||||
pass
|
pass
|
||||||
|
@ -62,7 +62,10 @@ def get_member_based_on_subscription(subscription_id, email):
|
|||||||
'subscription_id': subscription_id,
|
'subscription_id': subscription_id,
|
||||||
'email_id': email
|
'email_id': email
|
||||||
}, order_by="creation desc")
|
}, order_by="creation desc")
|
||||||
return frappe.get_doc("Member", members[0]['name'])
|
try:
|
||||||
|
return frappe.get_doc("Member", members[0]['name'])
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
def verify_signature(data):
|
def verify_signature(data):
|
||||||
signature = frappe.request.headers.get('X-Razorpay-Signature')
|
signature = frappe.request.headers.get('X-Razorpay-Signature')
|
||||||
@ -77,7 +80,7 @@ def verify_signature(data):
|
|||||||
|
|
||||||
@frappe.whitelist(allow_guest=True)
|
@frappe.whitelist(allow_guest=True)
|
||||||
def trigger_razorpay_subscription(*args, **kwargs):
|
def trigger_razorpay_subscription(*args, **kwargs):
|
||||||
data = frappe.request.get_data()
|
data = frappe.request.get_data(as_text=True)
|
||||||
verify_signature(data)
|
verify_signature(data)
|
||||||
|
|
||||||
if isinstance(data, six.string_types):
|
if isinstance(data, six.string_types):
|
||||||
@ -96,7 +99,10 @@ def trigger_razorpay_subscription(*args, **kwargs):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_log = frappe.log_error(frappe.get_traceback() + '\n' + data_json , _("Membership Webhook Failed"))
|
error_log = frappe.log_error(frappe.get_traceback() + '\n' + data_json , _("Membership Webhook Failed"))
|
||||||
notify_failure(error_log)
|
notify_failure(error_log)
|
||||||
raise e
|
return False
|
||||||
|
|
||||||
|
if not member:
|
||||||
|
return False
|
||||||
|
|
||||||
if data.event == "subscription.activated":
|
if data.event == "subscription.activated":
|
||||||
member.customer_id = payment.customer_id
|
member.customer_id = payment.customer_id
|
||||||
|
@ -680,6 +680,8 @@ erpnext.patches.v12_0.update_appointment_reminder_scheduler_entry
|
|||||||
erpnext.patches.v12_0.retain_permission_rules_for_video_doctype
|
erpnext.patches.v12_0.retain_permission_rules_for_video_doctype
|
||||||
erpnext.patches.v12_0.remove_duplicate_leave_ledger_entries #2020-05-22
|
erpnext.patches.v12_0.remove_duplicate_leave_ledger_entries #2020-05-22
|
||||||
erpnext.patches.v13_0.patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive
|
erpnext.patches.v13_0.patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive
|
||||||
|
execute:frappe.reload_doc("HR", "doctype", "Employee Advance")
|
||||||
|
erpnext.patches.v12_0.move_due_advance_amount_to_pending_amount
|
||||||
execute:frappe.delete_doc_if_exists("Page", "appointment-analytic")
|
execute:frappe.delete_doc_if_exists("Page", "appointment-analytic")
|
||||||
execute:frappe.rename_doc("Desk Page", "Getting Started", "Home", force=True)
|
execute:frappe.rename_doc("Desk Page", "Getting Started", "Home", force=True)
|
||||||
erpnext.patches.v12_0.unset_customer_supplier_based_on_type_of_item_price
|
erpnext.patches.v12_0.unset_customer_supplier_based_on_type_of_item_price
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2019, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
''' Move from due_advance_amount to pending_amount '''
|
||||||
|
frappe.db.sql(''' UPDATE `tabEmployee Advance` SET pending_amount=due_advance_amount ''')
|
@ -7,4 +7,4 @@ def execute():
|
|||||||
for entry in doctypes:
|
for entry in doctypes:
|
||||||
if frappe.db.exists('DocType', entry):
|
if frappe.db.exists('DocType', entry):
|
||||||
frappe.reload_doc('Healthcare', 'doctype', entry)
|
frappe.reload_doc('Healthcare', 'doctype', entry)
|
||||||
frappe.db.sql("update `tab{dt}` set company = '{company}' where ifnull(company, '') = ''".format(dt=entry, company=company))
|
frappe.db.sql("update `tab{dt}` set company = {company} where ifnull(company, '') = ''".format(dt=entry, company=frappe.db.escape(company)))
|
||||||
|
@ -73,6 +73,8 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
|||||||
me.frm.set_query('contact_person', erpnext.queries.contact_query);
|
me.frm.set_query('contact_person', erpnext.queries.contact_query);
|
||||||
me.frm.set_query('supplier_address', erpnext.queries.address_query);
|
me.frm.set_query('supplier_address', erpnext.queries.address_query);
|
||||||
|
|
||||||
|
me.frm.set_query('billing_address', erpnext.queries.company_address_query);
|
||||||
|
|
||||||
if(this.frm.fields_dict.supplier) {
|
if(this.frm.fields_dict.supplier) {
|
||||||
this.frm.set_query("supplier", function() {
|
this.frm.set_query("supplier", function() {
|
||||||
return{ query: "erpnext.controllers.queries.supplier_query" }});
|
return{ query: "erpnext.controllers.queries.supplier_query" }});
|
||||||
@ -283,6 +285,11 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
|||||||
"shipping_address_display", true);
|
"shipping_address_display", true);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
billing_address: function() {
|
||||||
|
erpnext.utils.get_address_display(this.frm, "billing_address",
|
||||||
|
"billing_address_display", true);
|
||||||
|
},
|
||||||
|
|
||||||
tc_name: function() {
|
tc_name: function() {
|
||||||
this.get_terms();
|
this.get_terms();
|
||||||
},
|
},
|
||||||
|
@ -3,16 +3,19 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
|
import json
|
||||||
from frappe.model.naming import set_name_by_naming_series
|
from frappe.model.naming import set_name_by_naming_series
|
||||||
from frappe import _, msgprint, throw
|
from frappe import _, msgprint
|
||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
from frappe.utils import flt, cint, cstr, today
|
from frappe.utils import flt, cint, cstr, today, get_formatted_email
|
||||||
from frappe.desk.reportview import build_match_conditions, get_filters_cond
|
from frappe.desk.reportview import build_match_conditions, get_filters_cond
|
||||||
from erpnext.utilities.transaction_base import TransactionBase
|
from erpnext.utilities.transaction_base import TransactionBase
|
||||||
from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this
|
from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this
|
||||||
from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
|
from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
|
||||||
from frappe.model.rename_doc import update_linked_doctypes
|
from frappe.model.rename_doc import update_linked_doctypes
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
|
from frappe.utils.user import get_users_with_role
|
||||||
|
|
||||||
|
|
||||||
class Customer(TransactionBase):
|
class Customer(TransactionBase):
|
||||||
def get_feed(self):
|
def get_feed(self):
|
||||||
@ -378,10 +381,45 @@ def check_credit_limit(customer, company, ignore_outstanding_sales_order=False,
|
|||||||
.format(customer, customer_outstanding, credit_limit))
|
.format(customer, customer_outstanding, credit_limit))
|
||||||
|
|
||||||
# If not authorized person raise exception
|
# If not authorized person raise exception
|
||||||
credit_controller = frappe.db.get_value('Accounts Settings', None, 'credit_controller')
|
credit_controller_role = frappe.db.get_single_value('Accounts Settings', 'credit_controller')
|
||||||
if not credit_controller or credit_controller not in frappe.get_roles():
|
if not credit_controller_role or credit_controller_role not in frappe.get_roles():
|
||||||
throw(_("Please contact to the user who have Sales Master Manager {0} role")
|
# form a list of emails for the credit controller users
|
||||||
.format(" / " + credit_controller if credit_controller else ""))
|
credit_controller_users = get_users_with_role(credit_controller_role or "Sales Master Manager")
|
||||||
|
|
||||||
|
# form a list of emails and names to show to the user
|
||||||
|
credit_controller_users_list = [user for user in credit_controller_users if frappe.db.exists("Employee", {"prefered_email": user})]
|
||||||
|
credit_controller_users = [get_formatted_email(user).replace("<", "(").replace(">", ")") for user in credit_controller_users_list]
|
||||||
|
|
||||||
|
if not credit_controller_users:
|
||||||
|
frappe.throw(_("Please contact your administrator to extend the credit limits for {0}.".format(customer)))
|
||||||
|
|
||||||
|
message = """Please contact any of the following users to extend the credit limits for {0}:
|
||||||
|
<br><br><ul><li>{1}</li></ul>""".format(customer, '<li>'.join(credit_controller_users))
|
||||||
|
|
||||||
|
# if the current user does not have permissions to override credit limit,
|
||||||
|
# prompt them to send out an email to the controller users
|
||||||
|
frappe.msgprint(message,
|
||||||
|
title="Notify",
|
||||||
|
raise_exception=1,
|
||||||
|
primary_action={
|
||||||
|
'label': 'Send Email',
|
||||||
|
'server_action': 'erpnext.selling.doctype.customer.customer.send_emails',
|
||||||
|
'args': {
|
||||||
|
'customer': customer,
|
||||||
|
'customer_outstanding': customer_outstanding,
|
||||||
|
'credit_limit': credit_limit,
|
||||||
|
'credit_controller_users_list': credit_controller_users_list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def send_emails(args):
|
||||||
|
args = json.loads(args)
|
||||||
|
subject = (_("Credit limit reached for customer {0}").format(args.get('customer')))
|
||||||
|
message = (_("Credit limit has been crossed for customer {0} ({1}/{2})")
|
||||||
|
.format(args.get('customer'), args.get('customer_outstanding'), args.get('credit_limit')))
|
||||||
|
frappe.sendmail(recipients=[args.get('credit_controller_users_list')], subject=subject, message=message)
|
||||||
|
|
||||||
def get_customer_outstanding(customer, company, ignore_outstanding_sales_order=False, cost_center=None):
|
def get_customer_outstanding(customer, company, ignore_outstanding_sales_order=False, cost_center=None):
|
||||||
# Outstanding based on GL Entries
|
# Outstanding based on GL Entries
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,7 @@ from frappe.utils import getdate, flt
|
|||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
if not filters: filters = {}
|
if not filters: filters = {}
|
||||||
float_preceision = frappe.db.get_default("float_preceision")
|
float_precision = frappe.db.get_default("float_precision")
|
||||||
|
|
||||||
condition = get_condition(filters)
|
condition = get_condition(filters)
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ def execute(filters=None):
|
|||||||
data = []
|
data = []
|
||||||
for item in items:
|
for item in items:
|
||||||
total_outgoing = flt(consumed_item_map.get(item.name, 0)) + flt(delivered_item_map.get(item.name,0))
|
total_outgoing = flt(consumed_item_map.get(item.name, 0)) + flt(delivered_item_map.get(item.name,0))
|
||||||
avg_daily_outgoing = flt(total_outgoing / diff, float_preceision)
|
avg_daily_outgoing = flt(total_outgoing / diff, float_precision)
|
||||||
reorder_level = (avg_daily_outgoing * flt(item.lead_time_days)) + flt(item.safety_stock)
|
reorder_level = (avg_daily_outgoing * flt(item.lead_time_days)) + flt(item.safety_stock)
|
||||||
|
|
||||||
data.append([item.name, item.item_name, item.item_group, item.brand, item.description,
|
data.append([item.name, item.item_name, item.item_group, item.brand, item.description,
|
||||||
|
@ -180,10 +180,10 @@ def get_fifo_queue(filters, sle=None):
|
|||||||
qty_to_pop = abs(d.actual_qty)
|
qty_to_pop = abs(d.actual_qty)
|
||||||
while qty_to_pop:
|
while qty_to_pop:
|
||||||
batch = fifo_queue[0] if fifo_queue else [0, None]
|
batch = fifo_queue[0] if fifo_queue else [0, None]
|
||||||
if 0 < batch[0] <= qty_to_pop:
|
if 0 < flt(batch[0]) <= qty_to_pop:
|
||||||
# if batch qty > 0
|
# if batch qty > 0
|
||||||
# not enough or exactly same qty in current batch, clear batch
|
# not enough or exactly same qty in current batch, clear batch
|
||||||
qty_to_pop -= batch[0]
|
qty_to_pop -= flt(batch[0])
|
||||||
transferred_item_details[(d.voucher_no, d.name)].append(fifo_queue.pop(0))
|
transferred_item_details[(d.voucher_no, d.name)].append(fifo_queue.pop(0))
|
||||||
else:
|
else:
|
||||||
# all from current batch
|
# all from current batch
|
||||||
@ -262,4 +262,4 @@ def get_chart_data(data, filters):
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"type" : "bar"
|
"type" : "bar"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user