Merge branch 'develop' into mr-to-order-and-receive-report
This commit is contained in:
commit
e0d5c6118f
@ -1595,6 +1595,56 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
self.assertEqual(expected_values[gle.account][1], gle.debit)
|
self.assertEqual(expected_values[gle.account][1], gle.debit)
|
||||||
self.assertEqual(expected_values[gle.account][2], gle.credit)
|
self.assertEqual(expected_values[gle.account][2], gle.credit)
|
||||||
|
|
||||||
|
def test_rounding_adjustment_3(self):
|
||||||
|
si = create_sales_invoice(do_not_save=True)
|
||||||
|
si.items = []
|
||||||
|
for d in [(1122, 2), (1122.01, 1), (1122.01, 1)]:
|
||||||
|
si.append("items", {
|
||||||
|
"item_code": "_Test Item",
|
||||||
|
"gst_hsn_code": "999800",
|
||||||
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
|
"qty": d[1],
|
||||||
|
"rate": d[0],
|
||||||
|
"income_account": "Sales - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC"
|
||||||
|
})
|
||||||
|
for tax_account in ["_Test Account VAT - _TC", "_Test Account Service Tax - _TC"]:
|
||||||
|
si.append("taxes", {
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"account_head": tax_account,
|
||||||
|
"description": tax_account,
|
||||||
|
"rate": 6,
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"included_in_print_rate": 1
|
||||||
|
})
|
||||||
|
si.save()
|
||||||
|
si.submit()
|
||||||
|
self.assertEqual(si.net_total, 4007.16)
|
||||||
|
self.assertEqual(si.grand_total, 4488.02)
|
||||||
|
self.assertEqual(si.total_taxes_and_charges, 480.86)
|
||||||
|
self.assertEqual(si.rounding_adjustment, -0.02)
|
||||||
|
|
||||||
|
expected_values = dict((d[0], d) for d in [
|
||||||
|
[si.debit_to, 4488.0, 0.0],
|
||||||
|
["_Test Account Service Tax - _TC", 0.0, 240.43],
|
||||||
|
["_Test Account VAT - _TC", 0.0, 240.43],
|
||||||
|
["Sales - _TC", 0.0, 4007.15],
|
||||||
|
["Round Off - _TC", 0.01, 0]
|
||||||
|
])
|
||||||
|
|
||||||
|
gl_entries = frappe.db.sql("""select account, debit, credit
|
||||||
|
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||||
|
order by account asc""", si.name, as_dict=1)
|
||||||
|
|
||||||
|
debit_credit_diff = 0
|
||||||
|
for gle in gl_entries:
|
||||||
|
self.assertEqual(expected_values[gle.account][0], gle.account)
|
||||||
|
self.assertEqual(expected_values[gle.account][1], gle.debit)
|
||||||
|
self.assertEqual(expected_values[gle.account][2], gle.credit)
|
||||||
|
debit_credit_diff += (gle.debit - gle.credit)
|
||||||
|
|
||||||
|
self.assertEqual(debit_credit_diff, 0)
|
||||||
|
|
||||||
def test_sales_invoice_with_shipping_rule(self):
|
def test_sales_invoice_with_shipping_rule(self):
|
||||||
from erpnext.accounts.doctype.shipping_rule.test_shipping_rule import create_shipping_rule
|
from erpnext.accounts.doctype.shipping_rule.test_shipping_rule import create_shipping_rule
|
||||||
|
|
||||||
|
|||||||
@ -55,5 +55,8 @@ def validate_disabled(doc):
|
|||||||
frappe.throw(_("Disabled template must not be default template"))
|
frappe.throw(_("Disabled template must not be default template"))
|
||||||
|
|
||||||
def validate_for_tax_category(doc):
|
def validate_for_tax_category(doc):
|
||||||
|
if not doc.tax_category:
|
||||||
|
return
|
||||||
|
|
||||||
if frappe.db.exists(doc.doctype, {"company": doc.company, "tax_category": doc.tax_category, "disabled": 0, "name": ["!=", doc.name]}):
|
if frappe.db.exists(doc.doctype, {"company": doc.company, "tax_category": doc.tax_category, "disabled": 0, "name": ["!=", doc.name]}):
|
||||||
frappe.throw(_("A template with tax category {0} already exists. Only one template is allowed with each tax category").format(frappe.bold(doc.tax_category)))
|
frappe.throw(_("A template with tax category {0} already exists. Only one template is allowed with each tax category").format(frappe.bold(doc.tax_category)))
|
||||||
|
|||||||
@ -274,7 +274,7 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision):
|
|||||||
debit_credit_diff += flt(d.credit)
|
debit_credit_diff += flt(d.credit)
|
||||||
round_off_account_exists = True
|
round_off_account_exists = True
|
||||||
|
|
||||||
if round_off_account_exists and abs(debit_credit_diff) <= (1.0 / (10**precision)):
|
if round_off_account_exists and abs(debit_credit_diff) < (1.0 / (10**precision)):
|
||||||
gl_map.remove(round_off_gle)
|
gl_map.remove(round_off_gle)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
"actions": [],
|
"actions": [],
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2017-10-09 14:26:29.612365",
|
"creation": "2022-01-17 18:36:51.450395",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
@ -121,7 +121,7 @@
|
|||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Status",
|
"label": "Status",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Draft\nPaid\nUnpaid\nClaimed\nCancelled",
|
"options": "Draft\nPaid\nUnpaid\nClaimed\nReturned\nPartly Claimed and Returned\nCancelled",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -200,7 +200,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-09-11 18:38:38.617478",
|
"modified": "2022-01-17 19:33:52.345823",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Employee Advance",
|
"name": "Employee Advance",
|
||||||
@ -237,5 +237,41 @@
|
|||||||
"search_fields": "employee,employee_name",
|
"search_fields": "employee,employee_name",
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"color": "Red",
|
||||||
|
"custom": 1,
|
||||||
|
"title": "Draft"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "Green",
|
||||||
|
"custom": 1,
|
||||||
|
"title": "Paid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "Orange",
|
||||||
|
"custom": 1,
|
||||||
|
"title": "Unpaid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "Blue",
|
||||||
|
"custom": 1,
|
||||||
|
"title": "Claimed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "Gray",
|
||||||
|
"title": "Returned"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "Yellow",
|
||||||
|
"title": "Partly Claimed and Returned"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "Red",
|
||||||
|
"custom": 1,
|
||||||
|
"title": "Cancelled"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title_field": "employee_name",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
@ -27,19 +27,33 @@ class EmployeeAdvance(Document):
|
|||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
self.ignore_linked_doctypes = ('GL Entry')
|
self.ignore_linked_doctypes = ('GL Entry')
|
||||||
|
self.set_status(update=True)
|
||||||
|
|
||||||
|
def set_status(self, update=False):
|
||||||
|
precision = self.precision("paid_amount")
|
||||||
|
total_amount = flt(flt(self.claimed_amount) + flt(self.return_amount), precision)
|
||||||
|
status = None
|
||||||
|
|
||||||
def set_status(self):
|
|
||||||
if self.docstatus == 0:
|
if self.docstatus == 0:
|
||||||
self.status = "Draft"
|
status = "Draft"
|
||||||
if self.docstatus == 1:
|
elif self.docstatus == 1:
|
||||||
if self.claimed_amount and flt(self.claimed_amount) == flt(self.paid_amount):
|
if flt(self.claimed_amount) > 0 and flt(self.claimed_amount, precision) == flt(self.paid_amount, precision):
|
||||||
self.status = "Claimed"
|
status = "Claimed"
|
||||||
elif self.paid_amount and self.advance_amount == flt(self.paid_amount):
|
elif flt(self.return_amount) > 0 and flt(self.return_amount, precision) == flt(self.paid_amount, precision):
|
||||||
self.status = "Paid"
|
status = "Returned"
|
||||||
|
elif flt(self.claimed_amount) > 0 and (flt(self.return_amount) > 0) and total_amount == flt(self.paid_amount, precision):
|
||||||
|
status = "Partly Claimed and Returned"
|
||||||
|
elif flt(self.paid_amount) > 0 and flt(self.advance_amount, precision) == flt(self.paid_amount, precision):
|
||||||
|
status = "Paid"
|
||||||
else:
|
else:
|
||||||
self.status = "Unpaid"
|
status = "Unpaid"
|
||||||
elif self.docstatus == 2:
|
elif self.docstatus == 2:
|
||||||
self.status = "Cancelled"
|
status = "Cancelled"
|
||||||
|
|
||||||
|
if update:
|
||||||
|
self.db_set("status", status)
|
||||||
|
else:
|
||||||
|
self.status = status
|
||||||
|
|
||||||
def set_total_advance_paid(self):
|
def set_total_advance_paid(self):
|
||||||
gle = frappe.qb.DocType("GL Entry")
|
gle = frappe.qb.DocType("GL Entry")
|
||||||
@ -85,9 +99,7 @@ class EmployeeAdvance(Document):
|
|||||||
|
|
||||||
self.db_set("paid_amount", paid_amount)
|
self.db_set("paid_amount", paid_amount)
|
||||||
self.db_set("return_amount", return_amount)
|
self.db_set("return_amount", return_amount)
|
||||||
self.set_status()
|
self.set_status(update=True)
|
||||||
frappe.db.set_value("Employee Advance", self.name , "status", self.status)
|
|
||||||
|
|
||||||
|
|
||||||
def update_claimed_amount(self):
|
def update_claimed_amount(self):
|
||||||
claimed_amount = frappe.db.sql("""
|
claimed_amount = frappe.db.sql("""
|
||||||
@ -103,8 +115,8 @@ class EmployeeAdvance(Document):
|
|||||||
|
|
||||||
frappe.db.set_value("Employee Advance", self.name, "claimed_amount", flt(claimed_amount))
|
frappe.db.set_value("Employee Advance", self.name, "claimed_amount", flt(claimed_amount))
|
||||||
self.reload()
|
self.reload()
|
||||||
self.set_status()
|
self.set_status(update=True)
|
||||||
frappe.db.set_value("Employee Advance", self.name, "status", self.status)
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_pending_amount(employee, posting_date):
|
def get_pending_amount(employee, posting_date):
|
||||||
@ -222,7 +234,8 @@ def make_return_entry(employee, company, employee_advance_name, return_amount,
|
|||||||
'reference_name': employee_advance_name,
|
'reference_name': employee_advance_name,
|
||||||
'party_type': 'Employee',
|
'party_type': 'Employee',
|
||||||
'party': employee,
|
'party': employee,
|
||||||
'is_advance': 'Yes'
|
'is_advance': 'Yes',
|
||||||
|
'cost_center': erpnext.get_default_cost_center(company)
|
||||||
})
|
})
|
||||||
|
|
||||||
bank_amount = flt(return_amount) if bank_cash_account.account_currency==currency \
|
bank_amount = flt(return_amount) if bank_cash_account.account_currency==currency \
|
||||||
@ -233,7 +246,8 @@ def make_return_entry(employee, company, employee_advance_name, return_amount,
|
|||||||
"debit_in_account_currency": bank_amount,
|
"debit_in_account_currency": bank_amount,
|
||||||
"account_currency": bank_cash_account.account_currency,
|
"account_currency": bank_cash_account.account_currency,
|
||||||
"account_type": bank_cash_account.account_type,
|
"account_type": bank_cash_account.account_type,
|
||||||
"exchange_rate": flt(exchange_rate) if bank_cash_account.account_currency == currency else 1
|
"exchange_rate": flt(exchange_rate) if bank_cash_account.account_currency == currency else 1,
|
||||||
|
"cost_center": erpnext.get_default_cost_center(company)
|
||||||
})
|
})
|
||||||
|
|
||||||
return je.as_dict()
|
return je.as_dict()
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import nowdate
|
from frappe.utils import flt, nowdate
|
||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
from erpnext.hr.doctype.employee.test_employee import make_employee
|
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||||
@ -12,12 +12,21 @@ from erpnext.hr.doctype.employee_advance.employee_advance import (
|
|||||||
EmployeeAdvanceOverPayment,
|
EmployeeAdvanceOverPayment,
|
||||||
create_return_through_additional_salary,
|
create_return_through_additional_salary,
|
||||||
make_bank_entry,
|
make_bank_entry,
|
||||||
|
make_return_entry,
|
||||||
|
)
|
||||||
|
from erpnext.hr.doctype.expense_claim.expense_claim import get_advances
|
||||||
|
from erpnext.hr.doctype.expense_claim.test_expense_claim import (
|
||||||
|
get_payable_account,
|
||||||
|
make_expense_claim,
|
||||||
)
|
)
|
||||||
from erpnext.payroll.doctype.salary_component.test_salary_component import create_salary_component
|
from erpnext.payroll.doctype.salary_component.test_salary_component import create_salary_component
|
||||||
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
|
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
|
||||||
|
|
||||||
|
|
||||||
class TestEmployeeAdvance(unittest.TestCase):
|
class TestEmployeeAdvance(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
frappe.db.delete("Employee Advance")
|
||||||
|
|
||||||
def test_paid_amount_and_status(self):
|
def test_paid_amount_and_status(self):
|
||||||
employee_name = make_employee("_T@employe.advance")
|
employee_name = make_employee("_T@employe.advance")
|
||||||
advance = make_employee_advance(employee_name)
|
advance = make_employee_advance(employee_name)
|
||||||
@ -52,9 +61,102 @@ class TestEmployeeAdvance(unittest.TestCase):
|
|||||||
self.assertEqual(advance.paid_amount, 0)
|
self.assertEqual(advance.paid_amount, 0)
|
||||||
self.assertEqual(advance.status, "Unpaid")
|
self.assertEqual(advance.status, "Unpaid")
|
||||||
|
|
||||||
|
advance.cancel()
|
||||||
|
advance.reload()
|
||||||
|
self.assertEqual(advance.status, "Cancelled")
|
||||||
|
|
||||||
|
def test_claimed_status(self):
|
||||||
|
# CLAIMED Status check, full amount claimed
|
||||||
|
payable_account = get_payable_account("_Test Company")
|
||||||
|
claim = make_expense_claim(payable_account, 1000, 1000, "_Test Company", "Travel Expenses - _TC", do_not_submit=True)
|
||||||
|
|
||||||
|
advance = make_employee_advance(claim.employee)
|
||||||
|
pe = make_payment_entry(advance)
|
||||||
|
pe.submit()
|
||||||
|
|
||||||
|
claim = get_advances_for_claim(claim, advance.name)
|
||||||
|
claim.save()
|
||||||
|
claim.submit()
|
||||||
|
|
||||||
|
advance.reload()
|
||||||
|
self.assertEqual(advance.claimed_amount, 1000)
|
||||||
|
self.assertEqual(advance.status, "Claimed")
|
||||||
|
|
||||||
|
# advance should not be shown in claims
|
||||||
|
advances = get_advances(claim.employee)
|
||||||
|
advances = [entry.name for entry in advances]
|
||||||
|
self.assertTrue(advance.name not in advances)
|
||||||
|
|
||||||
|
# cancel claim; status should be Paid
|
||||||
|
claim.cancel()
|
||||||
|
advance.reload()
|
||||||
|
self.assertEqual(advance.claimed_amount, 0)
|
||||||
|
self.assertEqual(advance.status, "Paid")
|
||||||
|
|
||||||
|
def test_partly_claimed_and_returned_status(self):
|
||||||
|
payable_account = get_payable_account("_Test Company")
|
||||||
|
claim = make_expense_claim(payable_account, 1000, 1000, "_Test Company", "Travel Expenses - _TC", do_not_submit=True)
|
||||||
|
|
||||||
|
advance = make_employee_advance(claim.employee)
|
||||||
|
pe = make_payment_entry(advance)
|
||||||
|
pe.submit()
|
||||||
|
|
||||||
|
# PARTLY CLAIMED AND RETURNED status check
|
||||||
|
# 500 Claimed, 500 Returned
|
||||||
|
claim = make_expense_claim(payable_account, 500, 500, "_Test Company", "Travel Expenses - _TC", do_not_submit=True)
|
||||||
|
|
||||||
|
advance = make_employee_advance(claim.employee)
|
||||||
|
pe = make_payment_entry(advance)
|
||||||
|
pe.submit()
|
||||||
|
|
||||||
|
claim = get_advances_for_claim(claim, advance.name, amount=500)
|
||||||
|
claim.save()
|
||||||
|
claim.submit()
|
||||||
|
|
||||||
|
advance.reload()
|
||||||
|
self.assertEqual(advance.claimed_amount, 500)
|
||||||
|
self.assertEqual(advance.status, "Paid")
|
||||||
|
|
||||||
|
entry = make_return_entry(
|
||||||
|
employee=advance.employee,
|
||||||
|
company=advance.company,
|
||||||
|
employee_advance_name=advance.name,
|
||||||
|
return_amount=flt(advance.paid_amount - advance.claimed_amount),
|
||||||
|
advance_account=advance.advance_account,
|
||||||
|
mode_of_payment=advance.mode_of_payment,
|
||||||
|
currency=advance.currency,
|
||||||
|
exchange_rate=advance.exchange_rate
|
||||||
|
)
|
||||||
|
|
||||||
|
entry = frappe.get_doc(entry)
|
||||||
|
entry.insert()
|
||||||
|
entry.submit()
|
||||||
|
|
||||||
|
advance.reload()
|
||||||
|
self.assertEqual(advance.return_amount, 500)
|
||||||
|
self.assertEqual(advance.status, "Partly Claimed and Returned")
|
||||||
|
|
||||||
|
# advance should not be shown in claims
|
||||||
|
advances = get_advances(claim.employee)
|
||||||
|
advances = [entry.name for entry in advances]
|
||||||
|
self.assertTrue(advance.name not in advances)
|
||||||
|
|
||||||
|
# Cancel return entry; status should change to PAID
|
||||||
|
entry.cancel()
|
||||||
|
advance.reload()
|
||||||
|
self.assertEqual(advance.return_amount, 0)
|
||||||
|
self.assertEqual(advance.status, "Paid")
|
||||||
|
|
||||||
|
# advance should be shown in claims
|
||||||
|
advances = get_advances(claim.employee)
|
||||||
|
advances = [entry.name for entry in advances]
|
||||||
|
self.assertTrue(advance.name in advances)
|
||||||
|
|
||||||
def test_repay_unclaimed_amount_from_salary(self):
|
def test_repay_unclaimed_amount_from_salary(self):
|
||||||
employee_name = make_employee("_T@employe.advance")
|
employee_name = make_employee("_T@employe.advance")
|
||||||
advance = make_employee_advance(employee_name, {"repay_unclaimed_amount_from_salary": 1})
|
advance = make_employee_advance(employee_name, {"repay_unclaimed_amount_from_salary": 1})
|
||||||
|
pe = make_payment_entry(advance)
|
||||||
|
pe.submit()
|
||||||
|
|
||||||
args = {"type": "Deduction"}
|
args = {"type": "Deduction"}
|
||||||
create_salary_component("Advance Salary - Deduction", **args)
|
create_salary_component("Advance Salary - Deduction", **args)
|
||||||
@ -82,11 +184,13 @@ class TestEmployeeAdvance(unittest.TestCase):
|
|||||||
|
|
||||||
advance.reload()
|
advance.reload()
|
||||||
self.assertEqual(advance.return_amount, 1000)
|
self.assertEqual(advance.return_amount, 1000)
|
||||||
|
self.assertEqual(advance.status, "Returned")
|
||||||
|
|
||||||
# update advance return amount on additional salary cancellation
|
# update advance return amount on additional salary cancellation
|
||||||
additional_salary.cancel()
|
additional_salary.cancel()
|
||||||
advance.reload()
|
advance.reload()
|
||||||
self.assertEqual(advance.return_amount, 700)
|
self.assertEqual(advance.return_amount, 700)
|
||||||
|
self.assertEqual(advance.status, "Paid")
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
frappe.db.rollback()
|
frappe.db.rollback()
|
||||||
@ -118,3 +222,24 @@ def make_employee_advance(employee_name, args=None):
|
|||||||
doc.submit()
|
doc.submit()
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
|
|
||||||
|
def get_advances_for_claim(claim, advance_name, amount=None):
|
||||||
|
advances = get_advances(claim.employee, advance_name)
|
||||||
|
|
||||||
|
for entry in advances:
|
||||||
|
if amount:
|
||||||
|
allocated_amount = amount
|
||||||
|
else:
|
||||||
|
allocated_amount = flt(entry.paid_amount) - flt(entry.claimed_amount)
|
||||||
|
|
||||||
|
claim.append("advances", {
|
||||||
|
"employee_advance": entry.name,
|
||||||
|
"posting_date": entry.posting_date,
|
||||||
|
"advance_account": entry.advance_account,
|
||||||
|
"advance_paid": entry.paid_amount,
|
||||||
|
"unclaimed_amount": allocated_amount,
|
||||||
|
"allocated_amount": allocated_amount
|
||||||
|
})
|
||||||
|
|
||||||
|
return claim
|
||||||
@ -171,7 +171,7 @@ frappe.ui.form.on("Expense Claim", {
|
|||||||
['docstatus', '=', 1],
|
['docstatus', '=', 1],
|
||||||
['employee', '=', frm.doc.employee],
|
['employee', '=', frm.doc.employee],
|
||||||
['paid_amount', '>', 0],
|
['paid_amount', '>', 0],
|
||||||
['status', '!=', 'Claimed']
|
['status', 'not in', ['Claimed', 'Returned', 'Partly Claimed and Returned']]
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@ -23,10 +23,10 @@ class ExpenseClaim(AccountsController):
|
|||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
validate_active_employee(self.employee)
|
validate_active_employee(self.employee)
|
||||||
self.validate_advances()
|
set_employee_name(self)
|
||||||
self.validate_sanctioned_amount()
|
self.validate_sanctioned_amount()
|
||||||
self.calculate_total_amount()
|
self.calculate_total_amount()
|
||||||
set_employee_name(self)
|
self.validate_advances()
|
||||||
self.set_expense_account(validate=True)
|
self.set_expense_account(validate=True)
|
||||||
self.set_payable_account()
|
self.set_payable_account()
|
||||||
self.set_cost_center()
|
self.set_cost_center()
|
||||||
@ -341,18 +341,27 @@ def get_expense_claim_account(expense_claim_type, company):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_advances(employee, advance_id=None):
|
def get_advances(employee, advance_id=None):
|
||||||
if not advance_id:
|
advance = frappe.qb.DocType("Employee Advance")
|
||||||
condition = 'docstatus=1 and employee={0} and paid_amount > 0 and paid_amount > claimed_amount + return_amount'.format(frappe.db.escape(employee))
|
|
||||||
else:
|
|
||||||
condition = 'name={0}'.format(frappe.db.escape(advance_id))
|
|
||||||
|
|
||||||
return frappe.db.sql("""
|
query = (
|
||||||
select
|
frappe.qb.from_(advance)
|
||||||
name, posting_date, paid_amount, claimed_amount, advance_account
|
.select(
|
||||||
from
|
advance.name, advance.posting_date, advance.paid_amount,
|
||||||
`tabEmployee Advance`
|
advance.claimed_amount, advance.advance_account
|
||||||
where {0}
|
)
|
||||||
""".format(condition), as_dict=1)
|
)
|
||||||
|
|
||||||
|
if not advance_id:
|
||||||
|
query = query.where(
|
||||||
|
(advance.docstatus == 1)
|
||||||
|
& (advance.employee == employee)
|
||||||
|
& (advance.paid_amount > 0)
|
||||||
|
& (advance.status.notin(["Claimed", "Returned", "Partly Claimed and Returned"]))
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
query = query.where(advance.name == advance_id)
|
||||||
|
|
||||||
|
return query.run(as_dict=True)
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@ -918,7 +918,7 @@ def validate_bom_no(item, bom_no):
|
|||||||
frappe.throw(_("BOM {0} does not belong to Item {1}").format(bom_no, item))
|
frappe.throw(_("BOM {0} does not belong to Item {1}").format(bom_no, item))
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_children(doctype, parent=None, is_root=False, **filters):
|
def get_children(parent=None, is_root=False, **filters):
|
||||||
if not parent or parent=="BOM":
|
if not parent or parent=="BOM":
|
||||||
frappe.msgprint(_('Please select a BOM'))
|
frappe.msgprint(_('Please select a BOM'))
|
||||||
return
|
return
|
||||||
|
|||||||
@ -232,7 +232,7 @@ frappe.ui.form.on('Production Plan', {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
combine_items: function (frm) {
|
combine_items: function (frm) {
|
||||||
frm.clear_table('prod_plan_references');
|
frm.clear_table("prod_plan_references");
|
||||||
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "get_items",
|
method: "get_items",
|
||||||
@ -247,6 +247,13 @@ frappe.ui.form.on('Production Plan', {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
combine_sub_items: (frm) => {
|
||||||
|
if (frm.doc.sub_assembly_items.length > 0) {
|
||||||
|
frm.clear_table("sub_assembly_items");
|
||||||
|
frm.trigger("get_sub_assembly_items");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
get_sub_assembly_items: function(frm) {
|
get_sub_assembly_items: function(frm) {
|
||||||
frm.dirty();
|
frm.dirty();
|
||||||
|
|
||||||
|
|||||||
@ -36,6 +36,7 @@
|
|||||||
"prod_plan_references",
|
"prod_plan_references",
|
||||||
"section_break_24",
|
"section_break_24",
|
||||||
"get_sub_assembly_items",
|
"get_sub_assembly_items",
|
||||||
|
"combine_sub_items",
|
||||||
"sub_assembly_items",
|
"sub_assembly_items",
|
||||||
"material_request_planning",
|
"material_request_planning",
|
||||||
"include_non_stock_items",
|
"include_non_stock_items",
|
||||||
@ -340,7 +341,6 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "prod_plan_references",
|
"fieldname": "prod_plan_references",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"hidden": 1,
|
|
||||||
"label": "Production Plan Item Reference",
|
"label": "Production Plan Item Reference",
|
||||||
"options": "Production Plan Item Reference"
|
"options": "Production Plan Item Reference"
|
||||||
},
|
},
|
||||||
@ -370,16 +370,23 @@
|
|||||||
"fieldname": "to_delivery_date",
|
"fieldname": "to_delivery_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "To Delivery Date"
|
"label": "To Delivery Date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "combine_sub_items",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Consolidate Sub Assembly Items"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-calendar",
|
"icon": "fa fa-calendar",
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-09-06 18:35:59.642232",
|
"modified": "2022-02-23 17:16:10.629378",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Production Plan",
|
"name": "Production Plan",
|
||||||
|
"naming_rule": "By \"Naming Series\" field",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -21,7 +21,8 @@ from frappe.utils import (
|
|||||||
)
|
)
|
||||||
from frappe.utils.csvutils import build_csv_response
|
from frappe.utils.csvutils import build_csv_response
|
||||||
|
|
||||||
from erpnext.manufacturing.doctype.bom.bom import get_children, validate_bom_no
|
from erpnext.manufacturing.doctype.bom.bom import get_children as get_bom_children
|
||||||
|
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
|
||||||
from erpnext.manufacturing.doctype.work_order.work_order import get_item_details
|
from erpnext.manufacturing.doctype.work_order.work_order import get_item_details
|
||||||
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
|
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
|
||||||
|
|
||||||
@ -570,17 +571,28 @@ class ProductionPlan(Document):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_sub_assembly_items(self, manufacturing_type=None):
|
def get_sub_assembly_items(self, manufacturing_type=None):
|
||||||
|
"Fetch sub assembly items and optionally combine them."
|
||||||
self.sub_assembly_items = []
|
self.sub_assembly_items = []
|
||||||
|
sub_assembly_items_store = [] # temporary store to process all subassembly items
|
||||||
|
|
||||||
for row in self.po_items:
|
for row in self.po_items:
|
||||||
bom_data = []
|
bom_data = []
|
||||||
get_sub_assembly_items(row.bom_no, bom_data, row.planned_qty)
|
get_sub_assembly_items(row.bom_no, bom_data, row.planned_qty)
|
||||||
self.set_sub_assembly_items_based_on_level(row, bom_data, manufacturing_type)
|
self.set_sub_assembly_items_based_on_level(row, bom_data, manufacturing_type)
|
||||||
|
sub_assembly_items_store.extend(bom_data)
|
||||||
|
|
||||||
self.sub_assembly_items.sort(key= lambda d: d.bom_level, reverse=True)
|
if self.combine_sub_items:
|
||||||
for idx, row in enumerate(self.sub_assembly_items, start=1):
|
# Combine subassembly items
|
||||||
row.idx = idx
|
sub_assembly_items_store = self.combine_subassembly_items(sub_assembly_items_store)
|
||||||
|
|
||||||
|
sub_assembly_items_store.sort(key= lambda d: d.bom_level, reverse=True) # sort by bom level
|
||||||
|
|
||||||
|
for idx, row in enumerate(sub_assembly_items_store):
|
||||||
|
row.idx = idx + 1
|
||||||
|
self.append("sub_assembly_items", row)
|
||||||
|
|
||||||
def set_sub_assembly_items_based_on_level(self, row, bom_data, manufacturing_type=None):
|
def set_sub_assembly_items_based_on_level(self, row, bom_data, manufacturing_type=None):
|
||||||
|
"Modify bom_data, set additional details."
|
||||||
for data in bom_data:
|
for data in bom_data:
|
||||||
data.qty = data.stock_qty
|
data.qty = data.stock_qty
|
||||||
data.production_plan_item = row.name
|
data.production_plan_item = row.name
|
||||||
@ -589,7 +601,32 @@ class ProductionPlan(Document):
|
|||||||
data.type_of_manufacturing = manufacturing_type or ("Subcontract" if data.is_sub_contracted_item
|
data.type_of_manufacturing = manufacturing_type or ("Subcontract" if data.is_sub_contracted_item
|
||||||
else "In House")
|
else "In House")
|
||||||
|
|
||||||
self.append("sub_assembly_items", data)
|
def combine_subassembly_items(self, sub_assembly_items_store):
|
||||||
|
"Aggregate if same: Item, Warehouse, Inhouse/Outhouse Manu.g, BOM No."
|
||||||
|
key_wise_data = {}
|
||||||
|
for row in sub_assembly_items_store:
|
||||||
|
key = (
|
||||||
|
row.get("production_item"), row.get("fg_warehouse"),
|
||||||
|
row.get("bom_no"), row.get("type_of_manufacturing")
|
||||||
|
)
|
||||||
|
if key not in key_wise_data:
|
||||||
|
# intialise (item, wh, bom no, man.g type) wise dict
|
||||||
|
key_wise_data[key] = row
|
||||||
|
continue
|
||||||
|
|
||||||
|
existing_row = key_wise_data[key]
|
||||||
|
if existing_row:
|
||||||
|
# if row with same (item, wh, bom no, man.g type) key, merge
|
||||||
|
existing_row.qty += flt(row.qty)
|
||||||
|
existing_row.stock_qty += flt(row.stock_qty)
|
||||||
|
existing_row.bom_level = max(existing_row.bom_level, row.bom_level)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
# add row with key
|
||||||
|
key_wise_data[key] = row
|
||||||
|
|
||||||
|
sub_assembly_items_store = [key_wise_data[key] for key in key_wise_data] # unpack into single level list
|
||||||
|
return sub_assembly_items_store
|
||||||
|
|
||||||
def all_items_completed(self):
|
def all_items_completed(self):
|
||||||
all_items_produced = all(flt(d.planned_qty) - flt(d.produced_qty) < 0.000001
|
all_items_produced = all(flt(d.planned_qty) - flt(d.produced_qty) < 0.000001
|
||||||
@ -1031,7 +1068,7 @@ def get_item_data(item_code):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def get_sub_assembly_items(bom_no, bom_data, to_produce_qty, indent=0):
|
def get_sub_assembly_items(bom_no, bom_data, to_produce_qty, indent=0):
|
||||||
data = get_children('BOM', parent = bom_no)
|
data = get_bom_children(parent=bom_no)
|
||||||
for d in data:
|
for d in data:
|
||||||
if d.expandable:
|
if d.expandable:
|
||||||
parent_item_code = frappe.get_cached_value("BOM", bom_no, "item")
|
parent_item_code = frappe.get_cached_value("BOM", bom_no, "item")
|
||||||
|
|||||||
@ -38,6 +38,9 @@ class TestProductionPlan(FrappeTestCase):
|
|||||||
if not frappe.db.get_value('BOM', {'item': item}):
|
if not frappe.db.get_value('BOM', {'item': item}):
|
||||||
make_bom(item = item, raw_materials = raw_materials)
|
make_bom(item = item, raw_materials = raw_materials)
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
frappe.db.rollback()
|
||||||
|
|
||||||
def test_production_plan_mr_creation(self):
|
def test_production_plan_mr_creation(self):
|
||||||
"Test if MRs are created for unavailable raw materials."
|
"Test if MRs are created for unavailable raw materials."
|
||||||
pln = create_production_plan(item_code='Test Production Item 1')
|
pln = create_production_plan(item_code='Test Production Item 1')
|
||||||
@ -110,7 +113,7 @@ class TestProductionPlan(FrappeTestCase):
|
|||||||
item_code='Test Production Item 1',
|
item_code='Test Production Item 1',
|
||||||
ignore_existing_ordered_qty=1
|
ignore_existing_ordered_qty=1
|
||||||
)
|
)
|
||||||
self.assertTrue(len(pln.mr_items), 1)
|
self.assertTrue(len(pln.mr_items))
|
||||||
self.assertTrue(flt(pln.mr_items[0].quantity), 1.0)
|
self.assertTrue(flt(pln.mr_items[0].quantity), 1.0)
|
||||||
|
|
||||||
sr1.cancel()
|
sr1.cancel()
|
||||||
@ -151,7 +154,7 @@ class TestProductionPlan(FrappeTestCase):
|
|||||||
use_multi_level_bom=0,
|
use_multi_level_bom=0,
|
||||||
ignore_existing_ordered_qty=0
|
ignore_existing_ordered_qty=0
|
||||||
)
|
)
|
||||||
self.assertTrue(len(pln.mr_items), 0)
|
self.assertFalse(len(pln.mr_items))
|
||||||
|
|
||||||
sr1.cancel()
|
sr1.cancel()
|
||||||
sr2.cancel()
|
sr2.cancel()
|
||||||
@ -258,6 +261,51 @@ class TestProductionPlan(FrappeTestCase):
|
|||||||
pln.reload()
|
pln.reload()
|
||||||
pln.cancel()
|
pln.cancel()
|
||||||
|
|
||||||
|
def test_production_plan_combine_subassembly(self):
|
||||||
|
"""
|
||||||
|
Test combining Sub assembly items belonging to the same BOM in Prod Plan.
|
||||||
|
1) Red-Car -> Wheel (sub assembly) > BOM-WHEEL-001
|
||||||
|
2) Green-Car -> Wheel (sub assembly) > BOM-WHEEL-001
|
||||||
|
"""
|
||||||
|
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
|
||||||
|
|
||||||
|
bom_tree_1 = {
|
||||||
|
"Red-Car": {"Wheel": {"Rubber": {}}}
|
||||||
|
}
|
||||||
|
bom_tree_2 = {
|
||||||
|
"Green-Car": {"Wheel": {"Rubber": {}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent_bom_1 = create_nested_bom(bom_tree_1, prefix="")
|
||||||
|
parent_bom_2 = create_nested_bom(bom_tree_2, prefix="")
|
||||||
|
|
||||||
|
# make sure both boms use same subassembly bom
|
||||||
|
subassembly_bom = parent_bom_1.items[0].bom_no
|
||||||
|
frappe.db.set_value("BOM Item", parent_bom_2.items[0].name, "bom_no", subassembly_bom)
|
||||||
|
|
||||||
|
plan = create_production_plan(item_code="Red-Car", use_multi_level_bom=1, do_not_save=True)
|
||||||
|
plan.append("po_items", { # Add Green-Car to Prod Plan
|
||||||
|
'use_multi_level_bom': 1,
|
||||||
|
'item_code': "Green-Car",
|
||||||
|
'bom_no': frappe.db.get_value('Item', "Green-Car", 'default_bom'),
|
||||||
|
'planned_qty': 1,
|
||||||
|
'planned_start_date': now_datetime()
|
||||||
|
})
|
||||||
|
plan.get_sub_assembly_items()
|
||||||
|
self.assertTrue(len(plan.sub_assembly_items), 2)
|
||||||
|
|
||||||
|
plan.combine_sub_items = 1
|
||||||
|
plan.get_sub_assembly_items()
|
||||||
|
|
||||||
|
self.assertTrue(len(plan.sub_assembly_items), 1) # check if sub-assembly items merged
|
||||||
|
self.assertEqual(plan.sub_assembly_items[0].qty, 2.0)
|
||||||
|
self.assertEqual(plan.sub_assembly_items[0].stock_qty, 2.0)
|
||||||
|
|
||||||
|
# change warehouse in one row, sub-assemblies should not merge
|
||||||
|
plan.po_items[0].warehouse = "Finished Goods - _TC"
|
||||||
|
plan.get_sub_assembly_items()
|
||||||
|
self.assertTrue(len(plan.sub_assembly_items), 2)
|
||||||
|
|
||||||
def test_pp_to_mr_customer_provided(self):
|
def test_pp_to_mr_customer_provided(self):
|
||||||
" Test Material Request from Production Plan for Customer Provided Item."
|
" Test Material Request from Production Plan for Customer Provided Item."
|
||||||
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
|
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
|
||||||
@ -532,6 +580,7 @@ class TestProductionPlan(FrappeTestCase):
|
|||||||
wip_warehouse='Work In Progress - _TC',
|
wip_warehouse='Work In Progress - _TC',
|
||||||
fg_warehouse='Finished Goods - _TC',
|
fg_warehouse='Finished Goods - _TC',
|
||||||
skip_transfer=1,
|
skip_transfer=1,
|
||||||
|
use_multi_level_bom=1,
|
||||||
do_not_submit=True
|
do_not_submit=True
|
||||||
)
|
)
|
||||||
wo.production_plan = pln.name
|
wo.production_plan = pln.name
|
||||||
@ -576,6 +625,7 @@ class TestProductionPlan(FrappeTestCase):
|
|||||||
wip_warehouse='Work In Progress - _TC',
|
wip_warehouse='Work In Progress - _TC',
|
||||||
fg_warehouse='Finished Goods - _TC',
|
fg_warehouse='Finished Goods - _TC',
|
||||||
skip_transfer=1,
|
skip_transfer=1,
|
||||||
|
use_multi_level_bom=1,
|
||||||
do_not_submit=True
|
do_not_submit=True
|
||||||
)
|
)
|
||||||
wo.production_plan = pln.name
|
wo.production_plan = pln.name
|
||||||
|
|||||||
@ -1040,7 +1040,7 @@ def make_wo_order_test_record(**args):
|
|||||||
wo_order.scrap_warehouse = args.fg_warehouse or "_Test Scrap Warehouse - _TC"
|
wo_order.scrap_warehouse = args.fg_warehouse or "_Test Scrap Warehouse - _TC"
|
||||||
wo_order.company = args.company or "_Test Company"
|
wo_order.company = args.company or "_Test Company"
|
||||||
wo_order.stock_uom = args.stock_uom or "_Test UOM"
|
wo_order.stock_uom = args.stock_uom or "_Test UOM"
|
||||||
wo_order.use_multi_level_bom=0
|
wo_order.use_multi_level_bom= args.use_multi_level_bom or 0
|
||||||
wo_order.skip_transfer=args.skip_transfer or 0
|
wo_order.skip_transfer=args.skip_transfer or 0
|
||||||
wo_order.get_items_and_operations_from_bom()
|
wo_order.get_items_and_operations_from_bom()
|
||||||
wo_order.sales_order = args.sales_order or None
|
wo_order.sales_order = args.sales_order or None
|
||||||
|
|||||||
@ -357,3 +357,4 @@ erpnext.patches.v13_0.set_work_order_qty_in_so_from_mr
|
|||||||
erpnext.patches.v13_0.update_accounts_in_loan_docs
|
erpnext.patches.v13_0.update_accounts_in_loan_docs
|
||||||
erpnext.patches.v14_0.update_batch_valuation_flag
|
erpnext.patches.v14_0.update_batch_valuation_flag
|
||||||
erpnext.patches.v14_0.delete_non_profit_doctypes
|
erpnext.patches.v14_0.delete_non_profit_doctypes
|
||||||
|
erpnext.patches.v14_0.update_employee_advance_status
|
||||||
26
erpnext/patches/v14_0/update_employee_advance_status.py
Normal file
26
erpnext/patches/v14_0/update_employee_advance_status.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doc('hr', 'doctype', 'employee_advance')
|
||||||
|
|
||||||
|
advance = frappe.qb.DocType('Employee Advance')
|
||||||
|
(frappe.qb
|
||||||
|
.update(advance)
|
||||||
|
.set(advance.status, 'Returned')
|
||||||
|
.where(
|
||||||
|
(advance.docstatus == 1)
|
||||||
|
& ((advance.return_amount) & (advance.paid_amount == advance.return_amount))
|
||||||
|
& (advance.status == 'Paid')
|
||||||
|
)
|
||||||
|
).run()
|
||||||
|
|
||||||
|
(frappe.qb
|
||||||
|
.update(advance)
|
||||||
|
.set(advance.status, 'Partly Claimed and Returned')
|
||||||
|
.where(
|
||||||
|
(advance.docstatus == 1)
|
||||||
|
& ((advance.claimed_amount & advance.return_amount) & (advance.paid_amount == (advance.return_amount + advance.claimed_amount)))
|
||||||
|
& (advance.status == 'Paid')
|
||||||
|
)
|
||||||
|
).run()
|
||||||
@ -105,6 +105,8 @@ class AdditionalSalary(Document):
|
|||||||
return_amount += self.amount
|
return_amount += self.amount
|
||||||
|
|
||||||
frappe.db.set_value("Employee Advance", self.ref_docname, "return_amount", return_amount)
|
frappe.db.set_value("Employee Advance", self.ref_docname, "return_amount", return_amount)
|
||||||
|
advance = frappe.get_doc("Employee Advance", self.ref_docname)
|
||||||
|
advance.set_status(update=True)
|
||||||
|
|
||||||
def update_employee_referral(self, cancel=False):
|
def update_employee_referral(self, cancel=False):
|
||||||
if self.ref_doctype == "Employee Referral":
|
if self.ref_doctype == "Employee Referral":
|
||||||
|
|||||||
@ -244,7 +244,7 @@
|
|||||||
"idx": 1,
|
"idx": 1,
|
||||||
"is_tree": 1,
|
"is_tree": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-12-03 04:40:06.414630",
|
"modified": "2022-03-01 02:37:48.034944",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Warehouse",
|
"name": "Warehouse",
|
||||||
@ -301,5 +301,7 @@
|
|||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"title_field": "warehouse_name"
|
"states": [],
|
||||||
|
"title_field": "warehouse_name",
|
||||||
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@ class TestPointOfSale(unittest.TestCase):
|
|||||||
Test Stock and Service Item Search.
|
Test Stock and Service Item Search.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pos_profile = make_pos_profile()
|
pos_profile = make_pos_profile(name="Test POS Profile for Search")
|
||||||
item1 = make_item("Test Search Stock Item", {"is_stock_item": 1})
|
item1 = make_item("Test Search Stock Item", {"is_stock_item": 1})
|
||||||
make_stock_entry(
|
make_stock_entry(
|
||||||
item_code="Test Search Stock Item",
|
item_code="Test Search Stock Item",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user