Merge branch 'develop' into feat-picklist-scan
diff --git a/.github/try-on-f-cloud-button.svg b/.github/try-on-f-cloud-button.svg
index fe0bb2c..2700927 100644
--- a/.github/try-on-f-cloud-button.svg
+++ b/.github/try-on-f-cloud-button.svg
@@ -1,4 +1,4 @@
-<svg width="201" height="60" viewBox="0 0 201 60" fill="none" xmlns="http://www.w3.org/2000/svg">
+<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="4 2 193 52">
<g filter="url(#filter0_dd)">
<rect x="4" y="2" width="193" height="52" rx="6" fill="#2490EF"/>
<path d="M28 22.2891H32.8786V35.5H36.2088V22.2891H41.0874V19.5H28V22.2891Z" fill="white"/>
diff --git a/README.md b/README.md
index f8f5f80..cea3472 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@
## Installation
<div align="center" style="max-height: 40px;">
- <a href="https://frappecloud.com/deploy?apps=frappe,erpnext&source=erpnext_readme">
+ <a href="https://frappecloud.com/erpnext/signup">
<img src=".github/try-on-f-cloud-button.svg" height="40">
</a>
<a href="https://labs.play-with-docker.com/?stack=https://raw.githubusercontent.com/frappe/frappe_docker/main/pwd.yml">
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
index 9d4d76b..2d9ae93 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
@@ -114,10 +114,13 @@
)
or {}
)
+
+ default_currency = frappe.db.get_value(row.party_type, row.party, "default_currency")
+
if company_details:
invoice.update(
{
- "currency": company_details.get("default_currency"),
+ "currency": default_currency or company_details.get("default_currency"),
"letter_head": company_details.get("default_letter_head"),
}
)
diff --git a/erpnext/hr/doctype/employee_checkin/employee_checkin.py b/erpnext/hr/doctype/employee_checkin/employee_checkin.py
index 64eb019..e07b5e5 100644
--- a/erpnext/hr/doctype/employee_checkin/employee_checkin.py
+++ b/erpnext/hr/doctype/employee_checkin/employee_checkin.py
@@ -5,7 +5,7 @@
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import cint, get_datetime
+from frappe.utils import cint, get_datetime, get_link_to_form
from erpnext.hr.doctype.attendance.attendance import (
get_duplicate_attendance_record,
@@ -130,14 +130,11 @@
"""
log_names = [x.name for x in logs]
employee = logs[0].employee
+
if attendance_status == "Skip":
- frappe.db.sql(
- """update `tabEmployee Checkin`
- set skip_auto_attendance = %s
- where name in %s""",
- ("1", log_names),
- )
+ skip_attendance_in_checkins(log_names)
return None
+
elif attendance_status in ("Present", "Absent", "Half Day"):
employee_doc = frappe.get_doc("Employee", employee)
duplicate = get_duplicate_attendance_record(employee, attendance_date, shift)
@@ -159,6 +156,12 @@
}
attendance = frappe.get_doc(doc_dict).insert()
attendance.submit()
+
+ if attendance_status == "Absent":
+ attendance.add_comment(
+ text=_("Employee was marked Absent for not meeting the working hours threshold.")
+ )
+
frappe.db.sql(
"""update `tabEmployee Checkin`
set attendance = %s
@@ -167,13 +170,10 @@
)
return attendance
else:
- frappe.db.sql(
- """update `tabEmployee Checkin`
- set skip_auto_attendance = %s
- where name in %s""",
- ("1", log_names),
- )
+ skip_attendance_in_checkins(log_names)
+ add_comment_in_checkins(log_names, duplicate, overlapping)
return None
+
else:
frappe.throw(_("{} is an invalid Attendance Status.").format(attendance_status))
@@ -241,3 +241,34 @@
def find_index_in_dict(dict_list, key, value):
return next((index for (index, d) in enumerate(dict_list) if d[key] == value), None)
+
+
+def add_comment_in_checkins(log_names, duplicate, overlapping):
+ if duplicate:
+ text = _("Auto Attendance skipped due to duplicate attendance record: {}").format(
+ get_link_to_form("Attendance", duplicate[0].name)
+ )
+ else:
+ text = _("Auto Attendance skipped due to overlapping attendance record: {}").format(
+ get_link_to_form("Attendance", overlapping.name)
+ )
+
+ for name in log_names:
+ frappe.get_doc(
+ {
+ "doctype": "Comment",
+ "comment_type": "Comment",
+ "reference_doctype": "Employee Checkin",
+ "reference_name": name,
+ "content": text,
+ }
+ ).insert(ignore_permissions=True)
+
+
+def skip_attendance_in_checkins(log_names):
+ EmployeeCheckin = frappe.qb.DocType("Employee Checkin")
+ (
+ frappe.qb.update(EmployeeCheckin)
+ .set("skip_auto_attendance", 1)
+ .where(EmployeeCheckin.name.isin(log_names))
+ ).run()
diff --git a/erpnext/hr/doctype/shift_type/shift_type.py b/erpnext/hr/doctype/shift_type/shift_type.py
index 5e214cf..a61bb9e 100644
--- a/erpnext/hr/doctype/shift_type/shift_type.py
+++ b/erpnext/hr/doctype/shift_type/shift_type.py
@@ -134,7 +134,17 @@
shift_details = get_employee_shift(employee, timestamp, True)
if shift_details and shift_details.shift_type.name == self.name:
- mark_attendance(employee, date, "Absent", self.name)
+ attendance = mark_attendance(employee, date, "Absent", self.name)
+ if attendance:
+ frappe.get_doc(
+ {
+ "doctype": "Comment",
+ "comment_type": "Comment",
+ "reference_doctype": "Attendance",
+ "reference_name": attendance,
+ "content": frappe._("Employee was marked Absent due to missing Employee Checkins."),
+ }
+ ).insert(ignore_permissions=True)
def get_start_and_end_dates(self, employee):
"""Returns start and end dates for checking attendance and marking absent
diff --git a/erpnext/selling/workspace/selling/selling.json b/erpnext/selling/workspace/selling/selling.json
index a700ad8..45e160d 100644
--- a/erpnext/selling/workspace/selling/selling.json
+++ b/erpnext/selling/workspace/selling/selling.json
@@ -5,7 +5,7 @@
"label": "Sales Order Trends"
}
],
- "content": "[{\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Selling\",\"col\":12}},{\"type\":\"chart\",\"data\":{\"chart_name\":\"Sales Order Trends\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Quick Access</b></span>\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Item\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Order\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Analytics\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Order Analysis\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Selling\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Items and Pricing\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Key Reports\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Other Reports\",\"col\":4}}]",
+ "content": "[{\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Selling\",\"col\":12}},{\"type\":\"chart\",\"data\":{\"chart_name\":\"Sales Order Trends\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Quick Access</b></span>\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Item\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Order\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Analytics\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Order Analysis\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Selling\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Items and Pricing\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Key Reports\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Other Reports\",\"col\":4}}]",
"creation": "2020-01-28 11:49:12.092882",
"docstatus": 0,
"doctype": "Workspace",
@@ -317,115 +317,8 @@
{
"hidden": 0,
"is_query_report": 0,
- "label": "Key Reports",
- "link_count": 0,
- "onboard": 0,
- "type": "Card Break"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 1,
- "label": "Sales Analytics",
- "link_count": 0,
- "link_to": "Sales Analytics",
- "link_type": "Report",
- "onboard": 1,
- "type": "Link"
- },
- {
- "dependencies": "Sales Order",
- "hidden": 0,
- "is_query_report": 1,
- "label": "Sales Order Analysis",
- "link_count": 0,
- "link_to": "Sales Order Analysis",
- "link_type": "Report",
- "onboard": 1,
- "type": "Link"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Sales Funnel",
- "link_count": 0,
- "link_to": "sales-funnel",
- "link_type": "Page",
- "onboard": 1,
- "type": "Link"
- },
- {
- "dependencies": "Sales Order",
- "hidden": 0,
- "is_query_report": 1,
- "label": "Sales Order Trends",
- "link_count": 0,
- "link_to": "Sales Order Trends",
- "link_type": "Report",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "Quotation",
- "hidden": 0,
- "is_query_report": 1,
- "label": "Quotation Trends",
- "link_count": 0,
- "link_to": "Quotation Trends",
- "link_type": "Report",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "Customer",
- "hidden": 0,
- "is_query_report": 1,
- "label": "Customer Acquisition and Loyalty",
- "link_count": 0,
- "link_to": "Customer Acquisition and Loyalty",
- "link_type": "Report",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "Sales Order",
- "hidden": 0,
- "is_query_report": 1,
- "label": "Inactive Customers",
- "link_count": 0,
- "link_to": "Inactive Customers",
- "link_type": "Report",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "Sales Order",
- "hidden": 0,
- "is_query_report": 1,
- "label": "Sales Person-wise Transaction Summary",
- "link_count": 0,
- "link_to": "Sales Person-wise Transaction Summary",
- "link_type": "Report",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "Item",
- "hidden": 0,
- "is_query_report": 1,
- "label": "Item-wise Sales History",
- "link_count": 0,
- "link_to": "Item-wise Sales History",
- "link_type": "Report",
- "onboard": 0,
- "type": "Link"
- },
- {
- "hidden": 0,
- "is_query_report": 0,
"label": "Other Reports",
- "link_count": 0,
+ "link_count": 12,
"onboard": 0,
"type": "Card Break"
},
@@ -560,9 +453,258 @@
"link_type": "Report",
"onboard": 0,
"type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Key Reports",
+ "link_count": 22,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Analytics",
+ "link_count": 0,
+ "link_to": "Sales Analytics",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Order Analysis",
+ "link_count": 0,
+ "link_to": "Sales Order Analysis",
+ "link_type": "Report",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Sales Funnel",
+ "link_count": 0,
+ "link_to": "sales-funnel",
+ "link_type": "Page",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Order Trends",
+ "link_count": 0,
+ "link_to": "Sales Order Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Quotation",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Quotation Trends",
+ "link_count": 0,
+ "link_to": "Quotation Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Customer",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Customer Acquisition and Loyalty",
+ "link_count": 0,
+ "link_to": "Customer Acquisition and Loyalty",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Inactive Customers",
+ "link_count": 0,
+ "link_to": "Inactive Customers",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Person-wise Transaction Summary",
+ "link_count": 0,
+ "link_to": "Sales Person-wise Transaction Summary",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Item-wise Sales History",
+ "link_count": 0,
+ "link_to": "Item-wise Sales History",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Lead",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Lead Details",
+ "link_count": 0,
+ "link_to": "Lead Details",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Address",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Customer Addresses And Contacts",
+ "link_count": 0,
+ "link_to": "Address And Contacts",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Available Stock for Packing Items",
+ "link_count": 0,
+ "link_to": "Available Stock for Packing Items",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Pending SO Items For Purchase Request",
+ "link_count": 0,
+ "link_to": "Pending SO Items For Purchase Request",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Delivery Note",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Delivery Note Trends",
+ "link_count": 0,
+ "link_to": "Delivery Note Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Invoice",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Invoice Trends",
+ "link_count": 0,
+ "link_to": "Sales Invoice Trends",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Customer",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Customer Credit Balance",
+ "link_count": 0,
+ "link_to": "Customer Credit Balance",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Customer",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Customers Without Any Sales Transactions",
+ "link_count": 0,
+ "link_to": "Customers Without Any Sales Transactions",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Customer",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Partners Commission",
+ "link_count": 0,
+ "link_to": "Sales Partners Commission",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Territory Target Variance Based On Item Group",
+ "link_count": 0,
+ "link_to": "Territory Target Variance Based On Item Group",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Person Target Variance Based On Item Group",
+ "link_count": 0,
+ "link_to": "Sales Person Target Variance Based On Item Group",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Sales Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Sales Partner Target Variance Based On Item Group",
+ "link_count": 0,
+ "link_to": "Sales Partner Target Variance based on Item Group",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Payment Terms Status for Sales Order",
+ "link_count": 0,
+ "link_to": "Payment Terms Status for Sales Order",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
}
],
- "modified": "2022-01-13 17:43:02.778627",
+ "modified": "2022-04-26 13:29:55.087240",
"modified_by": "Administrator",
"module": "Selling",
"name": "Selling",