From e04b3aaf7a2cb0792436a7e5f868572cb35c39f4 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 18 Jan 2022 14:36:22 +0530 Subject: [PATCH 01/30] feat(Employee Advance): add 'Returned' and 'Partly Claimed and Returned' status --- .../employee_advance/employee_advance.json | 42 +++++++++++++++++-- .../employee_advance/employee_advance.py | 39 ++++++++++------- .../hr/doctype/expense_claim/expense_claim.js | 2 +- .../hr/doctype/expense_claim/expense_claim.py | 31 +++++++++----- 4 files changed, 85 insertions(+), 29 deletions(-) diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.json b/erpnext/hr/doctype/employee_advance/employee_advance.json index 04754530c3..b0501830cc 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.json +++ b/erpnext/hr/doctype/employee_advance/employee_advance.json @@ -2,7 +2,7 @@ "actions": [], "allow_import": 1, "autoname": "naming_series:", - "creation": "2017-10-09 14:26:29.612365", + "creation": "2022-01-17 18:36:51.450395", "doctype": "DocType", "editable_grid": 1, "engine": "InnoDB", @@ -121,7 +121,7 @@ "fieldtype": "Select", "label": "Status", "no_copy": 1, - "options": "Draft\nPaid\nUnpaid\nClaimed\nCancelled", + "options": "Draft\nPaid\nUnpaid\nClaimed\nReturned\nPartly Claimed and Returned\nCancelled", "read_only": 1 }, { @@ -200,7 +200,7 @@ ], "is_submittable": 1, "links": [], - "modified": "2021-09-11 18:38:38.617478", + "modified": "2022-01-17 19:33:52.345823", "modified_by": "Administrator", "module": "HR", "name": "Employee Advance", @@ -237,5 +237,41 @@ "search_fields": "employee,employee_name", "sort_field": "modified", "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 } \ No newline at end of file diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py index 7aac2b63ed..e17eb214a1 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/employee_advance.py @@ -28,18 +28,31 @@ class EmployeeAdvance(Document): def on_cancel(self): self.ignore_linked_doctypes = ('GL Entry') - def set_status(self): + 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 + if self.docstatus == 0: - self.status = "Draft" - if self.docstatus == 1: - if self.claimed_amount and flt(self.claimed_amount) == flt(self.paid_amount): - self.status = "Claimed" - elif self.paid_amount and self.advance_amount == flt(self.paid_amount): - self.status = "Paid" + status = "Draft" + elif self.docstatus == 1: + if flt(self.claimed_amount) > 0 and flt(self.claimed_amount, precision) == flt(self.paid_amount, precision): + status = "Claimed" + elif flt(self.return_amount) > 0 and flt(self.return_amount, precision) == flt(self.paid_amount, precision): + 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: - self.status = "Unpaid" + status = "Unpaid" 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): gle = frappe.qb.DocType("GL Entry") @@ -85,9 +98,7 @@ class EmployeeAdvance(Document): self.db_set("paid_amount", paid_amount) self.db_set("return_amount", return_amount) - self.set_status() - frappe.db.set_value("Employee Advance", self.name , "status", self.status) - + self.set_status(update=True) def update_claimed_amount(self): claimed_amount = frappe.db.sql(""" @@ -103,8 +114,8 @@ class EmployeeAdvance(Document): frappe.db.set_value("Employee Advance", self.name, "claimed_amount", flt(claimed_amount)) self.reload() - self.set_status() - frappe.db.set_value("Employee Advance", self.name, "status", self.status) + self.set_status(update=True) + @frappe.whitelist() def get_pending_amount(employee, posting_date): diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js index 047945787d..af80b63845 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.js +++ b/erpnext/hr/doctype/expense_claim/expense_claim.js @@ -171,7 +171,7 @@ frappe.ui.form.on("Expense Claim", { ['docstatus', '=', 1], ['employee', '=', frm.doc.employee], ['paid_amount', '>', 0], - ['status', '!=', 'Claimed'] + ['status', 'not in', ['Claimed', 'Returned', 'Partly Claimed and Returned']] ] }; }); diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index 7e3898b7d5..2d2bb093ce 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -341,18 +341,27 @@ def get_expense_claim_account(expense_claim_type, company): @frappe.whitelist() def get_advances(employee, advance_id=None): - if not advance_id: - 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)) + advance = frappe.qb.DocType("Employee Advance") - return frappe.db.sql(""" - select - name, posting_date, paid_amount, claimed_amount, advance_account - from - `tabEmployee Advance` - where {0} - """.format(condition), as_dict=1) + query = ( + frappe.qb.from_(advance) + .select( + advance.name, advance.posting_date, advance.paid_amount, + advance.claimed_amount, advance.advance_account + ) + ) + + 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() From bf30932de0524c42ab3d9718e3d19a73e1cb2d39 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 18 Jan 2022 14:36:38 +0530 Subject: [PATCH 02/30] patch: Employee Advance return statuses --- erpnext/patches.txt | 3 ++- .../v14_0/update_employee_advance_status.py | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 erpnext/patches/v14_0/update_employee_advance_status.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index fa62b7fc27..ed39c204f6 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -326,4 +326,5 @@ erpnext.patches.v13_0.agriculture_deprecation_warning erpnext.patches.v14_0.delete_agriculture_doctypes erpnext.patches.v13_0.update_exchange_rate_settings erpnext.patches.v14_0.rearrange_company_fields -erpnext.patches.v14_0.update_leave_notification_template \ No newline at end of file +erpnext.patches.v14_0.update_leave_notification_template +erpnext.patches.v14_0.update_employee_advance_status \ No newline at end of file diff --git a/erpnext/patches/v14_0/update_employee_advance_status.py b/erpnext/patches/v14_0/update_employee_advance_status.py new file mode 100644 index 0000000000..a20e35a9f6 --- /dev/null +++ b/erpnext/patches/v14_0/update_employee_advance_status.py @@ -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() \ No newline at end of file From 0843d4388569616803a562a6928d6f1204f0e733 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 18 Jan 2022 14:37:45 +0530 Subject: [PATCH 03/30] fix(Expense Claim): validate advances after setting totals --- erpnext/hr/doctype/expense_claim/expense_claim.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index 2d2bb093ce..5146a5be90 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -23,10 +23,10 @@ class ExpenseClaim(AccountsController): def validate(self): validate_active_employee(self.employee) - self.validate_advances() + set_employee_name(self) self.validate_sanctioned_amount() self.calculate_total_amount() - set_employee_name(self) + self.validate_advances() self.set_expense_account(validate=True) self.set_payable_account() self.set_cost_center() From 85be0d22d4300a40f46b7268f7c56d8e7facbd40 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 18 Jan 2022 14:38:16 +0530 Subject: [PATCH 04/30] fix: employee advance status update on return via additional salary --- erpnext/payroll/doctype/additional_salary/additional_salary.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.py b/erpnext/payroll/doctype/additional_salary/additional_salary.py index bf8bd05fcc..d618568416 100644 --- a/erpnext/payroll/doctype/additional_salary/additional_salary.py +++ b/erpnext/payroll/doctype/additional_salary/additional_salary.py @@ -105,6 +105,8 @@ class AdditionalSalary(Document): return_amount += self.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): if self.ref_doctype == "Employee Referral": From 17b1f5f256ff63d34b3c20b4792cd77ae75402e0 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 18 Jan 2022 18:35:25 +0530 Subject: [PATCH 05/30] test: employee advance status --- .../employee_advance/employee_advance.py | 6 +- .../employee_advance/test_employee_advance.py | 97 ++++++++++++++++++- 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py index e17eb214a1..f63bb86129 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/employee_advance.py @@ -233,7 +233,8 @@ def make_return_entry(employee, company, employee_advance_name, return_amount, 'reference_name': employee_advance_name, 'party_type': '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 \ @@ -244,7 +245,8 @@ def make_return_entry(employee, company, employee_advance_name, return_amount, "debit_in_account_currency": bank_amount, "account_currency": bank_cash_account.account_currency, "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() diff --git a/erpnext/hr/doctype/employee_advance/test_employee_advance.py b/erpnext/hr/doctype/employee_advance/test_employee_advance.py index 5f2e720eb4..5f3a66a04f 100644 --- a/erpnext/hr/doctype/employee_advance/test_employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/test_employee_advance.py @@ -4,7 +4,7 @@ import unittest import frappe -from frappe.utils import nowdate +from frappe.utils import flt, nowdate import erpnext from erpnext.hr.doctype.employee.test_employee import make_employee @@ -12,6 +12,12 @@ from erpnext.hr.doctype.employee_advance.employee_advance import ( EmployeeAdvanceOverPayment, create_return_through_additional_salary, 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_structure.test_salary_structure import make_salary_structure @@ -52,9 +58,75 @@ class TestEmployeeAdvance(unittest.TestCase): self.assertEqual(advance.paid_amount, 0) self.assertEqual(advance.status, "Unpaid") + def test_claimed_and_returned_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") + + # cancel claim; status should be Paid + claim.cancel() + advance.reload() + self.assertEqual(advance.claimed_amount, 0) + self.assertEqual(advance.status, "Paid") + + # 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") + + # Cancel return entry; status should change to Paid + entry.cancel() + advance.reload() + self.assertEqual(advance.return_amount, 0) + self.assertEqual(advance.status, "Paid") + def test_repay_unclaimed_amount_from_salary(self): employee_name = make_employee("_T@employe.advance") advance = make_employee_advance(employee_name, {"repay_unclaimed_amount_from_salary": 1}) + pe = make_payment_entry(advance) + pe.submit() args = {"type": "Deduction"} create_salary_component("Advance Salary - Deduction", **args) @@ -82,11 +154,13 @@ class TestEmployeeAdvance(unittest.TestCase): advance.reload() self.assertEqual(advance.return_amount, 1000) + self.assertEqual(advance.status, "Returned") # update advance return amount on additional salary cancellation additional_salary.cancel() advance.reload() self.assertEqual(advance.return_amount, 700) + self.assertEqual(advance.status, "Paid") def tearDown(self): frappe.db.rollback() @@ -118,3 +192,24 @@ def make_employee_advance(employee_name, args=None): doc.submit() 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 \ No newline at end of file From 70b960e650bbc1c418eecd14ac42d64a3103a43c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 22 Feb 2022 09:16:08 +0530 Subject: [PATCH 06/30] fix: Account filter in PSOA --- .../process_statement_of_accounts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py index 09aa72352e..1b34d6d1f2 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py @@ -73,7 +73,7 @@ def get_report_pdf(doc, consolidated=True): 'to_date': doc.to_date, 'company': doc.company, 'finance_book': doc.finance_book if doc.finance_book else None, - 'account': doc.account if doc.account else None, + 'account': [doc.account] if doc.account else None, 'party_type': 'Customer', 'party': [entry.customer], 'presentation_currency': presentation_currency, From b1a46c80d5571d23a749656c98056ba1411b433f Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 24 Feb 2022 13:11:17 +0530 Subject: [PATCH 07/30] fix: Total taxes and charges in payment entry for multicurrency payments --- .../doctype/payment_entry/payment_entry.js | 13 ++++++++++--- .../doctype/payment_entry/payment_entry.json | 14 +++++++++++++- .../doctype/payment_entry/payment_entry.py | 8 ++++++-- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 3be3925b5a..c14251b7d2 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -196,8 +196,14 @@ frappe.ui.form.on('Payment Entry', { frm.doc.paid_from_account_currency != frm.doc.paid_to_account_currency)); frm.toggle_display("base_paid_amount", frm.doc.paid_from_account_currency != company_currency); - frm.toggle_display("base_total_taxes_and_charges", frm.doc.total_taxes_and_charges && - (frm.doc.paid_from_account_currency != company_currency)); + + if (frm.doc.payment_type == "Pay") { + frm.toggle_display("base_total_taxes_and_charges", frm.doc.total_taxes_and_charges && + (frm.doc.paid_to_account_currency != company_currency)); + } else { + frm.toggle_display("base_total_taxes_and_charges", frm.doc.total_taxes_and_charges && + (frm.doc.paid_from_account_currency != company_currency)); + } frm.toggle_display("base_received_amount", ( frm.doc.paid_to_account_currency != company_currency @@ -232,7 +238,8 @@ frappe.ui.form.on('Payment Entry', { var company_currency = frm.doc.company? frappe.get_doc(":Company", frm.doc.company).default_currency: ""; frm.set_currency_labels(["base_paid_amount", "base_received_amount", "base_total_allocated_amount", - "difference_amount", "base_paid_amount_after_tax", "base_received_amount_after_tax"], company_currency); + "difference_amount", "base_paid_amount_after_tax", "base_received_amount_after_tax", + "base_total_taxes_and_charges"], company_currency); frm.set_currency_labels(["paid_amount"], frm.doc.paid_from_account_currency); frm.set_currency_labels(["received_amount"], frm.doc.paid_to_account_currency); diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json index c8d1db91f5..3fc1adff2d 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.json +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json @@ -66,7 +66,9 @@ "tax_withholding_category", "section_break_56", "taxes", + "section_break_60", "base_total_taxes_and_charges", + "column_break_61", "total_taxes_and_charges", "deductions_or_loss_section", "deductions", @@ -715,12 +717,21 @@ "fieldtype": "Data", "hidden": 1, "label": "Paid To Account Type" + }, + { + "fieldname": "column_break_61", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_60", + "fieldtype": "Section Break", + "hide_border": 1 } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-11-24 18:58:24.919764", + "modified": "2022-02-23 20:08:39.559814", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry", @@ -763,6 +774,7 @@ "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", + "states": [], "title_field": "title", "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 02a144d3e7..6ec15e1e87 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -945,8 +945,12 @@ class PaymentEntry(AccountsController): tax.base_total = tax.total * self.source_exchange_rate - self.total_taxes_and_charges += current_tax_amount - self.base_total_taxes_and_charges += current_tax_amount * self.source_exchange_rate + if self.payment_type == 'Pay': + self.base_total_taxes_and_charges += current_tax_amount * self.source_exchange_rate + self.total_taxes_and_charges += current_tax_amount * self.target_exchange_rate + else: + self.base_total_taxes_and_charges += current_tax_amount * self.target_exchange_rate + self.total_taxes_and_charges += current_tax_amount * self.source_exchange_rate if self.get('taxes'): self.paid_amount_after_tax = self.get('taxes')[-1].base_total From 03739147049ed78bd2bb43f5f47cfc70d6be43ba Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 24 Feb 2022 14:42:56 +0530 Subject: [PATCH 08/30] fix: Commission not applied while making Sales Order from Quotation --- .../doctype/sales_invoice_item/sales_invoice_item.json | 6 ++++-- .../doctype/sales_order_item/sales_order_item.json | 7 +++++-- .../doctype/delivery_note_item/delivery_note_item.json | 9 ++++++--- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index ae9ac35729..2901cf0888 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -832,6 +832,7 @@ }, { "default": "0", + "fetch_from": "item_code.grant_commission", "fieldname": "grant_commission", "fieldtype": "Check", "label": "Grant Commission", @@ -841,7 +842,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2021-10-05 12:24:54.968907", + "modified": "2022-02-24 14:41:36.392560", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", @@ -849,5 +850,6 @@ "owner": "Administrator", "permissions": [], "sort_field": "modified", - "sort_order": "DESC" + "sort_order": "DESC", + "states": [] } \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 080d517d13..7e55499533 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -83,8 +83,8 @@ "planned_qty", "column_break_69", "work_order_qty", - "produced_qty", "delivered_qty", + "produced_qty", "returned_qty", "shopping_cart_section", "additional_notes", @@ -701,8 +701,10 @@ "width": "50px" }, { + "description": "For Production", "fieldname": "produced_qty", "fieldtype": "Float", + "hidden": 1, "label": "Produced Quantity", "oldfieldname": "produced_qty", "oldfieldtype": "Currency", @@ -791,6 +793,7 @@ }, { "default": "0", + "fetch_from": "item_code.grant_commission", "fieldname": "grant_commission", "fieldtype": "Check", "label": "Grant Commission", @@ -800,7 +803,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-02-21 13:55:08.883104", + "modified": "2022-02-24 14:41:57.325799", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index 51c88bed61..f1f5d96e62 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -757,6 +757,7 @@ }, { "default": "0", + "fetch_from": "item_code.grant_commission", "fieldname": "grant_commission", "fieldtype": "Check", "label": "Grant Commission", @@ -767,12 +768,14 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-10-06 12:12:44.018872", + "modified": "2022-02-24 14:42:20.211085", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", + "naming_rule": "Random", "owner": "Administrator", "permissions": [], "sort_field": "modified", - "sort_order": "DESC" -} + "sort_order": "DESC", + "states": [] +} \ No newline at end of file From 6d72aa377f98f07f28312074b453a97e482998e8 Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 24 Feb 2022 15:20:18 +0530 Subject: [PATCH 09/30] feat: Combine Sub-assembly items in Production Plan - Combine subassembly rows if same Item, Warehouse, Inhouse/Outhouse Manu.g, BOM No. --- erpnext/manufacturing/doctype/bom/bom.py | 2 +- .../production_plan/production_plan.js | 9 +++- .../production_plan/production_plan.json | 11 ++++- .../production_plan/production_plan.py | 49 ++++++++++++++++--- 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index d640f3fda7..37d2b9ff97 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -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.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": frappe.msgprint(_('Please select a BOM')) return diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js index 0babf875e7..c78ff51a7c 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.js +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js @@ -232,7 +232,7 @@ frappe.ui.form.on('Production Plan', { }); }, combine_items: function (frm) { - frm.clear_table('prod_plan_references'); + frm.clear_table("prod_plan_references"); frappe.call({ 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) { frm.dirty(); diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json index 56cf2b4f08..3bfb764ba5 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.json +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json @@ -36,6 +36,7 @@ "prod_plan_references", "section_break_24", "get_sub_assembly_items", + "combine_sub_items", "sub_assembly_items", "material_request_planning", "include_non_stock_items", @@ -340,7 +341,6 @@ { "fieldname": "prod_plan_references", "fieldtype": "Table", - "hidden": 1, "label": "Production Plan Item Reference", "options": "Production Plan Item Reference" }, @@ -370,16 +370,23 @@ "fieldname": "to_delivery_date", "fieldtype": "Date", "label": "To Delivery Date" + }, + { + "default": "0", + "fieldname": "combine_sub_items", + "fieldtype": "Check", + "label": "Consolidate Sub Assembly Items" } ], "icon": "fa fa-calendar", "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-09-06 18:35:59.642232", + "modified": "2022-02-23 17:16:10.629378", "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Plan", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 80003dab78..48cd753d75 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -21,7 +21,8 @@ from frappe.utils import ( ) 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.setup.doctype.item_group.item_group import get_item_group_defaults @@ -570,17 +571,28 @@ class ProductionPlan(Document): @frappe.whitelist() def get_sub_assembly_items(self, manufacturing_type=None): + "Fetch sub assembly items and optionally combine them." self.sub_assembly_items = [] + sub_assembly_items_store = [] # temporary store to process all subassembly items + for row in self.po_items: bom_data = [] 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) + sub_assembly_items_store.extend(bom_data) - self.sub_assembly_items.sort(key= lambda d: d.bom_level, reverse=True) - for idx, row in enumerate(self.sub_assembly_items, start=1): - row.idx = idx + if self.combine_sub_items: + # Combine subassembly items + 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): + "Modify bom_data, set additional details." for data in bom_data: data.qty = data.stock_qty 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 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): 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): - data = get_children('BOM', parent = bom_no) + data = get_bom_children(parent=bom_no) for d in data: if d.expandable: parent_item_code = frappe.get_cached_value("BOM", bom_no, "item") From 4e9a9f35a605f4f886cc9cc920ec4ab4262b9709 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 28 Feb 2022 12:41:59 +0530 Subject: [PATCH 10/30] test: add correct test case --- .../doctype/sales_invoice/test_sales_invoice.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 941061f2a2..07591e7b1e 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2429,14 +2429,22 @@ class TestSalesInvoice(unittest.TestCase): def test_sales_commission(self): - si = frappe.copy_doc(test_records[0]) + si = frappe.copy_doc(test_records[2]) + + frappe.db.set_value('Item', si.get('items')[0].item_code, 'grant_commission', 1) + frappe.db.set_value('Item', si.get('items')[1].item_code, 'grant_commission', 0) + item = copy.deepcopy(si.get('items')[0]) item.update({ "qty": 1, "rate": 500, - "grant_commission": 1 }) - si.append("items", item) + + item = copy.deepcopy(si.get('items')[1]) + item.update({ + "qty": 1, + "rate": 500, + }) # Test valid values for commission_rate, total_commission in ((0, 0), (10, 50), (100, 500)): From 88a21ca7d2fd2944912bc3cd48c81185478f3cb3 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 26 Jan 2022 01:01:10 +0530 Subject: [PATCH 11/30] fix: only show child warehouses for transfer --- erpnext/stock/dashboard/item_dashboard.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js index 37e9e89a0a..204d62355c 100644 --- a/erpnext/stock/dashboard/item_dashboard.js +++ b/erpnext/stock/dashboard/item_dashboard.js @@ -213,7 +213,14 @@ erpnext.stock.move_item = function (item, source, target, actual_qty, rate, call label: __('Target Warehouse'), fieldtype: 'Link', options: 'Warehouse', - reqd: 1 + reqd: 1, + get_query() { + return { + filters: { + is_group: 0 + } + } + } }, { fieldname: 'qty', From 0bed5927779c823455e9cd819cba5281d297e1b3 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 26 Jan 2022 01:01:33 +0530 Subject: [PATCH 12/30] fix: open stock entry instead of submitting from item dashboard --- erpnext/stock/dashboard/item_dashboard.js | 61 ++++++----------------- 1 file changed, 15 insertions(+), 46 deletions(-) diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js index 204d62355c..1f259bd425 100644 --- a/erpnext/stock/dashboard/item_dashboard.js +++ b/erpnext/stock/dashboard/item_dashboard.js @@ -259,52 +259,21 @@ erpnext.stock.move_item = function (item, source, target, actual_qty, rate, call dialog.get_field('target').refresh(); } - dialog.set_primary_action(__('Submit'), function () { - var values = dialog.get_values(); - if (!values) { - return; - } - if (source && values.qty > actual_qty) { - frappe.msgprint(__('Quantity must be less than or equal to {0}', [actual_qty])); - return; - } - if (values.source === values.target) { - frappe.msgprint(__('Source and target warehouse must be different')); - } - - frappe.call({ - method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry', - args: values, - btn: dialog.get_primary_btn(), - freeze: true, - freeze_message: __('Creating Stock Entry'), - callback: function (r) { - frappe.show_alert(__('Stock Entry {0} created', - ['' + r.message.name + ''])); - dialog.hide(); - callback(r); - }, + dialog.set_primary_action(__('Create Stock Entry'), function () { + frappe.model.with_doctype('Stock Entry', function () { + let doc = frappe.model.get_new_doc('Stock Entry'); + doc.from_warehouse = dialog.get_value('source'); + doc.to_warehouse = dialog.get_value('target'); + doc.stock_entry_type = doc.from_warehouse ? "Material Transfer" : "Material Receipt"; + let row = frappe.model.add_child(doc, 'items'); + row.item_code = dialog.get_value('item_code'); + row.f_warehouse = dialog.get_value('target'); + row.t_warehouse = dialog.get_value('target'); + row.qty = dialog.get_value('qty'); + row.conversion_factor = 1; + row.transfer_qty = dialog.get_value('qty'); + row.basic_rate = dialog.get_value('rate'); + frappe.set_route('Form', doc.doctype, doc.name); }); }); - - $('

' + - __("Add more items or open full form") + '

') - .appendTo(dialog.body) - .find('.link-open') - .on('click', function () { - frappe.model.with_doctype('Stock Entry', function () { - var doc = frappe.model.get_new_doc('Stock Entry'); - doc.from_warehouse = dialog.get_value('source'); - doc.to_warehouse = dialog.get_value('target'); - var row = frappe.model.add_child(doc, 'items'); - row.item_code = dialog.get_value('item_code'); - row.f_warehouse = dialog.get_value('target'); - row.t_warehouse = dialog.get_value('target'); - row.qty = dialog.get_value('qty'); - row.conversion_factor = 1; - row.transfer_qty = dialog.get_value('qty'); - row.basic_rate = dialog.get_value('rate'); - frappe.set_route('Form', doc.doctype, doc.name); - }); - }); }; From 3cc47d5ba5b0b7a0a677e81bf4d092f85b36e969 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 28 Feb 2022 13:04:24 +0530 Subject: [PATCH 13/30] fix: correct fieldname for source warehouse --- erpnext/stock/dashboard/item_dashboard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js index 1f259bd425..c9d5f61f22 100644 --- a/erpnext/stock/dashboard/item_dashboard.js +++ b/erpnext/stock/dashboard/item_dashboard.js @@ -267,7 +267,7 @@ erpnext.stock.move_item = function (item, source, target, actual_qty, rate, call doc.stock_entry_type = doc.from_warehouse ? "Material Transfer" : "Material Receipt"; let row = frappe.model.add_child(doc, 'items'); row.item_code = dialog.get_value('item_code'); - row.f_warehouse = dialog.get_value('target'); + row.s_warehouse = dialog.get_value('source'); row.t_warehouse = dialog.get_value('target'); row.qty = dialog.get_value('qty'); row.conversion_factor = 1; From 1d1203d5eca07e40d8ce32248a0d81b0d7130627 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 28 Feb 2022 12:44:39 +0530 Subject: [PATCH 14/30] fix: dont fetch draft/cancelled BOMs --- .../manufacturing/doctype/production_plan/production_plan.js | 2 +- erpnext/manufacturing/doctype/work_order/work_order.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js index 0babf875e7..c33e64674e 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.js +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js @@ -49,7 +49,7 @@ frappe.ui.form.on('Production Plan', { if (d.item_code) { return { query: "erpnext.controllers.queries.bom", - filters:{'item': cstr(d.item_code)} + filters:{'item': cstr(d.item_code), 'docstatus': 1} } } else frappe.msgprint(__("Please enter Item first")); } diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index e1120c723d..374ab86cad 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -854,7 +854,7 @@ def get_item_details(item, project = None, skip_bom_info=False): res = res[0] if skip_bom_info: return res - filters = {"item": item, "is_default": 1} + filters = {"item": item, "is_default": 1, "docstatus": 1} if project: filters = {"item": item, "project": project} From 39d3f20d9b45939e1b7a5564a1c79ad99a304953 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 28 Feb 2022 14:19:48 +0530 Subject: [PATCH 15/30] fix: removed validation to check zero qty --- erpnext/controllers/subcontracting.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/erpnext/controllers/subcontracting.py b/erpnext/controllers/subcontracting.py index 3addb91aaa..c52c688b73 100644 --- a/erpnext/controllers/subcontracting.py +++ b/erpnext/controllers/subcontracting.py @@ -363,8 +363,6 @@ class Subcontracting(): return for row in self.get(self.raw_material_table): - self.__validate_consumed_qty(row) - key = (row.rm_item_code, row.main_item_code, row.purchase_order) if not self.__transferred_items or not self.__transferred_items.get(key): return @@ -372,12 +370,6 @@ class Subcontracting(): self.__validate_batch_no(row, key) self.__validate_serial_no(row, key) - def __validate_consumed_qty(self, row): - if self.backflush_based_on != 'BOM' and flt(row.consumed_qty) == 0.0: - msg = f'Row {row.idx}: the consumed qty cannot be zero for the item {frappe.bold(row.rm_item_code)}' - - frappe.throw(_(msg),title=_('Consumed Items Qty Check')) - def __validate_batch_no(self, row, key): if row.get('batch_no') and row.get('batch_no') not in self.__transferred_items.get(key).get('batch_no'): link = get_link_to_form('Purchase Order', row.purchase_order) From 292fe370dbb1d4c090c78f34bd70ddf95774fe5d Mon Sep 17 00:00:00 2001 From: marination Date: Mon, 28 Feb 2022 16:35:20 +0530 Subject: [PATCH 16/30] test: combine sub assembly items and make Production Plan tests atomic --- .../production_plan/test_production_plan.py | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 2359815813..8e34e1bca3 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -20,7 +20,7 @@ from erpnext.tests.utils import ERPNextTestCase class TestProductionPlan(ERPNextTestCase): - def setUp(self): + def setUp(self) -> None: for item in ['Test Production Item 1', 'Subassembly Item 1', 'Raw Material Item 1', 'Raw Material Item 2']: create_item(item, valuation_rate=100) @@ -38,6 +38,9 @@ class TestProductionPlan(ERPNextTestCase): if not frappe.db.get_value('BOM', {'item': item}): make_bom(item = item, raw_materials = raw_materials) + def tearDown(self) -> None: + frappe.db.rollback() + def test_production_plan_mr_creation(self): "Test if MRs are created for unavailable raw materials." pln = create_production_plan(item_code='Test Production Item 1') @@ -258,6 +261,46 @@ class TestProductionPlan(ERPNextTestCase): pln.reload() 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) + def test_pp_to_mr_customer_provided(self): " 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) From b0d1e6db54ea73af5a2b31d32cd5ba360d0dd7b1 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 28 Feb 2022 16:55:46 +0530 Subject: [PATCH 17/30] test(refactor): use FrappeTestCase --- .../test_opening_invoice_creation_tool.py | 4 +- .../shopping_cart/test_shopping_cart.py | 3 +- .../variant_selector/test_variant_selector.py | 6 +- .../blanket_order/test_blanket_order.py | 4 +- erpnext/manufacturing/doctype/bom/test_bom.py | 4 +- .../bom_update_tool/test_bom_update_tool.py | 4 +- .../doctype/job_card/test_job_card.py | 4 +- .../production_plan/test_production_plan.py | 4 +- .../doctype/routing/test_routing.py | 4 +- .../doctype/work_order/test_work_order.py | 4 +- .../doctype/workstation/test_workstation.py | 4 +- .../selling/doctype/customer/test_customer.py | 5 +- .../test_party_specific_item.py | 6 +- .../doctype/quotation/test_quotation.py | 5 +- .../doctype/sales_order/test_sales_order.py | 4 +- ...st_payment_terms_status_for_sales_order.py | 4 +- ...t_pending_so_items_for_purchase_request.py | 4 +- .../report/sales_analytics/test_analytics.py | 4 +- erpnext/stock/doctype/batch/test_batch.py | 4 +- erpnext/stock/doctype/bin/test_bin.py | 4 +- .../delivery_note/test_delivery_note.py | 4 +- .../delivery_trip/test_delivery_trip.py | 5 +- erpnext/stock/doctype/item/test_item.py | 4 +- .../item_alternative/test_item_alternative.py | 4 +- .../item_attribute/test_item_attribute.py | 5 +- .../doctype/item_price/test_item_price.py | 4 +- .../test_landed_cost_voucher.py | 4 +- .../material_request/test_material_request.py | 4 +- .../doctype/packed_item/test_packed_item.py | 4 +- .../doctype/packing_slip/test_packing_slip.py | 2 +- .../stock/doctype/pick_list/test_pick_list.py | 5 +- .../purchase_receipt/test_purchase_receipt.py | 4 +- .../doctype/putaway_rule/test_putaway_rule.py | 4 +- .../test_quality_inspection.py | 4 +- .../stock/doctype/serial_no/test_serial_no.py | 5 +- .../stock/doctype/shipment/test_shipment.py | 4 +- .../doctype/stock_entry/test_stock_entry.py | 4 +- .../test_stock_ledger_entry.py | 4 +- .../test_stock_reconciliation.py | 4 +- .../stock_settings/test_stock_settings.py | 5 +- .../stock/doctype/warehouse/test_warehouse.py | 4 +- .../report/stock_ageing/test_stock_ageing.py | 6 +- .../stock_analytics/test_stock_analytics.py | 5 +- erpnext/stock/tests/test_valuation.py | 4 +- erpnext/tests/utils.py | 78 ------------------- 45 files changed, 94 insertions(+), 171 deletions(-) diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py index 3eaf6a28f3..77d54a605e 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py @@ -2,6 +2,7 @@ # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import ( create_dimension, @@ -10,11 +11,10 @@ from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension imp from erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool import ( get_temporary_opening_account, ) -from erpnext.tests.utils import ERPNextTestCase test_dependencies = ["Customer", "Supplier", "Accounting Dimension"] -class TestOpeningInvoiceCreationTool(ERPNextTestCase): +class TestOpeningInvoiceCreationTool(FrappeTestCase): @classmethod def setUpClass(self): if not frappe.db.exists("Company", "_Test Opening Invoice Company"): diff --git a/erpnext/e_commerce/shopping_cart/test_shopping_cart.py b/erpnext/e_commerce/shopping_cart/test_shopping_cart.py index 37b3672806..9c389d0d0b 100644 --- a/erpnext/e_commerce/shopping_cart/test_shopping_cart.py +++ b/erpnext/e_commerce/shopping_cart/test_shopping_cart.py @@ -5,6 +5,7 @@ import unittest import frappe +from frappe.tests.utils import change_settings from frappe.utils import add_months, nowdate from erpnext.accounts.doctype.tax_rule.tax_rule import ConflictingTaxRule @@ -15,7 +16,7 @@ from erpnext.e_commerce.shopping_cart.cart import ( get_party, update_cart, ) -from erpnext.tests.utils import change_settings, create_test_contact_and_address +from erpnext.tests.utils import create_test_contact_and_address # test_dependencies = ['Payment Terms Template'] diff --git a/erpnext/e_commerce/variant_selector/test_variant_selector.py b/erpnext/e_commerce/variant_selector/test_variant_selector.py index 4d907c6221..ee098e16e7 100644 --- a/erpnext/e_commerce/variant_selector/test_variant_selector.py +++ b/erpnext/e_commerce/variant_selector/test_variant_selector.py @@ -1,4 +1,5 @@ import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.controllers.item_variant import create_variant from erpnext.e_commerce.doctype.e_commerce_settings.test_e_commerce_settings import ( @@ -7,11 +8,10 @@ from erpnext.e_commerce.doctype.e_commerce_settings.test_e_commerce_settings imp from erpnext.e_commerce.doctype.website_item.website_item import make_website_item from erpnext.e_commerce.variant_selector.utils import get_next_attribute_and_values from erpnext.stock.doctype.item.test_item import make_item -from erpnext.tests.utils import ERPNextTestCase test_dependencies = ["Item"] -class TestVariantSelector(ERPNextTestCase): +class TestVariantSelector(FrappeTestCase): @classmethod def setUpClass(cls): @@ -116,4 +116,4 @@ class TestVariantSelector(ERPNextTestCase): self.assertEqual(next_values["exact_match"][0],"Test-Tshirt-Temp-S-R") self.assertEqual(next_values["exact_match"][0],"Test-Tshirt-Temp-S-R") self.assertEqual(price_info["price_list_rate"], 100.0) - self.assertEqual(price_info["formatted_price_sales_uom"], "₹ 100.00") \ No newline at end of file + self.assertEqual(price_info["formatted_price_sales_uom"], "₹ 100.00") diff --git a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py index eff2344e85..d4d337d841 100644 --- a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py +++ b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py @@ -1,15 +1,15 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_months, today from erpnext import get_company_currency -from erpnext.tests.utils import ERPNextTestCase from .blanket_order import make_order -class TestBlanketOrder(ERPNextTestCase): +class TestBlanketOrder(FrappeTestCase): def setUp(self): frappe.flags.args = frappe._dict() diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py index 53437c8012..3cc91b341c 100644 --- a/erpnext/manufacturing/doctype/bom/test_bom.py +++ b/erpnext/manufacturing/doctype/bom/test_bom.py @@ -7,6 +7,7 @@ from functools import partial import frappe from frappe.test_runner import make_test_records +from frappe.tests.utils import FrappeTestCase from frappe.utils import cstr, flt from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order @@ -17,11 +18,10 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation, ) from erpnext.tests.test_subcontracting import set_backflush_based_on -from erpnext.tests.utils import ERPNextTestCase test_records = frappe.get_test_records('BOM') -class TestBOM(ERPNextTestCase): +class TestBOM(FrappeTestCase): def setUp(self): if not frappe.get_value('Item', '_Test Item'): make_test_records('Item') diff --git a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py index 12576cbf32..b4c625d610 100644 --- a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py +++ b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py @@ -2,15 +2,15 @@ # License: GNU General Public License v3. See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool import update_cost from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom from erpnext.stock.doctype.item.test_item import create_item -from erpnext.tests.utils import ERPNextTestCase test_records = frappe.get_test_records('BOM') -class TestBOMUpdateTool(ERPNextTestCase): +class TestBOMUpdateTool(FrappeTestCase): def test_replace_bom(self): current_bom = "BOM-_Test Item Home Desktop Manufactured-001" diff --git a/erpnext/manufacturing/doctype/job_card/test_job_card.py b/erpnext/manufacturing/doctype/job_card/test_job_card.py index bb5004ba86..33425d2314 100644 --- a/erpnext/manufacturing/doctype/job_card/test_job_card.py +++ b/erpnext/manufacturing/doctype/job_card/test_job_card.py @@ -2,6 +2,7 @@ # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import random_string from erpnext.manufacturing.doctype.job_card.job_card import OperationMismatchError, OverlapError @@ -11,10 +12,9 @@ from erpnext.manufacturing.doctype.job_card.job_card import ( from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record from erpnext.manufacturing.doctype.workstation.test_workstation import make_workstation from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry -from erpnext.tests.utils import ERPNextTestCase -class TestJobCard(ERPNextTestCase): +class TestJobCard(FrappeTestCase): def setUp(self): make_bom_for_jc_tests() diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 2359815813..b2a41ff5b2 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -1,6 +1,7 @@ # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_to_date, flt, now_datetime, nowdate from erpnext.controllers.item_variant import create_variant @@ -16,10 +17,9 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ( create_stock_reconciliation, ) -from erpnext.tests.utils import ERPNextTestCase -class TestProductionPlan(ERPNextTestCase): +class TestProductionPlan(FrappeTestCase): def setUp(self): for item in ['Test Production Item 1', 'Subassembly Item 1', 'Raw Material Item 1', 'Raw Material Item 2']: diff --git a/erpnext/manufacturing/doctype/routing/test_routing.py b/erpnext/manufacturing/doctype/routing/test_routing.py index 8bd60ea4ac..696d9bca14 100644 --- a/erpnext/manufacturing/doctype/routing/test_routing.py +++ b/erpnext/manufacturing/doctype/routing/test_routing.py @@ -2,14 +2,14 @@ # See license.txt import frappe from frappe.test_runner import make_test_records +from frappe.tests.utils import FrappeTestCase from erpnext.manufacturing.doctype.job_card.job_card import OperationSequenceError from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record from erpnext.stock.doctype.item.test_item import make_item -from erpnext.tests.utils import ERPNextTestCase -class TestRouting(ERPNextTestCase): +class TestRouting(FrappeTestCase): @classmethod def setUpClass(cls): cls.item_code = "Test Routing Item - A" diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index 67c47efb5b..549ec7b4a6 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -2,6 +2,7 @@ # License: GNU General Public License v3. See license.txt import frappe +from frappe.tests.utils import FrappeTestCase, timeout from frappe.utils import add_days, add_months, cint, flt, now, today from erpnext.manufacturing.doctype.job_card.job_card import JobCardCancelError @@ -21,10 +22,9 @@ from erpnext.stock.doctype.item.test_item import create_item, make_item from erpnext.stock.doctype.stock_entry import test_stock_entry from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.utils import get_bin -from erpnext.tests.utils import ERPNextTestCase, timeout -class TestWorkOrder(ERPNextTestCase): +class TestWorkOrder(FrappeTestCase): def setUp(self): self.warehouse = '_Test Warehouse 2 - _TC' self.item = '_Test Item' diff --git a/erpnext/manufacturing/doctype/workstation/test_workstation.py b/erpnext/manufacturing/doctype/workstation/test_workstation.py index c298c0a8db..dd51017bb7 100644 --- a/erpnext/manufacturing/doctype/workstation/test_workstation.py +++ b/erpnext/manufacturing/doctype/workstation/test_workstation.py @@ -2,6 +2,7 @@ # See license.txt import frappe from frappe.test_runner import make_test_records +from frappe.tests.utils import FrappeTestCase from erpnext.manufacturing.doctype.operation.test_operation import make_operation from erpnext.manufacturing.doctype.routing.test_routing import create_routing, setup_bom @@ -10,13 +11,12 @@ from erpnext.manufacturing.doctype.workstation.workstation import ( WorkstationHolidayError, check_if_within_operating_hours, ) -from erpnext.tests.utils import ERPNextTestCase test_dependencies = ["Warehouse"] test_records = frappe.get_test_records('Workstation') make_test_records('Workstation') -class TestWorkstation(ERPNextTestCase): +class TestWorkstation(FrappeTestCase): def test_validate_timings(self): check_if_within_operating_hours("_Test Workstation 1", "Operation 1", "2013-02-02 11:00:00", "2013-02-02 19:00:00") check_if_within_operating_hours("_Test Workstation 1", "Operation 1", "2013-02-02 10:00:00", "2013-02-02 20:00:00") diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py index 5301fd0524..165ee81872 100644 --- a/erpnext/selling/doctype/customer/test_customer.py +++ b/erpnext/selling/doctype/customer/test_customer.py @@ -4,12 +4,13 @@ import frappe from frappe.test_runner import make_test_records +from frappe.tests.utils import FrappeTestCase from frappe.utils import flt from erpnext.accounts.party import get_due_date from erpnext.exceptions import PartyDisabled, PartyFrozen from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding -from erpnext.tests.utils import ERPNextTestCase, create_test_contact_and_address +from erpnext.tests.utils import create_test_contact_and_address test_ignore = ["Price List"] test_dependencies = ['Payment Term', 'Payment Terms Template'] @@ -17,7 +18,7 @@ test_records = frappe.get_test_records('Customer') -class TestCustomer(ERPNextTestCase): +class TestCustomer(FrappeTestCase): def setUp(self): if not frappe.get_value('Item', '_Test Item'): make_test_records('Item') diff --git a/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py b/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py index b951044f33..9b672b4b5d 100644 --- a/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py +++ b/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py @@ -1,12 +1,10 @@ # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -import unittest - import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.controllers.queries import item_query -from erpnext.tests.utils import ERPNextTestCase test_dependencies = ['Item', 'Customer', 'Supplier'] @@ -18,7 +16,7 @@ def create_party_specific_item(**args): psi.based_on_value = args.get('based_on_value') psi.insert() -class TestPartySpecificItem(ERPNextTestCase): +class TestPartySpecificItem(FrappeTestCase): def setUp(self): self.customer = frappe.get_last_doc("Customer") self.supplier = frappe.get_last_doc("Supplier") diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index 4357201d23..a749d9e1f1 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -2,14 +2,13 @@ # License: GNU General Public License v3. See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days, add_months, flt, getdate, nowdate -from erpnext.tests.utils import ERPNextTestCase - test_dependencies = ["Product Bundle"] -class TestQuotation(ERPNextTestCase): +class TestQuotation(FrappeTestCase): def test_make_quotation_without_terms(self): quotation = make_quotation(do_not_save=1) self.assertFalse(quotation.get('payment_schedule')) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 73c5bd299a..f5a34c0eec 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -6,6 +6,7 @@ import json import frappe import frappe.permissions from frappe.core.doctype.user_permission.test_user_permission import create_user +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days, flt, getdate, nowdate, today from erpnext.controllers.accounts_controller import update_child_qty_rate @@ -27,10 +28,9 @@ from erpnext.selling.doctype.sales_order.sales_order import ( ) from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry -from erpnext.tests.utils import ERPNextTestCase -class TestSalesOrder(ERPNextTestCase): +class TestSalesOrder(FrappeTestCase): @classmethod def setUpClass(cls): diff --git a/erpnext/selling/report/payment_terms_status_for_sales_order/test_payment_terms_status_for_sales_order.py b/erpnext/selling/report/payment_terms_status_for_sales_order/test_payment_terms_status_for_sales_order.py index cad41e1dc0..f7f8a5dbce 100644 --- a/erpnext/selling/report/payment_terms_status_for_sales_order/test_payment_terms_status_for_sales_order.py +++ b/erpnext/selling/report/payment_terms_status_for_sales_order/test_payment_terms_status_for_sales_order.py @@ -1,6 +1,7 @@ import datetime import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice @@ -9,12 +10,11 @@ from erpnext.selling.report.payment_terms_status_for_sales_order.payment_terms_s execute, ) from erpnext.stock.doctype.item.test_item import create_item -from erpnext.tests.utils import ERPNextTestCase test_dependencies = ["Sales Order", "Item", "Sales Invoice", "Payment Terms Template"] -class TestPaymentTermsStatusForSalesOrder(ERPNextTestCase): +class TestPaymentTermsStatusForSalesOrder(FrappeTestCase): def create_payment_terms_template(self): # create template for 50-50 payments template = None diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py index d62915fc66..16162acc8f 100644 --- a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py +++ b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py @@ -2,6 +2,7 @@ # For license information, please see license.txt +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_months, nowdate from erpnext.selling.doctype.sales_order.sales_order import make_material_request @@ -9,10 +10,9 @@ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_orde from erpnext.selling.report.pending_so_items_for_purchase_request.pending_so_items_for_purchase_request import ( execute, ) -from erpnext.tests.utils import ERPNextTestCase -class TestPendingSOItemsForPurchaseRequest(ERPNextTestCase): +class TestPendingSOItemsForPurchaseRequest(FrappeTestCase): def test_result_for_partial_material_request(self): so = make_sales_order() mr=make_material_request(so.name) diff --git a/erpnext/selling/report/sales_analytics/test_analytics.py b/erpnext/selling/report/sales_analytics/test_analytics.py index f56cce2dfd..564f48fef3 100644 --- a/erpnext/selling/report/sales_analytics/test_analytics.py +++ b/erpnext/selling/report/sales_analytics/test_analytics.py @@ -3,13 +3,13 @@ import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from erpnext.selling.report.sales_analytics.sales_analytics import execute -from erpnext.tests.utils import ERPNextTestCase -class TestAnalytics(ERPNextTestCase): +class TestAnalytics(FrappeTestCase): def test_sales_analytics(self): frappe.db.sql("delete from `tabSales Order` where company='_Test Company 2'") diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py index 613dd3f14d..5763753853 100644 --- a/erpnext/stock/doctype/batch/test_batch.py +++ b/erpnext/stock/doctype/batch/test_batch.py @@ -5,6 +5,7 @@ import json import frappe from frappe.exceptions import ValidationError +from frappe.tests.utils import FrappeTestCase from frappe.utils import cint, flt from frappe.utils.data import add_to_date, getdate @@ -16,10 +17,9 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ) from erpnext.stock.get_item_details import get_item_details from erpnext.stock.stock_ledger import get_valuation_rate -from erpnext.tests.utils import ERPNextTestCase -class TestBatch(ERPNextTestCase): +class TestBatch(FrappeTestCase): def test_item_has_batch_enabled(self): self.assertRaises(ValidationError, frappe.get_doc({ "doctype": "Batch", diff --git a/erpnext/stock/doctype/bin/test_bin.py b/erpnext/stock/doctype/bin/test_bin.py index 250126c6b9..ec0d8a88e3 100644 --- a/erpnext/stock/doctype/bin/test_bin.py +++ b/erpnext/stock/doctype/bin/test_bin.py @@ -2,13 +2,13 @@ # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.utils import _create_bin -from erpnext.tests.utils import ERPNextTestCase -class TestBin(ERPNextTestCase): +class TestBin(FrappeTestCase): def test_concurrent_inserts(self): diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index bd18e788ba..16c892128a 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -6,6 +6,7 @@ import json import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import cstr, flt, nowdate, nowtime from erpnext.accounts.doctype.account.test_account import get_inventory_account @@ -35,10 +36,9 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ) from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse from erpnext.stock.stock_ledger import get_previous_sle -from erpnext.tests.utils import ERPNextTestCase -class TestDeliveryNote(ERPNextTestCase): +class TestDeliveryNote(FrappeTestCase): def test_over_billing_against_dn(self): frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) diff --git a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py index 321f48b2c5..dcdff4a0f1 100644 --- a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py +++ b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py @@ -4,6 +4,7 @@ import unittest import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days, flt, now_datetime, nowdate import erpnext @@ -12,10 +13,10 @@ from erpnext.stock.doctype.delivery_trip.delivery_trip import ( make_expense_claim, notify_customers, ) -from erpnext.tests.utils import ERPNextTestCase, create_test_contact_and_address +from erpnext.tests.utils import create_test_contact_and_address -class TestDeliveryTrip(ERPNextTestCase): +class TestDeliveryTrip(FrappeTestCase): def setUp(self): super().setUp() driver = create_driver() diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 9491e17259..d7671b1d71 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -6,6 +6,7 @@ import json import frappe from frappe.test_runner import make_test_objects +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_days, today from erpnext.controllers.item_variant import ( @@ -25,7 +26,6 @@ from erpnext.stock.doctype.item.item import ( ) from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.stock.get_item_details import get_item_details -from erpnext.tests.utils import ERPNextTestCase, change_settings test_ignore = ["BOM"] test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand", "Item Attribute"] @@ -53,7 +53,7 @@ def make_item(item_code, properties=None): return item -class TestItem(ERPNextTestCase): +class TestItem(FrappeTestCase): def setUp(self): super().setUp() frappe.flags.attribute_values = None diff --git a/erpnext/stock/doctype/item_alternative/test_item_alternative.py b/erpnext/stock/doctype/item_alternative/test_item_alternative.py index 3976af4e88..501c1c1ad3 100644 --- a/erpnext/stock/doctype/item_alternative/test_item_alternative.py +++ b/erpnext/stock/doctype/item_alternative/test_item_alternative.py @@ -4,6 +4,7 @@ import json import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import flt from erpnext.buying.doctype.purchase_order.purchase_order import ( @@ -18,10 +19,9 @@ from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ( create_stock_reconciliation, ) -from erpnext.tests.utils import ERPNextTestCase -class TestItemAlternative(ERPNextTestCase): +class TestItemAlternative(FrappeTestCase): def setUp(self): super().setUp() make_items() diff --git a/erpnext/stock/doctype/item_attribute/test_item_attribute.py b/erpnext/stock/doctype/item_attribute/test_item_attribute.py index 0b7ca25715..055c22e0c5 100644 --- a/erpnext/stock/doctype/item_attribute/test_item_attribute.py +++ b/erpnext/stock/doctype/item_attribute/test_item_attribute.py @@ -6,11 +6,12 @@ import frappe test_records = frappe.get_test_records('Item Attribute') +from frappe.tests.utils import FrappeTestCase + from erpnext.stock.doctype.item_attribute.item_attribute import ItemAttributeIncrementError -from erpnext.tests.utils import ERPNextTestCase -class TestItemAttribute(ERPNextTestCase): +class TestItemAttribute(FrappeTestCase): def setUp(self): super().setUp() if frappe.db.exists("Item Attribute", "_Test_Length"): diff --git a/erpnext/stock/doctype/item_price/test_item_price.py b/erpnext/stock/doctype/item_price/test_item_price.py index f81770e487..6ceba3f8d3 100644 --- a/erpnext/stock/doctype/item_price/test_item_price.py +++ b/erpnext/stock/doctype/item_price/test_item_price.py @@ -4,13 +4,13 @@ import frappe from frappe.test_runner import make_test_records_for_doctype +from frappe.tests.utils import FrappeTestCase from erpnext.stock.doctype.item_price.item_price import ItemPriceDuplicateItem from erpnext.stock.get_item_details import get_price_list_rate_for, process_args -from erpnext.tests.utils import ERPNextTestCase -class TestItemPrice(ERPNextTestCase): +class TestItemPrice(FrappeTestCase): def setUp(self): super().setUp() frappe.db.sql("delete from `tabItem Price`") diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py index df8cadd7f8..dbaefc1e11 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py @@ -4,6 +4,7 @@ import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_to_date, flt, now from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account @@ -14,10 +15,9 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import ( get_gl_entries, make_purchase_receipt, ) -from erpnext.tests.utils import ERPNextTestCase -class TestLandedCostVoucher(ERPNextTestCase): +class TestLandedCostVoucher(FrappeTestCase): def test_landed_cost_voucher(self): frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1) diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index 383b0ae806..1cda781617 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -6,6 +6,7 @@ import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import flt, today from erpnext.stock.doctype.item.test_item import create_item @@ -15,10 +16,9 @@ from erpnext.stock.doctype.material_request.material_request import ( make_supplier_quotation, raise_work_orders, ) -from erpnext.tests.utils import ERPNextTestCase -class TestMaterialRequest(ERPNextTestCase): +class TestMaterialRequest(FrappeTestCase): def test_make_purchase_order(self): mr = frappe.copy_doc(test_records[0]).insert() diff --git a/erpnext/stock/doctype/packed_item/test_packed_item.py b/erpnext/stock/doctype/packed_item/test_packed_item.py index 2521ac9fe7..94268a8ef3 100644 --- a/erpnext/stock/doctype/packed_item/test_packed_item.py +++ b/erpnext/stock/doctype/packed_item/test_packed_item.py @@ -1,6 +1,7 @@ # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_to_date, nowdate from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle @@ -9,10 +10,9 @@ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_orde from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry -from erpnext.tests.utils import ERPNextTestCase, change_settings -class TestPackedItem(ERPNextTestCase): +class TestPackedItem(FrappeTestCase): "Test impact on Packed Items table in various scenarios." @classmethod def setUpClass(cls) -> None: diff --git a/erpnext/stock/doctype/packing_slip/test_packing_slip.py b/erpnext/stock/doctype/packing_slip/test_packing_slip.py index 5eb6b7399a..bc405b2099 100644 --- a/erpnext/stock/doctype/packing_slip/test_packing_slip.py +++ b/erpnext/stock/doctype/packing_slip/test_packing_slip.py @@ -4,7 +4,7 @@ import unittest # test_records = frappe.get_test_records('Packing Slip') -from erpnext.tests.utils import ERPNextTestCase +from frappe.tests.utils import FrappeTestCase class TestPackingSlip(unittest.TestCase): diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py index 41e3150f0d..f3b6b89784 100644 --- a/erpnext/stock/doctype/pick_list/test_pick_list.py +++ b/erpnext/stock/doctype/pick_list/test_pick_list.py @@ -6,16 +6,17 @@ from frappe import _dict test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch'] +from frappe.tests.utils import FrappeTestCase + from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.pick_list.pick_list import create_delivery_note from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import ( EmptyStockReconciliationItemsError, ) -from erpnext.tests.utils import ERPNextTestCase -class TestPickList(ERPNextTestCase): +class TestPickList(FrappeTestCase): def test_pick_list_picks_warehouse_for_each_item(self): try: diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index d481689c13..a24acb1bd8 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -7,6 +7,7 @@ import unittest from collections import defaultdict import frappe +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_days, cint, cstr, flt, today import erpnext @@ -17,10 +18,9 @@ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchas from erpnext.stock.doctype.serial_no.serial_no import SerialNoDuplicateError, get_serial_nos from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.stock_ledger import SerialNoExistsInFutureTransaction -from erpnext.tests.utils import ERPNextTestCase, change_settings -class TestPurchaseReceipt(ERPNextTestCase): +class TestPurchaseReceipt(FrappeTestCase): def setUp(self): frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1) diff --git a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py index ff1c19a827..4e8d71fe5e 100644 --- a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py +++ b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py @@ -2,6 +2,7 @@ # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.stock.doctype.batch.test_batch import make_new_batch from erpnext.stock.doctype.item.test_item import make_item @@ -9,10 +10,9 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_pu from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.get_item_details import get_conversion_factor -from erpnext.tests.utils import ERPNextTestCase -class TestPutawayRule(ERPNextTestCase): +class TestPutawayRule(FrappeTestCase): def setUp(self): if not frappe.db.exists("Item", "_Rice"): make_item("_Rice", { diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py index 308c62875d..601ca054b5 100644 --- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py +++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py @@ -2,6 +2,7 @@ # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import nowdate from erpnext.controllers.stock_controller import ( @@ -13,12 +14,11 @@ from erpnext.controllers.stock_controller import ( from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry -from erpnext.tests.utils import ERPNextTestCase # test_records = frappe.get_test_records('Quality Inspection') -class TestQualityInspection(ERPNextTestCase): +class TestQualityInspection(FrappeTestCase): def setUp(self): super().setUp() create_item("_Test Item with QA") diff --git a/erpnext/stock/doctype/serial_no/test_serial_no.py b/erpnext/stock/doctype/serial_no/test_serial_no.py index f8cea71725..057a7d4c01 100644 --- a/erpnext/stock/doctype/serial_no/test_serial_no.py +++ b/erpnext/stock/doctype/serial_no/test_serial_no.py @@ -18,11 +18,12 @@ from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse test_dependencies = ["Item"] test_records = frappe.get_test_records('Serial No') +from frappe.tests.utils import FrappeTestCase + from erpnext.stock.doctype.serial_no.serial_no import * -from erpnext.tests.utils import ERPNextTestCase -class TestSerialNo(ERPNextTestCase): +class TestSerialNo(FrappeTestCase): def tearDown(self): frappe.db.rollback() diff --git a/erpnext/stock/doctype/shipment/test_shipment.py b/erpnext/stock/doctype/shipment/test_shipment.py index afe821845a..317abb6d03 100644 --- a/erpnext/stock/doctype/shipment/test_shipment.py +++ b/erpnext/stock/doctype/shipment/test_shipment.py @@ -4,12 +4,12 @@ from datetime import date, timedelta import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.stock.doctype.delivery_note.delivery_note import make_shipment -from erpnext.tests.utils import ERPNextTestCase -class TestShipment(ERPNextTestCase): +class TestShipment(FrappeTestCase): def test_shipment_from_delivery_note(self): delivery_note = create_test_delivery_note() delivery_note.submit() diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index c5afa49166..54c0e43c5e 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -6,6 +6,7 @@ import unittest import frappe from frappe.permissions import add_user_permission, remove_user_permission +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import flt, nowdate, nowtime from erpnext.accounts.doctype.account.test_account import get_inventory_account @@ -28,7 +29,6 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation, ) from erpnext.stock.stock_ledger import NegativeStockError, get_previous_sle -from erpnext.tests.utils import ERPNextTestCase, change_settings def get_sle(**args): @@ -42,7 +42,7 @@ def get_sle(**args): order by timestamp(posting_date, posting_time) desc, creation desc limit 1"""% condition, values, as_dict=1) -class TestStockEntry(ERPNextTestCase): +class TestStockEntry(FrappeTestCase): def tearDown(self): frappe.db.rollback() frappe.set_user("Administrator") diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py index 0864ece995..01d25b2e86 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py @@ -7,6 +7,7 @@ from uuid import uuid4 import frappe from frappe.core.page.permission_manager.permission_manager import reset +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days, today from erpnext.stock.doctype.delivery_note.test_delivery_note import ( @@ -24,10 +25,9 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation, ) from erpnext.stock.stock_ledger import get_previous_sle -from erpnext.tests.utils import ERPNextTestCase -class TestStockLedgerEntry(ERPNextTestCase): +class TestStockLedgerEntry(FrappeTestCase): def setUp(self): items = create_items() reset('Stock Entry') diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index 2ffe127d9a..e6b252e856 100644 --- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -6,6 +6,7 @@ import frappe +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_days, cstr, flt, nowdate, nowtime, random_string from erpnext.accounts.utils import get_stock_and_account_balance @@ -19,10 +20,9 @@ from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import ( from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after from erpnext.stock.utils import get_incoming_rate, get_stock_value_on, get_valuation_method -from erpnext.tests.utils import ERPNextTestCase, change_settings -class TestStockReconciliation(ERPNextTestCase): +class TestStockReconciliation(FrappeTestCase): @classmethod def setUpClass(cls): create_batch_or_serial_no_items() diff --git a/erpnext/stock/doctype/stock_settings/test_stock_settings.py b/erpnext/stock/doctype/stock_settings/test_stock_settings.py index 072b54b820..13496718ea 100644 --- a/erpnext/stock/doctype/stock_settings/test_stock_settings.py +++ b/erpnext/stock/doctype/stock_settings/test_stock_settings.py @@ -4,11 +4,10 @@ import unittest import frappe - -from erpnext.tests.utils import ERPNextTestCase +from frappe.tests.utils import FrappeTestCase -class TestStockSettings(ERPNextTestCase): +class TestStockSettings(FrappeTestCase): def setUp(self): super().setUp() frappe.db.set_value("Stock Settings", None, "clean_description_html", 0) diff --git a/erpnext/stock/doctype/warehouse/test_warehouse.py b/erpnext/stock/doctype/warehouse/test_warehouse.py index 26db2642e4..cdb771935b 100644 --- a/erpnext/stock/doctype/warehouse/test_warehouse.py +++ b/erpnext/stock/doctype/warehouse/test_warehouse.py @@ -3,17 +3,17 @@ import frappe from frappe.test_runner import make_test_records +from frappe.tests.utils import FrappeTestCase from frappe.utils import cint import erpnext from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry -from erpnext.tests.utils import ERPNextTestCase test_records = frappe.get_test_records('Warehouse') -class TestWarehouse(ERPNextTestCase): +class TestWarehouse(FrappeTestCase): def setUp(self): super().setUp() if not frappe.get_value('Item', '_Test Item'): diff --git a/erpnext/stock/report/stock_ageing/test_stock_ageing.py b/erpnext/stock/report/stock_ageing/test_stock_ageing.py index 3fc357e8d4..2630805c62 100644 --- a/erpnext/stock/report/stock_ageing/test_stock_ageing.py +++ b/erpnext/stock/report/stock_ageing/test_stock_ageing.py @@ -2,12 +2,12 @@ # See license.txt import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.stock.report.stock_ageing.stock_ageing import FIFOSlots, format_report_data -from erpnext.tests.utils import ERPNextTestCase -class TestStockAgeing(ERPNextTestCase): +class TestStockAgeing(FrappeTestCase): def setUp(self) -> None: self.filters = frappe._dict( company="_Test Company", @@ -610,4 +610,4 @@ def generate_item_and_item_wh_wise_slots(filters, sle): item_wh_wise_slots = FIFOSlots(filters, sle).generate() filters.show_warehouse_wise_stock = False - return item_wise_slots, item_wh_wise_slots \ No newline at end of file + return item_wise_slots, item_wh_wise_slots diff --git a/erpnext/stock/report/stock_analytics/test_stock_analytics.py b/erpnext/stock/report/stock_analytics/test_stock_analytics.py index 32df585937..f6c98f914d 100644 --- a/erpnext/stock/report/stock_analytics/test_stock_analytics.py +++ b/erpnext/stock/report/stock_analytics/test_stock_analytics.py @@ -1,14 +1,13 @@ import datetime -import unittest from frappe import _dict +from frappe.tests.utils import FrappeTestCase from erpnext.accounts.utils import get_fiscal_year from erpnext.stock.report.stock_analytics.stock_analytics import get_period_date_ranges -from erpnext.tests.utils import ERPNextTestCase -class TestStockAnalyticsReport(ERPNextTestCase): +class TestStockAnalyticsReport(FrappeTestCase): def test_get_period_date_ranges(self): filters = _dict(range="Monthly", from_date="2020-12-28", to_date="2021-02-06") diff --git a/erpnext/stock/tests/test_valuation.py b/erpnext/stock/tests/test_valuation.py index bdb768f1ad..b64ff8e28c 100644 --- a/erpnext/stock/tests/test_valuation.py +++ b/erpnext/stock/tests/test_valuation.py @@ -2,13 +2,13 @@ import json import unittest import frappe +from frappe.tests.utils import FrappeTestCase from hypothesis import given from hypothesis import strategies as st from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.stock.valuation import FIFOValuation, LIFOValuation, round_off_if_near_zero -from erpnext.tests.utils import ERPNextTestCase qty_gen = st.floats(min_value=-1e6, max_value=1e6) value_gen = st.floats(min_value=1, max_value=1e6) @@ -290,7 +290,7 @@ class TestLIFOValuation(unittest.TestCase): self.assertTotalQty(total_qty) self.assertTotalValue(total_value) -class TestLIFOValuationSLE(ERPNextTestCase): +class TestLIFOValuationSLE(FrappeTestCase): ITEM_CODE = "_Test LIFO item" WAREHOUSE = "_Test Warehouse - _TC" diff --git a/erpnext/tests/utils.py b/erpnext/tests/utils.py index 40c95eb7a3..d795253665 100644 --- a/erpnext/tests/utils.py +++ b/erpnext/tests/utils.py @@ -1,10 +1,6 @@ # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -import copy -import signal -import unittest -from contextlib import contextmanager from typing import Any, Dict, NewType, Optional import frappe @@ -13,22 +9,6 @@ from frappe.core.doctype.report.report import get_report_module_dotted_path ReportFilters = Dict[str, Any] ReportName = NewType("ReportName", str) - -class ERPNextTestCase(unittest.TestCase): - """A sane default test class for ERPNext tests.""" - - - @classmethod - def setUpClass(cls) -> None: - frappe.db.commit() - return super().setUpClass() - - @classmethod - def tearDownClass(cls) -> None: - frappe.db.rollback() - return super().tearDownClass() - - def create_test_contact_and_address(): frappe.db.sql('delete from tabContact') frappe.db.sql('delete from `tabContact Email`') @@ -81,43 +61,6 @@ def create_test_contact_and_address(): contact_two.insert() -@contextmanager -def change_settings(doctype, settings_dict): - """ A context manager to ensure that settings are changed before running - function and restored after running it regardless of exceptions occured. - This is useful in tests where you want to make changes in a function but - don't retain those changes. - import and use as decorator to cover full function or using `with` statement. - - example: - @change_settings("Stock Settings", {"item_naming_by": "Naming Series"}) - def test_case(self): - ... - """ - - try: - settings = frappe.get_doc(doctype) - # remember setting - previous_settings = copy.deepcopy(settings_dict) - for key in previous_settings: - previous_settings[key] = getattr(settings, key) - - # change setting - for key, value in settings_dict.items(): - setattr(settings, key, value) - settings.save() - # singles are cached by default, clear to avoid flake - frappe.db.value_cache[settings] = {} - yield # yield control to calling function - - finally: - # restore settings - settings = frappe.get_doc(doctype) - for key, value in previous_settings.items(): - setattr(settings, key, value) - settings.save() - - def execute_script_report( report_name: ReportName, module: str, @@ -157,24 +100,3 @@ def execute_script_report( except Exception: print(f"Report failed to execute with filters: {test_filter}") raise - - - -def timeout(seconds=30, error_message="Test timed out."): - """ Timeout decorator to ensure a test doesn't run for too long. - - adapted from https://stackoverflow.com/a/2282656""" - def decorator(func): - def _handle_timeout(signum, frame): - raise Exception(error_message) - - def wrapper(*args, **kwargs): - signal.signal(signal.SIGALRM, _handle_timeout) - signal.alarm(seconds) - try: - result = func(*args, **kwargs) - finally: - signal.alarm(0) - return result - return wrapper - return decorator From 829c453cb616107471ed5fd6b0ef7b75bb0420e7 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 28 Feb 2022 17:12:51 +0530 Subject: [PATCH 18/30] test: remove transaction commits from buying module --- erpnext/buying/doctype/purchase_order/test_purchase_order.py | 4 ++-- .../request_for_quotation/test_request_for_quotation.py | 4 ++-- erpnext/buying/doctype/supplier/test_supplier.py | 5 +++-- .../doctype/supplier_quotation/test_supplier_quotation.py | 4 ++-- .../doctype/supplier_scorecard/test_supplier_scorecard.py | 4 ++-- .../test_supplier_scorecard_criteria.py | 4 ++-- .../test_supplier_scorecard_variable.py | 4 ++-- .../report/procurement_tracker/test_procurement_tracker.py | 4 ++-- .../test_subcontracted_item_to_be_received.py | 4 ++-- .../test_subcontracted_raw_materials_to_be_transferred.py | 4 ++-- 10 files changed, 21 insertions(+), 20 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 645e97ee7c..efa2ab1268 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -3,9 +3,9 @@ import json -import unittest import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days, flt, getdate, nowdate from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry @@ -27,7 +27,7 @@ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import ( from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry -class TestPurchaseOrder(unittest.TestCase): +class TestPurchaseOrder(FrappeTestCase): def test_make_purchase_receipt(self): po = create_purchase_order(do_not_submit=True) self.assertRaises(frappe.ValidationError, make_purchase_receipt, po.name) diff --git a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py index 51901991b5..5b2112424c 100644 --- a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py @@ -1,9 +1,9 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -import unittest import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils import nowdate from erpnext.buying.doctype.request_for_quotation.request_for_quotation import ( @@ -16,7 +16,7 @@ from erpnext.stock.doctype.item.test_item import make_item from erpnext.templates.pages.rfq import check_supplier_has_docname_access -class TestRequestforQuotation(unittest.TestCase): +class TestRequestforQuotation(FrappeTestCase): def test_quote_status(self): rfq = make_request_for_quotation() diff --git a/erpnext/buying/doctype/supplier/test_supplier.py b/erpnext/buying/doctype/supplier/test_supplier.py index 0fb81b2578..7358e2af22 100644 --- a/erpnext/buying/doctype/supplier/test_supplier.py +++ b/erpnext/buying/doctype/supplier/test_supplier.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -import unittest import frappe from frappe.test_runner import make_test_records @@ -12,8 +11,10 @@ from erpnext.exceptions import PartyDisabled test_dependencies = ['Payment Term', 'Payment Terms Template'] test_records = frappe.get_test_records('Supplier') +from frappe.tests.utils import FrappeTestCase -class TestSupplier(unittest.TestCase): + +class TestSupplier(FrappeTestCase): def test_get_supplier_group_details(self): doc = frappe.new_doc("Supplier Group") doc.supplier_group_name = "_Testing Supplier Group" diff --git a/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py b/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py index d48ac7eb3b..a4d45975c3 100644 --- a/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py +++ b/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py @@ -3,12 +3,12 @@ -import unittest import frappe +from frappe.tests.utils import FrappeTestCase -class TestPurchaseOrder(unittest.TestCase): +class TestPurchaseOrder(FrappeTestCase): def test_make_purchase_order(self): from erpnext.buying.doctype.supplier_quotation.supplier_quotation import make_purchase_order diff --git a/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py b/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py index 7908c35cbb..8ecc2cd466 100644 --- a/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py +++ b/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py @@ -1,12 +1,12 @@ # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -import unittest import frappe +from frappe.tests.utils import FrappeTestCase -class TestSupplierScorecard(unittest.TestCase): +class TestSupplierScorecard(FrappeTestCase): def test_create_scorecard(self): doc = make_supplier_scorecard().insert() diff --git a/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py b/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py index dacc982420..7ff84c15e5 100644 --- a/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py +++ b/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py @@ -1,12 +1,12 @@ # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -import unittest import frappe +from frappe.tests.utils import FrappeTestCase -class TestSupplierScorecardCriteria(unittest.TestCase): +class TestSupplierScorecardCriteria(FrappeTestCase): def test_variables_exist(self): delete_test_scorecards() for d in test_good_criteria: diff --git a/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py b/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py index 4d75981125..32005a37dc 100644 --- a/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py +++ b/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py @@ -1,16 +1,16 @@ # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -import unittest import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.buying.doctype.supplier_scorecard_variable.supplier_scorecard_variable import ( VariablePathNotFound, ) -class TestSupplierScorecardVariable(unittest.TestCase): +class TestSupplierScorecardVariable(FrappeTestCase): def test_variable_exist(self): for d in test_existing_variables: my_doc = frappe.get_doc("Supplier Scorecard Variable", d.get("name")) diff --git a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py index 84de8c6743..44524527e3 100644 --- a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py +++ b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py @@ -2,10 +2,10 @@ # For license information, please see license.txt -import unittest from datetime import datetime import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt from erpnext.buying.report.procurement_tracker.procurement_tracker import execute @@ -14,7 +14,7 @@ from erpnext.stock.doctype.material_request.test_material_request import make_ma from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse -class TestProcurementTracker(unittest.TestCase): +class TestProcurementTracker(FrappeTestCase): def test_result_for_procurement_tracker(self): filters = { 'company': '_Test Procurement Company', diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py index 144523ad52..c2b38d38e1 100644 --- a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py +++ b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py @@ -3,9 +3,9 @@ # Compiled at: 2019-05-06 09:51:46 # Decompiled by https://python-decompiler.com -import unittest import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order @@ -15,7 +15,7 @@ from erpnext.buying.report.subcontracted_item_to_be_received.subcontracted_item_ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry -class TestSubcontractedItemToBeReceived(unittest.TestCase): +class TestSubcontractedItemToBeReceived(FrappeTestCase): def test_pending_and_received_qty(self): po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes') diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py index 3c203ac23f..fc9acabc81 100644 --- a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py +++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py @@ -4,9 +4,9 @@ # Decompiled by https://python-decompiler.com import json -import unittest import frappe +from frappe.tests.utils import FrappeTestCase from erpnext.buying.doctype.purchase_order.purchase_order import make_rm_stock_entry from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order @@ -16,7 +16,7 @@ from erpnext.buying.report.subcontracted_raw_materials_to_be_transferred.subcont from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry -class TestSubcontractedItemToBeTransferred(unittest.TestCase): +class TestSubcontractedItemToBeTransferred(FrappeTestCase): def test_pending_and_transferred_qty(self): po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes', supplier_warehouse="_Test Warehouse 1 - _TC") From 19fb7ead9f249d28403f618297009d498675d224 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 28 Feb 2022 18:05:58 +0530 Subject: [PATCH 19/30] test: Add test case for payment entry taxes --- .../doctype/payment_entry/payment_entry.py | 8 ++-- .../payment_entry/test_payment_entry.py | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 6ec15e1e87..eb2019bdf0 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -946,11 +946,11 @@ class PaymentEntry(AccountsController): tax.base_total = tax.total * self.source_exchange_rate if self.payment_type == 'Pay': - self.base_total_taxes_and_charges += current_tax_amount * self.source_exchange_rate - self.total_taxes_and_charges += current_tax_amount * self.target_exchange_rate + self.base_total_taxes_and_charges += flt(current_tax_amount / self.source_exchange_rate) + self.total_taxes_and_charges += flt(current_tax_amount / self.target_exchange_rate) else: - self.base_total_taxes_and_charges += current_tax_amount * self.target_exchange_rate - self.total_taxes_and_charges += current_tax_amount * self.source_exchange_rate + self.base_total_taxes_and_charges += flt(current_tax_amount / self.target_exchange_rate) + self.total_taxes_and_charges += flt(current_tax_amount / self.source_exchange_rate) if self.get('taxes'): self.paid_amount_after_tax = self.get('taxes')[-1].base_total diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index cc3528e9aa..349b8bb5b1 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -633,6 +633,45 @@ class TestPaymentEntry(unittest.TestCase): self.assertEqual(flt(expected_party_balance), party_balance) self.assertEqual(flt(expected_party_account_balance), party_account_balance) + def test_multi_currency_payment_entry_with_taxes(self): + payment_entry = create_payment_entry(party='_Test Supplier USD', paid_to = '_Test Payable USD - _TC', + save=True) + payment_entry.append('taxes', { + 'account_head': '_Test Account Service Tax - _TC', + 'charge_type': 'Actual', + 'tax_amount': 10, + 'add_deduct_tax': 'Add', + 'description': 'Test' + }) + + payment_entry.save() + self.assertEqual(payment_entry.base_total_taxes_and_charges, 10) + self.assertEqual(flt(payment_entry.total_taxes_and_charges, 2), flt(10 / payment_entry.target_exchange_rate, 2)) + +def create_payment_entry(**args): + payment_entry = frappe.new_doc('Payment Entry') + payment_entry.company = args.get('company') or '_Test Company' + payment_entry.payment_type = args.get('payment_type') or 'Pay' + payment_entry.party_type = args.get('party_type') or 'Supplier' + payment_entry.party = args.get('party') or '_Test Supplier' + payment_entry.paid_from = args.get('paid_from') or '_Test Bank - _TC' + payment_entry.paid_to = args.get('paid_to') or 'Creditors - _TC' + payment_entry.paid_amount = args.get('paid_amount') or 1000 + + payment_entry.setup_party_account_field() + payment_entry.set_missing_values() + payment_entry.set_exchange_rate() + payment_entry.received_amount = payment_entry.paid_amount / payment_entry.target_exchange_rate + payment_entry.reference_no = 'Test001' + payment_entry.reference_date = nowdate() + + if args.get('save'): + payment_entry.save() + if args.get('submit'): + payment_entry.submit() + + return payment_entry + def create_payment_terms_template(): create_payment_term('Basic Amount Receivable') From 4e2c284be7904f9d553a6eb8e93e100edcd909e6 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Tue, 1 Mar 2022 08:52:42 +0530 Subject: [PATCH 20/30] fix(minor): nix the ugly banner --- .../includes/footer/footer_powered.html | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/erpnext/templates/includes/footer/footer_powered.html b/erpnext/templates/includes/footer/footer_powered.html index 82b2716a92..faf5e9278c 100644 --- a/erpnext/templates/includes/footer/footer_powered.html +++ b/erpnext/templates/includes/footer/footer_powered.html @@ -1,27 +1 @@ -{% set domains = frappe.get_doc("Domain Settings").active_domains %} -{% set links = { - 'Manufacturing': '/manufacturing', - 'Services': '/services', - 'Retail': '/retail', - 'Distribution': '/distribution', - 'Non Profit': '/non-profit', - 'Education': '/education', - 'Healthcare': '/healthcare', - 'Agriculture': '/agriculture', - 'Hospitality': '' -} %} - -{% set link = '' %} -{% set label = '' %} -{% if domains %} - {% set label = domains[0].domain %} - {% set link = links[label] %} -{% endif %} - -{% if label == "Services" %} - {% set label = "Service" %} -{% endif %} - - - -Powered by ERPNext - {{ '' if domains else 'Open Source' }} ERP Software {{ ('for ' + label + ' Companies') if domains else '' }} +Powered by ERPNext From 366120ffeed36c68b9ceb1f677cc4497673b4289 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 1 Mar 2022 11:56:20 +0530 Subject: [PATCH 21/30] fix: Deferred revenue booking --- erpnext/accounts/deferred_revenue.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py index 9e2cdfffd9..ab1061beeb 100644 --- a/erpnext/accounts/deferred_revenue.py +++ b/erpnext/accounts/deferred_revenue.py @@ -120,6 +120,7 @@ def get_booking_dates(doc, item, posting_date=None): prev_gl_entry = frappe.db.sql(''' select name, posting_date from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s + and is_cancelled = 0 order by posting_date desc limit 1 ''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True) @@ -227,6 +228,7 @@ def get_already_booked_amount(doc, item): gl_entries_details = frappe.db.sql(''' select sum({0}) as total_credit, sum({1}) as total_credit_in_account_currency, voucher_detail_no from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s + and is_cancelled = 0 group by voucher_detail_no '''.format(total_credit_debit, total_credit_debit_currency), (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True) @@ -282,7 +284,7 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None): return # check if books nor frozen till endate: - if getdate(end_date) >= getdate(accounts_frozen_upto): + if accounts_frozen_upto and (end_date) <= getdate(accounts_frozen_upto): end_date = get_last_day(add_days(accounts_frozen_upto, 1)) if via_journal_entry: From 25fa6344a6c3dc3af7ecea250d30a421f4016afc Mon Sep 17 00:00:00 2001 From: marination Date: Tue, 1 Mar 2022 12:24:45 +0530 Subject: [PATCH 22/30] test: Adjust test as per teardown - make tests use multi level bom in WO, as BOM at setup is used - earlier, an intermediate BOM made in a test would override the BOM at setup --- .../doctype/production_plan/test_production_plan.py | 4 +++- erpnext/manufacturing/doctype/work_order/test_work_order.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 85ecec2f69..ca8cc7a47e 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -154,7 +154,7 @@ class TestProductionPlan(FrappeTestCase): use_multi_level_bom=0, ignore_existing_ordered_qty=0 ) - self.assertTrue(len(pln.mr_items), 0) + self.assertTrue(len(pln.mr_items)) sr1.cancel() sr2.cancel() @@ -575,6 +575,7 @@ class TestProductionPlan(FrappeTestCase): wip_warehouse='Work In Progress - _TC', fg_warehouse='Finished Goods - _TC', skip_transfer=1, + use_multi_level_bom=1, do_not_submit=True ) wo.production_plan = pln.name @@ -619,6 +620,7 @@ class TestProductionPlan(FrappeTestCase): wip_warehouse='Work In Progress - _TC', fg_warehouse='Finished Goods - _TC', skip_transfer=1, + use_multi_level_bom=1, do_not_submit=True ) wo.production_plan = pln.name diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index 549ec7b4a6..bc07d22e83 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -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.company = args.company or "_Test Company" 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.get_items_and_operations_from_bom() wo_order.sales_order = args.sales_order or None From ffbb2c831152686b9ec0b230b3c72b94edce0c6a Mon Sep 17 00:00:00 2001 From: marination Date: Tue, 1 Mar 2022 12:57:09 +0530 Subject: [PATCH 23/30] fix: Assert False for test that is anticipating an empty table and remove second arg to assertTrue --- .../doctype/production_plan/test_production_plan.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index ca8cc7a47e..59cc17a5ee 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -113,7 +113,7 @@ class TestProductionPlan(FrappeTestCase): item_code='Test Production Item 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) sr1.cancel() @@ -154,7 +154,7 @@ class TestProductionPlan(FrappeTestCase): use_multi_level_bom=0, ignore_existing_ordered_qty=0 ) - self.assertTrue(len(pln.mr_items)) + self.assertFalse(len(pln.mr_items)) sr1.cancel() sr2.cancel() From d22a1d440c96d5a476ce466074a264362a4c814a Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 1 Mar 2022 13:06:40 +0530 Subject: [PATCH 24/30] fix: track changes on warehouse --- erpnext/stock/doctype/warehouse/warehouse.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/warehouse/warehouse.json b/erpnext/stock/doctype/warehouse/warehouse.json index 05076b51a3..c695d541bf 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.json +++ b/erpnext/stock/doctype/warehouse/warehouse.json @@ -244,7 +244,7 @@ "idx": 1, "is_tree": 1, "links": [], - "modified": "2021-12-03 04:40:06.414630", + "modified": "2022-03-01 02:37:48.034944", "modified_by": "Administrator", "module": "Stock", "name": "Warehouse", @@ -301,5 +301,7 @@ "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", - "title_field": "warehouse_name" + "states": [], + "title_field": "warehouse_name", + "track_changes": 1 } \ No newline at end of file From ad2c64f3ff3cafa0abcee35639c9e5d4952bccdf Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Tue, 1 Mar 2022 13:32:34 +0530 Subject: [PATCH 25/30] fix: debit credit difference case with rounding adjustment --- .../sales_invoice/test_sales_invoice.py | 50 +++++++++++++++++++ erpnext/accounts/general_ledger.py | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 941061f2a2..83caab43b4 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1595,6 +1595,56 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(expected_values[gle.account][1], gle.debit) 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): from erpnext.accounts.doctype.shipping_rule.test_shipping_rule import create_shipping_rule diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index d24d56b4bb..0cd5e86a8c 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -274,7 +274,7 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision): debit_credit_diff += flt(d.credit) 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) return From 47fe87a72f40d1651951cecc97e9ae2ae0115fa4 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Tue, 1 Mar 2022 14:56:24 +0530 Subject: [PATCH 26/30] fix(test): flaky test_point_of_sale --- erpnext/tests/test_point_of_sale.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/tests/test_point_of_sale.py b/erpnext/tests/test_point_of_sale.py index 3299c8885f..38f2c16d93 100644 --- a/erpnext/tests/test_point_of_sale.py +++ b/erpnext/tests/test_point_of_sale.py @@ -25,7 +25,7 @@ class TestPointOfSale(unittest.TestCase): 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}) make_stock_entry( item_code="Test Search Stock Item", From 1d1d586d4dd356cf84edaed8a51f934194219d11 Mon Sep 17 00:00:00 2001 From: marination Date: Tue, 1 Mar 2022 15:42:34 +0530 Subject: [PATCH 27/30] test: Included sub assembly non-merging in test case --- .../doctype/production_plan/test_production_plan.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 59cc17a5ee..eeab788d5c 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -301,6 +301,11 @@ class TestProductionPlan(FrappeTestCase): 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): " 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) From 65bb72703029a38fedc02f2ad8f03ebfadf0b223 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 1 Mar 2022 17:25:42 +0530 Subject: [PATCH 28/30] fix: dont validate empty category --- .../sales_taxes_and_charges_template.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py index 1d30934df9..8043a1b66f 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py +++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py @@ -55,5 +55,8 @@ def validate_disabled(doc): frappe.throw(_("Disabled template must not be default template")) 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]}): 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))) From 57f92df108ae6c33567a95be22a43015fe3178e5 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 1 Mar 2022 20:50:36 +0530 Subject: [PATCH 29/30] fix: flake8 issues --- erpnext/hr/doctype/expense_claim/expense_claim.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index 5146a5be90..fe04efbbab 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -345,10 +345,10 @@ def get_advances(employee, advance_id=None): query = ( frappe.qb.from_(advance) - .select( - advance.name, advance.posting_date, advance.paid_amount, - advance.claimed_amount, advance.advance_account - ) + .select( + advance.name, advance.posting_date, advance.paid_amount, + advance.claimed_amount, advance.advance_account + ) ) if not advance_id: From 9988ec697f056b476ead3be1a371a82c6337be8e Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 1 Mar 2022 21:40:39 +0530 Subject: [PATCH 30/30] test: test advance filters in expense claim and cancelled status --- .../employee_advance/employee_advance.py | 1 + .../employee_advance/test_employee_advance.py | 38 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py index f63bb86129..79d389d440 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/employee_advance.py @@ -27,6 +27,7 @@ class EmployeeAdvance(Document): def on_cancel(self): self.ignore_linked_doctypes = ('GL Entry') + self.set_status(update=True) def set_status(self, update=False): precision = self.precision("paid_amount") diff --git a/erpnext/hr/doctype/employee_advance/test_employee_advance.py b/erpnext/hr/doctype/employee_advance/test_employee_advance.py index 5f3a66a04f..e3c1487ca2 100644 --- a/erpnext/hr/doctype/employee_advance/test_employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/test_employee_advance.py @@ -24,6 +24,9 @@ from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_ class TestEmployeeAdvance(unittest.TestCase): + def setUp(self): + frappe.db.delete("Employee Advance") + def test_paid_amount_and_status(self): employee_name = make_employee("_T@employe.advance") advance = make_employee_advance(employee_name) @@ -58,8 +61,12 @@ class TestEmployeeAdvance(unittest.TestCase): self.assertEqual(advance.paid_amount, 0) self.assertEqual(advance.status, "Unpaid") - def test_claimed_and_returned_status(self): - # Claimed Status check, full amount claimed + 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) @@ -75,13 +82,26 @@ class TestEmployeeAdvance(unittest.TestCase): 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") - # Partly Claimed and Returned status check + 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) @@ -116,12 +136,22 @@ class TestEmployeeAdvance(unittest.TestCase): self.assertEqual(advance.return_amount, 500) self.assertEqual(advance.status, "Partly Claimed and Returned") - # Cancel return entry; status should change to Paid + # 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): employee_name = make_employee("_T@employe.advance") advance = make_employee_advance(employee_name, {"repay_unclaimed_amount_from_salary": 1})