Merge pull request #25858 from alyf-de/item-tax-templates
feat: Item Tax Templates for Germany
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 1808005..f813425 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -17,7 +17,7 @@
var me = this;
this._super();
- this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice', 'Timesheet'];
+ this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice', 'Timesheet', 'POS Invoice Merge Log', 'POS Closing Entry'];
if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) {
// show debit_to in print format
this.frm.set_df_property("debit_to", "print_hide", 0);
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 023f4b0..f8b5179 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -531,7 +531,7 @@
# set pos values in items
for item in self.get("items"):
if item.get('item_code'):
- profile_details = get_pos_profile_item_details(pos, frappe._dict(item.as_dict()), pos)
+ profile_details = get_pos_profile_item_details(pos, frappe._dict(item.as_dict()), pos, update_data=True)
for fname, val in iteritems(profile_details):
if (not for_validate) or (for_validate and not item.get(fname)):
item.set(fname, val)
diff --git a/erpnext/education/utils.py b/erpnext/education/utils.py
index 8f51fef..9db8a4a 100644
--- a/erpnext/education/utils.py
+++ b/erpnext/education/utils.py
@@ -219,7 +219,6 @@
try:
quiz = frappe.get_doc("Quiz", quiz_name)
questions = quiz.get_questions()
- duration = quiz.duration
except:
frappe.throw(_("Quiz {0} does not exist").format(quiz_name), frappe.DoesNotExistError)
return None
@@ -236,15 +235,17 @@
return {
'questions': questions,
'activity': None,
- 'duration':duration
+ 'is_time_bound': quiz.is_time_bound,
+ 'duration': quiz.duration
}
student = get_current_student()
course_enrollment = get_enrollment("course", course, student.name)
status, score, result, time_taken = check_quiz_completion(quiz, course_enrollment)
return {
- 'questions': questions,
+ 'questions': questions,
'activity': {'is_complete': status, 'score': score, 'result': result, 'time_taken': time_taken},
+ 'is_time_bound': quiz.is_time_bound,
'duration': quiz.duration
}
@@ -372,9 +373,9 @@
def check_quiz_completion(quiz, enrollment_name):
attempts = frappe.get_all("Quiz Activity",
filters={
- 'enrollment': enrollment_name,
+ 'enrollment': enrollment_name,
'quiz': quiz.name
- },
+ },
fields=["name", "activity_date", "score", "status", "time_taken"]
)
status = False if quiz.max_attempts == 0 else bool(len(attempts) >= quiz.max_attempts)
@@ -389,4 +390,4 @@
time_taken = attempts[0]['time_taken']
if result == 'Pass':
status = True
- return status, score, result, time_taken
\ No newline at end of file
+ return status, score, result, time_taken
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index fb26062..d764db3 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -433,7 +433,8 @@
def make_stock_entry(source_name, target_doc=None):
def update_item(obj, target, source_parent):
target.t_warehouse = source_parent.wip_warehouse
- target.conversion_factor = 1
+ if not target.conversion_factor:
+ target.conversion_factor = 1
def set_missing_values(source, target):
target.purpose = "Material Transfer for Manufacture"
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index afdf081..877503b 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -115,10 +115,23 @@
status = "Cancelled"
return status
- def validate_dates(self):
+ def validate_dates(self, joining_date=None, relieving_date=None):
if date_diff(self.end_date, self.start_date) < 0:
frappe.throw(_("To date cannot be before From date"))
+ if not joining_date:
+ joining_date, relieving_date = frappe.get_cached_value(
+ "Employee",
+ self.employee,
+ ("date_of_joining", "relieving_date")
+ )
+
+ if date_diff(self.end_date, joining_date) < 0:
+ frappe.throw(_("Cannot create Salary Slip for Employee joining after Payroll Period"))
+
+ if relieving_date and date_diff(relieving_date, self.start_date) < 0:
+ frappe.throw(_("Cannot create Salary Slip for Employee who has left before Payroll Period"))
+
def is_rounding_total_disabled(self):
return cint(frappe.db.get_single_value("Payroll Settings", "disable_rounded_total"))
@@ -154,9 +167,14 @@
if not self.salary_slip_based_on_timesheet:
self.get_date_details()
- self.validate_dates()
- joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
- ["date_of_joining", "relieving_date"])
+
+ joining_date, relieving_date = frappe.get_cached_value(
+ "Employee",
+ self.employee,
+ ("date_of_joining", "relieving_date")
+ )
+
+ self.validate_dates(joining_date, relieving_date)
#getin leave details
self.get_working_days_details(joining_date, relieving_date)
@@ -492,11 +510,39 @@
def get_data_for_eval(self):
'''Returns data for evaluating formula'''
data = frappe._dict()
+ employee = frappe.get_doc("Employee", self.employee).as_dict()
- data.update(frappe.get_doc("Salary Structure Assignment",
- {"employee": self.employee, "salary_structure": self.salary_structure}).as_dict())
+ start_date = getdate(self.start_date)
+ date_to_validate = (
+ employee.date_of_joining
+ if employee.date_of_joining > start_date
+ else start_date
+ )
- data.update(frappe.get_doc("Employee", self.employee).as_dict())
+ salary_structure_assignment = frappe.get_value(
+ "Salary Structure Assignment",
+ {
+ "employee": self.employee,
+ "salary_structure": self.salary_structure,
+ "from_date": ("<=", date_to_validate),
+ "docstatus": 1,
+ },
+ "*",
+ order_by="from_date desc",
+ as_dict=True,
+ )
+
+ if not salary_structure_assignment:
+ frappe.throw(
+ _("Please assign a Salary Structure for Employee {0} "
+ "applicable from or before {1} first").format(
+ frappe.bold(self.employee_name),
+ frappe.bold(formatdate(date_to_validate)),
+ )
+ )
+
+ data.update(salary_structure_assignment)
+ data.update(employee)
data.update(self.as_dict())
# set values for components
diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py
index 01e4170..9e7db97 100644
--- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py
@@ -8,7 +8,6 @@
import calendar
import random
from erpnext.accounts.utils import get_fiscal_year
-from frappe.utils.make_random import get_random
from frappe.utils import getdate, nowdate, add_days, add_months, flt, get_first_day, get_last_day, cstr
from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_month_details
@@ -155,12 +154,14 @@
self.assertEqual(ss.gross_pay, 78000)
def test_payment_days(self):
+ from erpnext.payroll.doctype.salary_structure.test_salary_structure import create_salary_structure_assignment
+
no_of_days = self.get_no_of_days()
# Holidays not included in working days
frappe.db.set_value("Payroll Settings", None, "include_holidays_in_total_working_days", 1)
# set joinng date in the same month
- make_employee("test_payment_days@salary.com")
+ employee = make_employee("test_payment_days@salary.com")
if getdate(nowdate()).day >= 15:
relieving_date = getdate(add_days(nowdate(),-10))
date_of_joining = getdate(add_days(nowdate(),-10))
@@ -174,25 +175,30 @@
date_of_joining = getdate(nowdate())
relieving_date = getdate(nowdate())
- frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_payment_days@salary.com"}, "name"), "date_of_joining", date_of_joining)
- frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_payment_days@salary.com"}, "name"), "relieving_date", None)
- frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_payment_days@salary.com"}, "name"), "status", "Active")
+ frappe.db.set_value("Employee", employee, {
+ "date_of_joining": date_of_joining,
+ "relieving_date": None,
+ "status": "Active"
+ })
- ss = make_employee_salary_slip("test_payment_days@salary.com", "Monthly", "Test Payment Days")
+ salary_structure = "Test Payment Days"
+ ss = make_employee_salary_slip("test_payment_days@salary.com", "Monthly", salary_structure)
self.assertEqual(ss.total_working_days, no_of_days[0])
self.assertEqual(ss.payment_days, (no_of_days[0] - getdate(date_of_joining).day + 1))
# set relieving date in the same month
- frappe.db.set_value("Employee",frappe.get_value("Employee",
- {"employee_name":"test_payment_days@salary.com"}, "name"), "date_of_joining", (add_days(nowdate(),-60)))
- frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_payment_days@salary.com"}, "name"), "relieving_date", relieving_date)
- frappe.db.set_value("Employee", frappe.get_value("Employee",
- {"employee_name":"test_payment_days@salary.com"}, "name"), "status", "Left")
+ frappe.db.set_value("Employee", employee, {
+ "date_of_joining": add_days(nowdate(),-60),
+ "relieving_date": relieving_date,
+ "status": "Left"
+ })
+
+ if date_of_joining.day > 1:
+ self.assertRaises(frappe.ValidationError, ss.save)
+
+ create_salary_structure_assignment(employee, salary_structure)
+ ss.reload()
ss.save()
self.assertEqual(ss.total_working_days, no_of_days[0])
@@ -285,6 +291,7 @@
def test_multi_currency_salary_slip(self):
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
+
applicant = make_employee("test_multi_currency_salary_slip@salary.com", company="_Test Company")
frappe.db.sql("""delete from `tabSalary Structure` where name='Test Multi Currency Salary Slip'""")
salary_structure = make_salary_structure("Test Multi Currency Salary Slip", "Monthly", employee=applicant, company="_Test Company", currency='USD')
@@ -325,7 +332,8 @@
def test_component_wise_year_to_date_computation(self):
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
- applicant = make_employee("test_ytd@salary.com", company="_Test Company")
+ employee_name = "test_component_wise_ytd@salary.com"
+ applicant = make_employee(employee_name, company="_Test Company")
payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company")
@@ -336,13 +344,13 @@
"Monthly", employee=applicant, company="_Test Company", currency="INR", payroll_period=payroll_period)
# clear salary slip for this employee
- frappe.db.sql("DELETE FROM `tabSalary Slip` where employee_name = 'test_ytd@salary.com'")
+ frappe.db.sql("DELETE FROM `tabSalary Slip` where employee_name = '%s'" % employee_name)
create_salary_slips_for_payroll_period(applicant, salary_structure.name,
payroll_period, deduct_random=False, num=3)
salary_slips = frappe.get_all("Salary Slip", fields=["name"], filters={"employee_name":
- "test_ytd@salary.com"}, order_by = "posting_date")
+ employee_name}, order_by="posting_date")
year_to_date = dict()
for slip in salary_slips:
@@ -380,10 +388,10 @@
from erpnext.payroll.doctype.salary_structure.test_salary_structure import \
make_salary_structure, create_salary_structure_assignment
+
salary_structure = make_salary_structure("Stucture to test tax", "Monthly",
- other_details={"max_benefits": 100000}, test_tax=True)
- create_salary_structure_assignment(employee, salary_structure.name,
- payroll_period.start_date)
+ other_details={"max_benefits": 100000}, test_tax=True,
+ employee=employee, payroll_period=payroll_period)
# create salary slip for whole period deducting tax only on last period
# to find the total tax amount paid
@@ -469,6 +477,7 @@
def make_employee_salary_slip(user, payroll_frequency, salary_structure=None):
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
+
if not salary_structure:
salary_structure = payroll_frequency + " Salary Structure Test for Salary Slip"
diff --git a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py
index 36387f2..dce6b7a 100644
--- a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py
+++ b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py
@@ -6,7 +6,7 @@
import unittest
import erpnext
from frappe.utils.make_random import get_random
-from frappe.utils import nowdate, add_days, add_years, getdate, add_months
+from frappe.utils import nowdate, add_years, get_first_day, date_diff
from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_earning_salary_component,\
make_deduction_salary_component, make_employee_salary_slip, create_tax_slab
@@ -113,8 +113,9 @@
sal_struct = make_salary_structure("Salary Structure Multi Currency", "Monthly", currency='USD')
self.assertEqual(sal_struct.currency, 'USD')
-def make_salary_structure(salary_structure, payroll_frequency, employee=None, dont_submit=False, other_details=None,
- test_tax=False, company=None, currency=erpnext.get_default_currency(), payroll_period=None):
+def make_salary_structure(salary_structure, payroll_frequency, employee=None,
+ from_date=None, dont_submit=False, other_details=None,test_tax=False,
+ company=None, currency=erpnext.get_default_currency(), payroll_period=None):
if test_tax:
frappe.db.sql("""delete from `tabSalary Structure` where name=%s""",(salary_structure))
@@ -139,10 +140,23 @@
else:
salary_structure_doc = frappe.get_doc("Salary Structure", salary_structure)
+ filters = {'employee':employee, 'docstatus': 1}
+ if not from_date and payroll_period:
+ from_date = payroll_period.start_date
+
+ if from_date:
+ filters['from_date'] = from_date
+
if employee and not frappe.db.get_value("Salary Structure Assignment",
- {'employee':employee, 'docstatus': 1}) and salary_structure_doc.docstatus==1:
- create_salary_structure_assignment(employee, salary_structure, company=company, currency=currency,
- payroll_period=payroll_period)
+ filters) and salary_structure_doc.docstatus==1:
+ create_salary_structure_assignment(
+ employee,
+ salary_structure,
+ from_date=from_date,
+ company=company,
+ currency=currency,
+ payroll_period=payroll_period
+ )
return salary_structure_doc
@@ -165,12 +179,13 @@
salary_structure_assignment.base = 50000
salary_structure_assignment.variable = 5000
- if getdate(nowdate()).day == 1:
- date = from_date or nowdate()
- else:
- date = from_date or add_days(nowdate(), -1)
+ if not from_date:
+ from_date = get_first_day(nowdate())
+ joining_date = frappe.get_cached_value("Employee", employee, "date_of_joining")
+ if date_diff(joining_date, from_date) > 0:
+ from_date = joining_date
- salary_structure_assignment.from_date = date
+ salary_structure_assignment.from_date = from_date
salary_structure_assignment.salary_structure = salary_structure
salary_structure_assignment.currency = currency
salary_structure_assignment.payroll_payable_account = get_payable_account(company)
@@ -183,4 +198,4 @@
def get_payable_account(company=None):
if not company:
company = erpnext.get_default_company()
- return frappe.db.get_value("Company", company, "default_payroll_payable_account")
\ No newline at end of file
+ return frappe.db.get_value("Company", company, "default_payroll_payable_account")
diff --git a/erpnext/public/js/education/lms/quiz.js b/erpnext/public/js/education/lms/quiz.js
index 32fa4ab..66160a7 100644
--- a/erpnext/public/js/education/lms/quiz.js
+++ b/erpnext/public/js/education/lms/quiz.js
@@ -20,10 +20,8 @@
}
make(data) {
- if (data.duration) {
- const timer_display = document.createElement("div");
- timer_display.classList.add("lms-timer", "float-right", "font-weight-bold");
- document.getElementsByClassName("lms-title")[0].appendChild(timer_display);
+ if (data.is_time_bound) {
+ $(".lms-timer").removeClass("hide");
if (!data.activity || (data.activity && !data.activity.is_complete)) {
this.initialiseTimer(data.duration);
this.is_time_bound = true;
@@ -118,7 +116,7 @@
quiz_response: this.get_selected(),
course: this.course,
program: this.program,
- time_taken: this.is_time_bound ? this.time_taken : ""
+ time_taken: this.is_time_bound ? this.time_taken : 0
}).then(res => {
this.submit_btn.remove()
if (!res.message) {
@@ -237,4 +235,4 @@
this.options = option_list
this.wrapper.appendChild(options_wrapper)
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py
index cb811df..7742f24 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -8,38 +8,52 @@
from erpnext.accounts.doctype.pos_profile.pos_profile import get_item_groups
from erpnext.accounts.doctype.pos_invoice.pos_invoice import get_stock_availability
-from six import string_types
+def search_by_term(search_term, warehouse, price_list):
+ result = search_for_serial_or_batch_or_barcode_number(search_term)
+
+ item_code = result.get("item_code") or search_term
+ serial_no = result.get("serial_no") or ""
+ batch_no = result.get("batch_no") or ""
+ barcode = result.get("barcode") or ""
+
+ if result:
+ item_info = frappe.db.get_value("Item", item_code,
+ ["name as item_code", "item_name", "description", "stock_uom", "image as item_image", "is_stock_item"],
+ as_dict=1)
+
+ item_stock_qty = get_stock_availability(item_code, warehouse)
+ price_list_rate, currency = frappe.db.get_value('Item Price', {
+ 'price_list': price_list,
+ 'item_code': item_code
+ }, ["price_list_rate", "currency"])
+
+ item_info.update({
+ 'serial_no': serial_no,
+ 'batch_no': batch_no,
+ 'barcode': barcode,
+ 'price_list_rate': price_list_rate,
+ 'currency': currency,
+ 'actual_qty': item_stock_qty
+ })
+
+ return {'items': [item_info]}
@frappe.whitelist()
-def get_items(start, page_length, price_list, item_group, pos_profile, search_value=""):
- data = dict()
+def get_items(start, page_length, price_list, item_group, pos_profile, search_term=""):
+ warehouse, hide_unavailable_items = frappe.db.get_value(
+ 'POS Profile', pos_profile, ['warehouse', 'hide_unavailable_items'])
+
result = []
- warehouse, hide_unavailable_items = frappe.db.get_value('POS Profile', pos_profile, ['warehouse', 'hide_unavailable_items'])
+ if search_term:
+ result = search_by_term(search_term, warehouse, price_list)
+ if result:
+ return result
if not frappe.db.exists('Item Group', item_group):
item_group = get_root_of('Item Group')
- if search_value:
- data = search_serial_or_batch_or_barcode_number(search_value)
-
- item_code = data.get("item_code") if data.get("item_code") else search_value
- serial_no = data.get("serial_no") if data.get("serial_no") else ""
- batch_no = data.get("batch_no") if data.get("batch_no") else ""
- barcode = data.get("barcode") if data.get("barcode") else ""
-
- if data:
- item_info = frappe.db.get_value(
- "Item", data.get("item_code"),
- ["name as item_code", "item_name", "description", "stock_uom", "image as item_image", "is_stock_item"]
- , as_dict=1)
- item_info.setdefault('serial_no', serial_no)
- item_info.setdefault('batch_no', batch_no)
- item_info.setdefault('barcode', barcode)
-
- return { 'items': [item_info] }
-
- condition = get_conditions(item_code, serial_no, batch_no, barcode)
+ condition = get_conditions(search_term)
condition += get_item_group_condition(pos_profile)
lft, rgt = frappe.db.get_value('Item Group', item_group, ['lft', 'rgt'])
@@ -106,14 +120,10 @@
})
result.append(row)
- res = {
- 'items': result
- }
-
- return res
+ return {'items': result}
@frappe.whitelist()
-def search_serial_or_batch_or_barcode_number(search_value):
+def search_for_serial_or_batch_or_barcode_number(search_value):
# search barcode no
barcode_data = frappe.db.get_value('Item Barcode', {'barcode': search_value}, ['barcode', 'parent as item_code'], as_dict=True)
if barcode_data:
@@ -139,27 +149,21 @@
return items
-def get_conditions(item_code, serial_no, batch_no, barcode):
- if serial_no or batch_no or barcode:
- return "item.name = {0}".format(frappe.db.escape(item_code))
-
- return make_condition(item_code)
-
-def make_condition(item_code):
+def get_conditions(search_term):
condition = "("
- condition += """item.name like {item_code}
- or item.item_name like {item_code}""".format(item_code = frappe.db.escape('%' + item_code + '%'))
- condition += add_search_fields_condition(item_code)
+ condition += """item.name like {search_term}
+ or item.item_name like {search_term}""".format(search_term=frappe.db.escape('%' + search_term + '%'))
+ condition += add_search_fields_condition(search_term)
condition += ")"
return condition
-def add_search_fields_condition(item_code):
+def add_search_fields_condition(search_term):
condition = ''
search_fields = frappe.get_all('POS Search Fields', fields = ['fieldname'])
if search_fields:
for field in search_fields:
- condition += " or item.{0} like {1}".format(field['fieldname'], frappe.db.escape('%' + item_code + '%'))
+ condition += " or item.`{0}` like {1}".format(field['fieldname'], frappe.db.escape('%' + search_term + '%'))
return condition
def get_item_group_condition(pos_profile):
diff --git a/erpnext/selling/page/point_of_sale/pos_item_details.js b/erpnext/selling/page/point_of_sale/pos_item_details.js
index df62696..5e09df8 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_details.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_details.js
@@ -133,13 +133,24 @@
this.$item_description.html(get_description_html());
this.$item_price.html(format_currency(price_list_rate, this.currency));
if (image) {
- this.$item_image.html(`<img src="${image}" alt="${image}">`);
+ this.$item_image.html(
+ `<img
+ onerror="cur_pos.item_details.handle_broken_image(this)"
+ class="h-full" src="${image}"
+ alt="${frappe.get_abbr(item_name)}"
+ style="object-fit: cover;">`
+ );
} else {
this.$item_image.html(`<div class="item-abbr">${frappe.get_abbr(item_name)}</div>`);
}
}
+ handle_broken_image($img) {
+ const item_abbr = $($img).attr('alt');
+ $($img).replaceWith(`<div class="item-abbr">${item_abbr}</div>`);
+ }
+
render_discount_dom(item) {
if (item.discount_percentage) {
this.$dicount_section.html(
diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js
index 5b48725..64c529e 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_selector.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js
@@ -51,7 +51,7 @@
});
}
- get_items({start = 0, page_length = 40, search_value=''}) {
+ get_items({start = 0, page_length = 40, search_term=''}) {
const doc = this.events.get_frm().doc;
const price_list = (doc && doc.selling_price_list) || this.price_list;
let { item_group, pos_profile } = this;
@@ -61,7 +61,7 @@
return frappe.call({
method: "erpnext.selling.page.point_of_sale.point_of_sale.get_items",
freeze: true,
- args: { start, page_length, price_list, item_group, search_value, pos_profile },
+ args: { start, page_length, price_list, item_group, search_term, pos_profile },
});
}
@@ -80,6 +80,7 @@
// eslint-disable-next-line no-unused-vars
const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom, price_list_rate } = item;
const indicator_color = actual_qty > 10 ? "green" : actual_qty <= 0 ? "red" : "orange";
+ const precision = flt(price_list_rate, 2) % 1 != 0 ? 2 : 0;
let qty_to_display = actual_qty;
@@ -121,7 +122,7 @@
<div class="item-name">
${frappe.ellipsis(item.item_name, 18)}
</div>
- <div class="item-rate">${format_currency(price_list_rate, item.currency, 0) || 0}</div>
+ <div class="item-rate">${format_currency(price_list_rate, item.currency, precision) || 0}</div>
</div>
</div>`
);
@@ -302,7 +303,7 @@
}
}
- this.get_items({ search_value: search_term })
+ this.get_items({ search_term })
.then(({ message }) => {
// eslint-disable-next-line no-unused-vars
const { items, serial_no, batch_no, barcode } = message;
diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js
index 600f160..156fb77 100644
--- a/erpnext/selling/page/point_of_sale/pos_payment.js
+++ b/erpnext/selling/page/point_of_sale/pos_payment.js
@@ -171,7 +171,7 @@
this.setup_listener_for_payments();
- this.$payment_modes.on('click', '.shortcut', () => {
+ this.$payment_modes.on('click', '.shortcut', function() {
const value = $(this).attr('data-value');
me.selected_mode.set_value(value);
});
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
index 38f8de7..ece9fb5 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
@@ -12,10 +12,6 @@
class TransactionDeletionRecord(Document):
def validate(self):
frappe.only_for('System Manager')
- company_obj = frappe.get_doc('Company', self.company)
- if frappe.session.user != company_obj.owner and frappe.session.user != 'Administrator':
- frappe.throw(_('Transactions can only be deleted by the creator of the Company or the Administrator.'),
- frappe.PermissionError)
doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
for doctype in self.doctypes_to_be_ignored:
if doctype.doctype_name not in doctypes_to_be_ignored_list:
diff --git a/erpnext/www/lms/content.html b/erpnext/www/lms/content.html
index 15afb09..d22ef66 100644
--- a/erpnext/www/lms/content.html
+++ b/erpnext/www/lms/content.html
@@ -64,6 +64,7 @@
</div>
<div class="lms-title">
<h2>{{ content.name }} <span class="small text-muted">({{ position + 1 }}/{{length}})</span></h2>
+ <div class="lms-timer float-right fond-weight-bold hide"></div>
</div>
{% endmacro %}