Compare commits
40 Commits
v13.54.6
...
deepeshgar
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f8b13ac57 | ||
|
|
1b78dd17c9 | ||
|
|
77e01ebacf | ||
|
|
bd371e697c | ||
|
|
2c4cee025b | ||
|
|
303becf1e3 | ||
|
|
6f44a1630f | ||
|
|
b7944a7c07 | ||
|
|
3dfc1450a1 | ||
|
|
835c85a087 | ||
|
|
190f77abff | ||
|
|
095d99dbd2 | ||
|
|
a9429e160d | ||
|
|
5342cd0dfa | ||
|
|
3bf84e1464 | ||
|
|
65ae8d9c05 | ||
|
|
35717124cd | ||
|
|
89c107ea8b | ||
|
|
958db77cda | ||
|
|
bc1da4678a | ||
|
|
6cb8a40339 | ||
|
|
9139c14639 | ||
|
|
461eb7a50d | ||
|
|
635c3d54f5 | ||
|
|
1bd3f4eeef | ||
|
|
4b8ed0f6ae | ||
|
|
eea7bbcea7 | ||
|
|
1e436052e2 | ||
|
|
5be5fde276 | ||
|
|
8cb0f690d5 | ||
|
|
4789ecacea | ||
|
|
d00257ffd7 | ||
|
|
37b1a0e778 | ||
|
|
6952f0f082 | ||
|
|
8f4ded6ad1 | ||
|
|
13d5eec194 | ||
|
|
335b6c84db | ||
|
|
00dff0a219 | ||
|
|
b55b428114 | ||
|
|
5669a89afe |
16
.github/workflows/linters.yml
vendored
16
.github/workflows/linters.yml
vendored
@@ -11,10 +11,10 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python 3.8
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install and Run Pre-commit
|
||||
uses: pre-commit/action@v2.0.3
|
||||
@@ -22,10 +22,8 @@ jobs:
|
||||
- name: Download Semgrep rules
|
||||
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules
|
||||
|
||||
- uses: returntocorp/semgrep-action@v1
|
||||
env:
|
||||
SEMGREP_TIMEOUT: 120
|
||||
with:
|
||||
config: >-
|
||||
r/python.lang.correctness
|
||||
./frappe-semgrep-rules/rules
|
||||
- name: Download semgrep
|
||||
run: pip install semgrep
|
||||
|
||||
- name: Run Semgrep rules
|
||||
run: semgrep ci --config ./frappe-semgrep-rules/rules --config r/python.lang.correctness
|
||||
|
||||
@@ -358,6 +358,7 @@ def update_outstanding_amt(
|
||||
if against_voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]:
|
||||
ref_doc = frappe.get_doc(against_voucher_type, against_voucher)
|
||||
|
||||
bal = flt(bal, frappe.get_precision(against_voucher_type, "outstanding_amount"))
|
||||
# Didn't use db_set for optimization purpose
|
||||
ref_doc.outstanding_amount = bal
|
||||
frappe.db.set_value(against_voucher_type, against_voucher, "outstanding_amount", bal)
|
||||
|
||||
@@ -295,6 +295,7 @@ class PaymentReconciliation(Document):
|
||||
"amount": pay.get("amount"),
|
||||
"allocated_amount": allocated_amount,
|
||||
"difference_amount": pay.get("difference_amount"),
|
||||
"currency": inv.get("currency"),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
"section_break_5",
|
||||
"difference_amount",
|
||||
"column_break_7",
|
||||
"difference_account"
|
||||
"difference_account",
|
||||
"currency"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@@ -37,7 +38,7 @@
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Allocated Amount",
|
||||
"options": "Currency",
|
||||
"options": "currency",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
@@ -112,7 +113,7 @@
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 1,
|
||||
"label": "Unreconciled Amount",
|
||||
"options": "Currency",
|
||||
"options": "currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
@@ -120,7 +121,7 @@
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 1,
|
||||
"label": "Amount",
|
||||
"options": "Currency",
|
||||
"options": "currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
@@ -129,11 +130,18 @@
|
||||
"hidden": 1,
|
||||
"label": "Reference Row",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "currency",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"label": "Currency",
|
||||
"options": "Currency"
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-10-06 11:48:59.616562",
|
||||
"modified": "2023-11-28 16:30:43.344612",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Reconciliation Allocation",
|
||||
|
||||
@@ -226,7 +226,9 @@ def set_address_details(
|
||||
party_details.update(
|
||||
{
|
||||
"shipping_address": shipping_address,
|
||||
"shipping_address_display": render_address(shipping_address),
|
||||
"shipping_address_display": render_address(
|
||||
shipping_address, check_permissions=not ignore_permissions
|
||||
),
|
||||
**get_fetch_values(doctype, "shipping_address", shipping_address),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import frappe
|
||||
from frappe import ValidationError, _, msgprint
|
||||
from frappe.contacts.doctype.address.address import get_address_display
|
||||
from frappe.contacts.doctype.address.address import render_address
|
||||
from frappe.utils import cint, cstr, flt, getdate
|
||||
|
||||
from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
|
||||
@@ -187,7 +187,9 @@ class BuyingController(StockController, Subcontracting):
|
||||
|
||||
for address_field, address_display_field in address_dict.items():
|
||||
if self.get(address_field):
|
||||
self.set(address_display_field, get_address_display(self.get(address_field)))
|
||||
self.set(
|
||||
address_display_field, render_address(self.get(address_field), check_permissions=False)
|
||||
)
|
||||
|
||||
def set_total_in_words(self):
|
||||
from frappe.utils import money_in_words
|
||||
|
||||
@@ -914,8 +914,6 @@ def create_item_wise_repost_entries(voucher_type, voucher_no, allow_zero_rate=Fa
|
||||
|
||||
repost_entry = frappe.new_doc("Repost Item Valuation")
|
||||
repost_entry.based_on = "Item and Warehouse"
|
||||
repost_entry.voucher_type = voucher_type
|
||||
repost_entry.voucher_no = voucher_no
|
||||
|
||||
repost_entry.item_code = sle.item_code
|
||||
repost_entry.warehouse = sle.warehouse
|
||||
|
||||
@@ -296,18 +296,27 @@ class LeaveAllocation(Document):
|
||||
|
||||
def get_previous_allocation(from_date, leave_type, employee):
|
||||
"""Returns document properties of previous allocation"""
|
||||
return frappe.db.get_value(
|
||||
"Leave Allocation",
|
||||
filters={
|
||||
"to_date": ("<", from_date),
|
||||
"leave_type": leave_type,
|
||||
"employee": employee,
|
||||
"docstatus": 1,
|
||||
},
|
||||
order_by="to_date DESC",
|
||||
fieldname=["name", "from_date", "to_date", "employee", "leave_type"],
|
||||
as_dict=1,
|
||||
)
|
||||
Allocation = frappe.qb.DocType("Leave Allocation")
|
||||
allocations = (
|
||||
frappe.qb.from_(Allocation)
|
||||
.select(
|
||||
Allocation.name,
|
||||
Allocation.from_date,
|
||||
Allocation.to_date,
|
||||
Allocation.employee,
|
||||
Allocation.leave_type,
|
||||
)
|
||||
.where(
|
||||
(Allocation.employee == employee)
|
||||
& (Allocation.leave_type == leave_type)
|
||||
& (Allocation.to_date < from_date)
|
||||
& (Allocation.docstatus == 1)
|
||||
)
|
||||
.orderby(Allocation.to_date, order=frappe.qb.desc)
|
||||
.limit(1)
|
||||
).run(as_dict=True)
|
||||
|
||||
return allocations[0] if allocations else None
|
||||
|
||||
|
||||
def get_leave_allocation_for_period(
|
||||
|
||||
@@ -706,19 +706,22 @@ def get_allocation_expiry_for_cf_leaves(
|
||||
employee: str, leave_type: str, to_date: str, from_date: str
|
||||
) -> str:
|
||||
"""Returns expiry of carry forward allocation in leave ledger entry"""
|
||||
expiry = frappe.get_all(
|
||||
"Leave Ledger Entry",
|
||||
filters={
|
||||
"employee": employee,
|
||||
"leave_type": leave_type,
|
||||
"is_carry_forward": 1,
|
||||
"transaction_type": "Leave Allocation",
|
||||
"to_date": ["between", (from_date, to_date)],
|
||||
"docstatus": 1,
|
||||
},
|
||||
fields=["to_date"],
|
||||
)
|
||||
return expiry[0]["to_date"] if expiry else ""
|
||||
Ledger = frappe.qb.DocType("Leave Ledger Entry")
|
||||
expiry = (
|
||||
frappe.qb.from_(Ledger)
|
||||
.select(Ledger.to_date)
|
||||
.where(
|
||||
(Ledger.employee == employee)
|
||||
& (Ledger.leave_type == leave_type)
|
||||
& (Ledger.is_carry_forward == 1)
|
||||
& (Ledger.transaction_type == "Leave Allocation")
|
||||
& (Ledger.to_date.between(from_date, to_date))
|
||||
& (Ledger.docstatus == 1)
|
||||
)
|
||||
.limit(1)
|
||||
).run()
|
||||
|
||||
return expiry[0][0] if expiry else ""
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@@ -1017,7 +1020,7 @@ def get_leaves_for_period(
|
||||
if leave_entry.leaves % 1:
|
||||
half_day = 1
|
||||
half_day_date = frappe.db.get_value(
|
||||
"Leave Application", {"name": leave_entry.transaction_name}, ["half_day_date"]
|
||||
"Leave Application", leave_entry.transaction_name, "half_day_date"
|
||||
)
|
||||
|
||||
leave_days += (
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Employee",
|
||||
"options": "Employee"
|
||||
"options": "Employee",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "employee.employee_name",
|
||||
@@ -57,13 +58,15 @@
|
||||
"fieldtype": "Link",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Transaction Type",
|
||||
"options": "DocType"
|
||||
"options": "DocType",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "transaction_name",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Transaction Name",
|
||||
"options": "transaction_type"
|
||||
"options": "transaction_type",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "leaves",
|
||||
@@ -123,7 +126,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-01-04 18:47:45.146652",
|
||||
"modified": "2023-11-17 12:36:36.963697",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Leave Ledger Entry",
|
||||
|
||||
@@ -225,3 +225,7 @@ def expire_carried_forward_allocation(allocation):
|
||||
to_date=allocation.to_date,
|
||||
)
|
||||
create_leave_ledger_entry(allocation, args)
|
||||
|
||||
|
||||
def on_doctype_update():
|
||||
frappe.db.add_index("Leave Ledger Entry", ["transaction_type", "transaction_name"])
|
||||
|
||||
@@ -1,26 +1,32 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"apply_user_permissions": 1,
|
||||
"creation": "2013-02-22 15:29:34",
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 3,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2017-02-24 20:18:04.317397",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee Leave Balance",
|
||||
"owner": "Administrator",
|
||||
"ref_doctype": "Employee",
|
||||
"report_name": "Employee Leave Balance",
|
||||
"report_type": "Script Report",
|
||||
"add_total_row": 0,
|
||||
"columns": [],
|
||||
"creation": "2013-02-22 15:29:34",
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"filters": [],
|
||||
"idx": 3,
|
||||
"is_standard": "Yes",
|
||||
"letterhead": null,
|
||||
"modified": "2023-11-17 13:28:40.669200",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee Leave Balance",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Employee",
|
||||
"report_name": "Employee Leave Balance",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "HR User"
|
||||
},
|
||||
},
|
||||
{
|
||||
"role": "HR Manager"
|
||||
},
|
||||
{
|
||||
"role": "Employee"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -85,19 +85,10 @@ def get_columns() -> List[Dict]:
|
||||
|
||||
|
||||
def get_data(filters: Filters) -> List:
|
||||
leave_types = frappe.db.get_list("Leave Type", pluck="name", order_by="name")
|
||||
conditions = get_conditions(filters)
|
||||
leave_types = get_leave_types()
|
||||
active_employees = get_employees(filters)
|
||||
|
||||
user = frappe.session.user
|
||||
department_approver_map = get_department_leave_approver_map(filters.department)
|
||||
|
||||
active_employees = frappe.get_list(
|
||||
"Employee",
|
||||
filters=conditions,
|
||||
fields=["name", "employee_name", "department", "user_id", "leave_approver"],
|
||||
)
|
||||
|
||||
precision = cint(frappe.db.get_single_value("System Settings", "float_precision", cache=True))
|
||||
precision = cint(frappe.db.get_single_value("System Settings", "float_precision"))
|
||||
consolidate_leave_types = len(active_employees) > 1 and filters.consolidate_leave_types
|
||||
row = None
|
||||
|
||||
@@ -110,10 +101,6 @@ def get_data(filters: Filters) -> List:
|
||||
row = frappe._dict({"leave_type": leave_type})
|
||||
|
||||
for employee in active_employees:
|
||||
leave_approvers = department_approver_map.get(employee.department_name, []).append(
|
||||
employee.leave_approver
|
||||
)
|
||||
|
||||
if consolidate_leave_types:
|
||||
row = frappe._dict()
|
||||
else:
|
||||
@@ -144,6 +131,35 @@ def get_data(filters: Filters) -> List:
|
||||
return data
|
||||
|
||||
|
||||
def get_leave_types() -> List[str]:
|
||||
LeaveType = frappe.qb.DocType("Leave Type")
|
||||
leave_types = (frappe.qb.from_(LeaveType).select(LeaveType.name).orderby(LeaveType.name)).run(
|
||||
as_dict=True
|
||||
)
|
||||
return [leave_type.name for leave_type in leave_types]
|
||||
|
||||
|
||||
def get_employees(filters: Filters) -> List[Dict]:
|
||||
Employee = frappe.qb.DocType("Employee")
|
||||
query = frappe.qb.from_(Employee).select(
|
||||
Employee.name,
|
||||
Employee.employee_name,
|
||||
Employee.department,
|
||||
)
|
||||
|
||||
for field in ["company", "department"]:
|
||||
if filters.get(field):
|
||||
query = query.where((getattr(Employee, field) == filters.get(field)))
|
||||
|
||||
if filters.get("employee"):
|
||||
query = query.where(Employee.name == filters.get("employee"))
|
||||
|
||||
if filters.get("employee_status"):
|
||||
query = query.where(Employee.status == filters.get("employee_status"))
|
||||
|
||||
return query.run(as_dict=True)
|
||||
|
||||
|
||||
def get_opening_balance(
|
||||
employee: str, leave_type: str, filters: Filters, carry_forwarded_leaves: float
|
||||
) -> float:
|
||||
@@ -168,48 +184,6 @@ def get_opening_balance(
|
||||
return opening_balance
|
||||
|
||||
|
||||
def get_conditions(filters: Filters) -> Dict:
|
||||
conditions = {}
|
||||
|
||||
if filters.employee:
|
||||
conditions["name"] = filters.employee
|
||||
|
||||
if filters.company:
|
||||
conditions["company"] = filters.company
|
||||
|
||||
if filters.department:
|
||||
conditions["department"] = filters.department
|
||||
|
||||
if filters.employee_status:
|
||||
conditions["status"] = filters.employee_status
|
||||
|
||||
return conditions
|
||||
|
||||
|
||||
def get_department_leave_approver_map(department: Optional[str] = None):
|
||||
# get current department and all its child
|
||||
department_list = frappe.get_list(
|
||||
"Department",
|
||||
filters={"disabled": 0},
|
||||
or_filters={"name": department, "parent_department": department},
|
||||
pluck="name",
|
||||
)
|
||||
# retrieve approvers list from current department and from its subsequent child departments
|
||||
approver_list = frappe.get_all(
|
||||
"Department Approver",
|
||||
filters={"parentfield": "leave_approvers", "parent": ("in", department_list)},
|
||||
fields=["parent", "approver"],
|
||||
as_list=True,
|
||||
)
|
||||
|
||||
approvers = {}
|
||||
|
||||
for k, v in approver_list:
|
||||
approvers.setdefault(k, []).append(v)
|
||||
|
||||
return approvers
|
||||
|
||||
|
||||
def get_allocated_and_expired_leaves(
|
||||
from_date: str, to_date: str, employee: str, leave_type: str
|
||||
) -> Tuple[float, float, float]:
|
||||
@@ -244,7 +218,7 @@ def get_leave_ledger_entries(
|
||||
from_date: str, to_date: str, employee: str, leave_type: str
|
||||
) -> List[Dict]:
|
||||
ledger = frappe.qb.DocType("Leave Ledger Entry")
|
||||
records = (
|
||||
return (
|
||||
frappe.qb.from_(ledger)
|
||||
.select(
|
||||
ledger.employee,
|
||||
@@ -270,8 +244,6 @@ def get_leave_ledger_entries(
|
||||
)
|
||||
).run(as_dict=True)
|
||||
|
||||
return records
|
||||
|
||||
|
||||
def get_chart_data(data: List, filters: Filters) -> Dict:
|
||||
labels = []
|
||||
|
||||
@@ -6,9 +6,6 @@ import frappe
|
||||
from frappe import _
|
||||
|
||||
from erpnext.hr.doctype.leave_application.leave_application import get_leave_details
|
||||
from erpnext.hr.report.employee_leave_balance.employee_leave_balance import (
|
||||
get_department_leave_approver_map,
|
||||
)
|
||||
|
||||
|
||||
def execute(filters=None):
|
||||
@@ -54,17 +51,11 @@ def get_data(filters, leave_types):
|
||||
active_employees = frappe.get_all(
|
||||
"Employee",
|
||||
filters=conditions,
|
||||
fields=["name", "employee_name", "department", "user_id", "leave_approver"],
|
||||
fields=["name", "employee_name", "department", "user_id"],
|
||||
)
|
||||
|
||||
department_approver_map = get_department_leave_approver_map(filters.get("department"))
|
||||
|
||||
data = []
|
||||
for employee in active_employees:
|
||||
leave_approvers = department_approver_map.get(employee.department_name, [])
|
||||
if employee.leave_approver:
|
||||
leave_approvers.append(employee.leave_approver)
|
||||
|
||||
row = [employee.name, employee.employee_name, employee.department]
|
||||
available_leave = get_leave_details(employee.name, filters.date)
|
||||
for leave_type in leave_types:
|
||||
|
||||
@@ -306,7 +306,7 @@ def get_last_accrual_date(loan, posting_date):
|
||||
def get_last_disbursement_date(loan, posting_date):
|
||||
last_disbursement_date = frappe.db.get_value(
|
||||
"Loan Disbursement",
|
||||
{"docstatus": 1, "against_loan": loan, "posting_date": ("<", posting_date)},
|
||||
{"docstatus": 1, "against_loan": loan, "posting_date": ("<=", posting_date)},
|
||||
"MAX(posting_date)",
|
||||
)
|
||||
|
||||
|
||||
@@ -3,23 +3,27 @@ import frappe
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("stock", "doctype", "quality_inspection_parameter")
|
||||
params = set()
|
||||
|
||||
# get all distinct parameters from QI readigs table
|
||||
reading_params = frappe.db.get_all(
|
||||
"Quality Inspection Reading", fields=["distinct specification"]
|
||||
)
|
||||
reading_params = [d.specification for d in reading_params]
|
||||
# get all parameters from QI readings table
|
||||
for (p,) in frappe.db.get_all(
|
||||
"Quality Inspection Reading", fields=["specification"], as_list=True
|
||||
):
|
||||
params.add(p.strip())
|
||||
|
||||
# get all distinct parameters from QI Template as some may be unused in QI
|
||||
template_params = frappe.db.get_all(
|
||||
"Item Quality Inspection Parameter", fields=["distinct specification"]
|
||||
)
|
||||
template_params = [d.specification for d in template_params]
|
||||
# get all parameters from QI Template as some may be unused in QI
|
||||
for (p,) in frappe.db.get_all(
|
||||
"Item Quality Inspection Parameter", fields=["specification"], as_list=True
|
||||
):
|
||||
params.add(p.strip())
|
||||
|
||||
params = list(set(reading_params + template_params))
|
||||
# because db primary keys are case insensitive, so duplicates will cause an exception
|
||||
params = set({x.casefold(): x for x in params}.values())
|
||||
|
||||
for parameter in params:
|
||||
if not frappe.db.exists("Quality Inspection Parameter", parameter):
|
||||
frappe.get_doc(
|
||||
{"doctype": "Quality Inspection Parameter", "parameter": parameter, "description": parameter}
|
||||
).insert(ignore_permissions=True)
|
||||
if frappe.db.exists("Quality Inspection Parameter", parameter):
|
||||
continue
|
||||
|
||||
frappe.get_doc(
|
||||
{"doctype": "Quality Inspection Parameter", "parameter": parameter, "description": parameter}
|
||||
).insert(ignore_permissions=True)
|
||||
|
||||
@@ -125,6 +125,7 @@ def execute():
|
||||
loan_type_doc.company = loan.company
|
||||
loan_type_doc.mode_of_payment = loan.mode_of_payment
|
||||
loan_type_doc.payment_account = loan.payment_account
|
||||
loan_type_doc.disbursement_account = loan.payment_account
|
||||
loan_type_doc.loan_account = loan.loan_account
|
||||
loan_type_doc.interest_income_account = loan.interest_income_account
|
||||
loan_type_doc.penalty_income_account = penalty_account
|
||||
|
||||
@@ -71,6 +71,12 @@ class Timesheet(Document):
|
||||
if args.is_billable:
|
||||
if flt(args.billing_hours) == 0.0:
|
||||
args.billing_hours = args.hours
|
||||
elif flt(args.billing_hours) > flt(args.hours):
|
||||
frappe.msgprint(
|
||||
_("Warning - Row {0}: Billing Hours are more than Actual Hours").format(args.idx),
|
||||
indicator="orange",
|
||||
alert=True,
|
||||
)
|
||||
else:
|
||||
args.billing_hours = 0
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ frappe.ui.form.on("Communication", {
|
||||
frappe.confirm(__(confirm_msg, [__("Issue")]), () => {
|
||||
frm.trigger('make_issue_from_communication');
|
||||
})
|
||||
}, "Create");
|
||||
}, __("Create"));
|
||||
}
|
||||
|
||||
if(!in_list(["Lead", "Opportunity"], frm.doc.reference_doctype)) {
|
||||
|
||||
@@ -1378,7 +1378,7 @@ class GSPConnector:
|
||||
|
||||
def set_einvoice_data(self, res):
|
||||
enc_signed_invoice = res.get("SignedInvoice")
|
||||
dec_signed_invoice = jwt.decode(enc_signed_invoice, verify=False)["data"]
|
||||
dec_signed_invoice = jwt.decode(enc_signed_invoice, options={"verify_signature": False})["data"]
|
||||
|
||||
self.invoice.irn = res.get("Irn")
|
||||
self.invoice.ewaybill = res.get("EwbNo")
|
||||
|
||||
@@ -532,6 +532,7 @@ def check_credit_limit(customer, company, ignore_outstanding_sales_order=False,
|
||||
primary_action={
|
||||
"label": "Send Email",
|
||||
"server_action": "erpnext.selling.doctype.customer.customer.send_emails",
|
||||
"hide_on_success": True,
|
||||
"args": {
|
||||
"customer": customer,
|
||||
"customer_outstanding": customer_outstanding,
|
||||
|
||||
@@ -1184,16 +1184,16 @@ class TestDeliveryNote(FrappeTestCase):
|
||||
frappe.db.rollback()
|
||||
frappe.db.set_single_value("Selling Settings", "dont_reserve_sales_order_qty_on_sales_return", 0)
|
||||
|
||||
def non_internal_transfer_delivery_note(self):
|
||||
def test_non_internal_transfer_delivery_note(self):
|
||||
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||
|
||||
dn = create_delivery_note(do_not_submit=True)
|
||||
warehouse = create_warehouse("Internal Transfer Warehouse", dn.company)
|
||||
dn.items[0].db_set("target_warehouse", "warehouse")
|
||||
warehouse = create_warehouse("Internal Transfer Warehouse", company=dn.company)
|
||||
dn.items[0].db_set("target_warehouse", warehouse)
|
||||
|
||||
dn.reload()
|
||||
|
||||
self.assertEqual(dn.items[0].target_warehouse, warehouse.name)
|
||||
self.assertEqual(dn.items[0].target_warehouse, warehouse)
|
||||
|
||||
dn.save()
|
||||
dn.reload()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
from unittest.mock import MagicMock, call
|
||||
|
||||
import frappe
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
from frappe.tests.utils import FrappeTestCase, change_settings
|
||||
from frappe.utils import nowdate
|
||||
from frappe.utils.data import add_to_date, today
|
||||
|
||||
@@ -173,6 +173,7 @@ class TestRepostItemValuation(FrappeTestCase, StockTestMixin):
|
||||
|
||||
riv.set_status("Skipped")
|
||||
|
||||
@change_settings("Stock Reposting Settings", {"item_based_reposting": 0})
|
||||
def test_prevention_of_cancelled_transaction_riv(self):
|
||||
frappe.flags.dont_execute_stock_reposts = True
|
||||
|
||||
@@ -295,6 +296,7 @@ class TestRepostItemValuation(FrappeTestCase, StockTestMixin):
|
||||
accounts_settings.acc_frozen_upto = ""
|
||||
accounts_settings.save()
|
||||
|
||||
@change_settings("Stock Reposting Settings", {"item_based_reposting": 0})
|
||||
def test_create_repost_entry_for_cancelled_document(self):
|
||||
pr = make_purchase_receipt(
|
||||
company="_Test Company with perpetual inventory",
|
||||
|
||||
@@ -1414,6 +1414,7 @@ class TestStockEntry(FrappeTestCase):
|
||||
self.assertEqual(se.items[0].item_name, item.item_name)
|
||||
self.assertEqual(se.items[0].stock_uom, item.stock_uom)
|
||||
|
||||
@change_settings("Stock Reposting Settings", {"item_based_reposting": 0})
|
||||
def test_reposting_for_depedent_warehouse(self):
|
||||
from erpnext.stock.doctype.repost_item_valuation.repost_item_valuation import repost_sl_entries
|
||||
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"label": "Limit timeslot for Stock Reposting"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"default": "1",
|
||||
"fieldname": "item_based_reposting",
|
||||
"fieldtype": "Check",
|
||||
"label": "Use Item based reposting"
|
||||
@@ -57,7 +57,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2021-11-02 01:22:45.155841",
|
||||
"modified": "2023-11-01 16:14:29.080697",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Stock Reposting Settings",
|
||||
@@ -77,4 +77,4 @@
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,18 @@ const DIFFERENCE_FIELD_NAMES = [
|
||||
|
||||
frappe.query_reports["Stock Ledger Variance"] = {
|
||||
"filters": [
|
||||
{
|
||||
"fieldname": "company",
|
||||
"label": __("Company"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Company",
|
||||
"reqd": 1,
|
||||
"default": frappe.defaults.get_user_default("Company")
|
||||
},
|
||||
{
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"label": "Item",
|
||||
"label": __("Item"),
|
||||
"options": "Item",
|
||||
get_query: function() {
|
||||
return {
|
||||
@@ -27,7 +35,7 @@ frappe.query_reports["Stock Ledger Variance"] = {
|
||||
{
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
"label": "Warehouse",
|
||||
"label": __("Warehouse"),
|
||||
"options": "Warehouse",
|
||||
get_query: function() {
|
||||
return {
|
||||
@@ -38,7 +46,7 @@ frappe.query_reports["Stock Ledger Variance"] = {
|
||||
{
|
||||
"fieldname": "difference_in",
|
||||
"fieldtype": "Select",
|
||||
"label": "Difference In",
|
||||
"label": __("Difference In"),
|
||||
"options": [
|
||||
"",
|
||||
"Qty",
|
||||
@@ -49,7 +57,7 @@ frappe.query_reports["Stock Ledger Variance"] = {
|
||||
{
|
||||
"fieldname": "include_disabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Include Disabled",
|
||||
"label": __("Include Disabled"),
|
||||
}
|
||||
],
|
||||
|
||||
|
||||
@@ -55,6 +55,11 @@ def get_columns():
|
||||
"label": _("Warehouse"),
|
||||
"options": "Warehouse",
|
||||
},
|
||||
{
|
||||
"fieldname": "valuation_method",
|
||||
"fieldtype": "Data",
|
||||
"label": _("Valuation Method"),
|
||||
},
|
||||
{
|
||||
"fieldname": "voucher_type",
|
||||
"fieldtype": "Link",
|
||||
@@ -194,6 +199,7 @@ def get_columns():
|
||||
def get_data(filters=None):
|
||||
filters = frappe._dict(filters or {})
|
||||
item_warehouse_map = get_item_warehouse_combinations(filters)
|
||||
valuation_method = frappe.db.get_single_value("Stock Settings", "valuation_method")
|
||||
|
||||
data = []
|
||||
if item_warehouse_map:
|
||||
@@ -206,8 +212,17 @@ def get_data(filters=None):
|
||||
continue
|
||||
|
||||
for row in report_data:
|
||||
if has_difference(row, precision, filters.difference_in):
|
||||
data.append(add_item_warehouse_details(row, item_warehouse))
|
||||
if has_difference(
|
||||
row, precision, filters.difference_in, item_warehouse.valuation_method or valuation_method
|
||||
):
|
||||
row.update(
|
||||
{
|
||||
"item_code": item_warehouse.item_code,
|
||||
"warehouse": item_warehouse.warehouse,
|
||||
"valuation_method": item_warehouse.valuation_method or valuation_method,
|
||||
}
|
||||
)
|
||||
data.append(row)
|
||||
break
|
||||
|
||||
return data
|
||||
@@ -229,8 +244,14 @@ def get_item_warehouse_combinations(filters: dict = None) -> dict:
|
||||
.select(
|
||||
bin.item_code,
|
||||
bin.warehouse,
|
||||
item.valuation_method,
|
||||
)
|
||||
.where(
|
||||
(item.is_stock_item == 1)
|
||||
& (item.has_serial_no == 0)
|
||||
& (warehouse.is_group == 0)
|
||||
& (warehouse.company == filters.company)
|
||||
)
|
||||
.where((item.is_stock_item == 1) & (item.has_serial_no == 0) & (warehouse.is_group == 0))
|
||||
)
|
||||
|
||||
if filters.item_code:
|
||||
@@ -243,37 +264,27 @@ def get_item_warehouse_combinations(filters: dict = None) -> dict:
|
||||
return query.run(as_dict=1)
|
||||
|
||||
|
||||
def has_difference(row, precision, difference_in):
|
||||
has_qty_difference = flt(row.difference_in_qty, precision) or flt(row.fifo_qty_diff, precision)
|
||||
has_value_difference = (
|
||||
flt(row.diff_value_diff, precision)
|
||||
or flt(row.fifo_value_diff, precision)
|
||||
or flt(row.fifo_difference_diff, precision)
|
||||
)
|
||||
has_valuation_difference = flt(row.valuation_diff, precision) or flt(
|
||||
row.fifo_valuation_diff, precision
|
||||
)
|
||||
def has_difference(row, precision, difference_in, valuation_method):
|
||||
if valuation_method == "Moving Average":
|
||||
qty_diff = flt(row.difference_in_qty, precision)
|
||||
value_diff = flt(row.diff_value_diff, precision)
|
||||
valuation_diff = flt(row.valuation_diff, precision)
|
||||
else:
|
||||
qty_diff = flt(row.difference_in_qty, precision) or flt(row.fifo_qty_diff, precision)
|
||||
value_diff = (
|
||||
flt(row.diff_value_diff, precision)
|
||||
or flt(row.fifo_value_diff, precision)
|
||||
or flt(row.fifo_difference_diff, precision)
|
||||
)
|
||||
valuation_diff = flt(row.valuation_diff, precision) or flt(row.fifo_valuation_diff, precision)
|
||||
|
||||
if difference_in == "Qty" and has_qty_difference:
|
||||
if difference_in == "Qty" and qty_diff:
|
||||
return True
|
||||
elif difference_in == "Value" and has_value_difference:
|
||||
elif difference_in == "Value" and value_diff:
|
||||
return True
|
||||
elif difference_in == "Valuation" and has_valuation_difference:
|
||||
elif difference_in == "Valuation" and valuation_diff:
|
||||
return True
|
||||
elif difference_in not in ["Qty", "Value", "Valuation"] and (
|
||||
has_qty_difference or has_value_difference or has_valuation_difference
|
||||
qty_diff or value_diff or valuation_diff
|
||||
):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def add_item_warehouse_details(row, item_warehouse):
|
||||
row.update(
|
||||
{
|
||||
"item_code": item_warehouse.item_code,
|
||||
"warehouse": item_warehouse.warehouse,
|
||||
}
|
||||
)
|
||||
|
||||
return row
|
||||
|
||||
@@ -369,7 +369,7 @@ Base,Basis,
|
||||
Base URL,Basis-URL,
|
||||
Based On,Basiert auf,
|
||||
Based On Payment Terms,Basierend auf Zahlungsbedingungen,
|
||||
Basic,Grundeinkommen,
|
||||
Basic,Basic,
|
||||
Batch,Charge,
|
||||
Batch Entries,Batch-Einträge,
|
||||
Batch ID is mandatory,Batch-ID ist obligatorisch,
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -4,7 +4,7 @@ googlemaps # used in ERPNext, but dependency is defined in Frappe
|
||||
pandas>=1.1.5,<2.0.0
|
||||
plaid-python~=7.2.1
|
||||
pycountry~=20.7.3
|
||||
PyGithub~=1.54.1
|
||||
PyGithub~=2.1.1
|
||||
python-stdnum~=1.16
|
||||
python-youtube~=0.8.0
|
||||
taxjar~=1.9.2
|
||||
|
||||
Reference in New Issue
Block a user