From 656686f2b19405d2cd12b3516310a77bfaa35a28 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 19 Nov 2021 11:03:13 +0530 Subject: [PATCH 01/11] fix(India): GST category not getting auto updated (cherry picked from commit f8a26a9fac2c91b036f1dd4033f3fb4797285043) --- erpnext/regional/india/utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py index 6be2832ec28..9afb0a57a32 100644 --- a/erpnext/regional/india/utils.py +++ b/erpnext/regional/india/utils.py @@ -67,11 +67,11 @@ def validate_tax_category(doc, method): frappe.throw(_("Intra State tax category for GST State {0} already exists").format(doc.gst_state)) def update_gst_category(doc, method): - if hasattr(doc, 'gst_category'): - for link in doc.links: - if link.link_doctype in ['Customer', 'Supplier']: - if doc.get('gstin'): - frappe.db.set_value(link.link_doctype, {'name': link.link_name, 'gst_category': 'Unregistered'}, 'gst_category', 'Registered Regular') + for link in doc.links: + if link.link_doctype in ['Customer', 'Supplier']: + meta = frappe.get_meta(link.link_doctype) + if doc.get('gstin') and meta.has_field('gst_category'): + frappe.db.set_value(link.link_doctype, {'name': link.link_name, 'gst_category': 'Unregistered'}, 'gst_category', 'Registered Regular') def set_gst_state_and_state_number(doc): if not doc.gst_state: From 9b83e3856ab6a9c91486f58035a56d96eeae65dc Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 19 Nov 2021 11:58:44 +0530 Subject: [PATCH 02/11] fix: Add test for gst category check (cherry picked from commit cdbc991e3f97c7ed3e120b2e4720298402d1de77) # Conflicts: # erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py --- .../gstr_3b_report/test_gstr_3b_report.py | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py index 15f7506d682..83bb02746cc 100644 --- a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py +++ b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py @@ -67,6 +67,84 @@ class TestGSTR3BReport(unittest.TestCase): self.assertEqual(output["itc_elg"]["itc_avl"][4]["samt"], 22.50) self.assertEqual(output["itc_elg"]["itc_avl"][4]["camt"], 22.50) +<<<<<<< HEAD +======= + def test_gst_rounding(self): + gst_settings = frappe.get_doc('GST Settings') + gst_settings.round_off_gst_values = 1 + gst_settings.save() + + current_country = frappe.flags.country + frappe.flags.country = 'India' + + si = create_sales_invoice(company="_Test Company GST", + customer = '_Test GST Customer', + currency = 'INR', + warehouse = 'Finished Goods - _GST', + debit_to = 'Debtors - _GST', + income_account = 'Sales - _GST', + expense_account = 'Cost of Goods Sold - _GST', + cost_center = 'Main - _GST', + rate=216, + do_not_save=1 + ) + + si.append("taxes", { + "charge_type": "On Net Total", + "account_head": "Output Tax IGST - _GST", + "cost_center": "Main - _GST", + "description": "IGST @ 18.0", + "rate": 18 + }) + + si.save() + # Check for 39 instead of 38.88 + self.assertEqual(si.taxes[0].base_tax_amount_after_discount_amount, 39) + + frappe.flags.country = current_country + gst_settings.round_off_gst_values = 1 + gst_settings.save() + + def test_gst_category_auto_update(self): + if not frappe.db.exists("Customer", "_Test GST Customer With GSTIN"): + customer = frappe.get_doc({ + "customer_group": "_Test Customer Group", + "customer_name": "_Test GST Customer With GSTIN", + "customer_type": "Individual", + "doctype": "Customer", + "territory": "_Test Territory" + }).insert() + + self.assertEqual(customer.gst_category, 'Unregistered') + + if not frappe.db.exists('Address', '_Test GST Category-1-Billing'): + address = frappe.get_doc({ + "address_line1": "_Test Address Line 1", + "address_title": "_Test GST Category-1", + "address_type": "Billing", + "city": "_Test City", + "state": "Test State", + "country": "India", + "doctype": "Address", + "is_primary_address": 1, + "phone": "+91 0000000000", + "gstin": "29AZWPS7135H1ZG", + "gst_state": "Karnataka", + "gst_state_number": "29" + }).insert() + + address.append("links", { + "link_doctype": "Customer", + "link_name": "_Test GST Customer With GSTIN" + }) + + address.save() + + customer.load_from_db() + self.assertEqual(customer.gst_category, 'Registered Regular') + + +>>>>>>> cdbc991e3f (fix: Add test for gst category check) def make_sales_invoice(): si = create_sales_invoice(company="_Test Company GST", customer = '_Test GST Customer', From d09ed0a578a02e6808274f323b0b24786b0bda67 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Fri, 19 Nov 2021 13:11:07 +0530 Subject: [PATCH 03/11] fix: Conflicts --- .../regional/doctype/gstr_3b_report/test_gstr_3b_report.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py index 83bb02746cc..8ebefba3642 100644 --- a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py +++ b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py @@ -67,8 +67,6 @@ class TestGSTR3BReport(unittest.TestCase): self.assertEqual(output["itc_elg"]["itc_avl"][4]["samt"], 22.50) self.assertEqual(output["itc_elg"]["itc_avl"][4]["camt"], 22.50) -<<<<<<< HEAD -======= def test_gst_rounding(self): gst_settings = frappe.get_doc('GST Settings') gst_settings.round_off_gst_values = 1 @@ -143,8 +141,6 @@ class TestGSTR3BReport(unittest.TestCase): customer.load_from_db() self.assertEqual(customer.gst_category, 'Registered Regular') - ->>>>>>> cdbc991e3f (fix: Add test for gst category check) def make_sales_invoice(): si = create_sales_invoice(company="_Test Company GST", customer = '_Test GST Customer', From 67f17c7a0c30103f3c235dfe088937313e1b68cf Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 29 Nov 2021 18:05:36 +0530 Subject: [PATCH 04/11] fix: Remove tests --- .../gstr_3b_report/test_gstr_3b_report.py | 74 ------------------- 1 file changed, 74 deletions(-) diff --git a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py index 8ebefba3642..15f7506d682 100644 --- a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py +++ b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py @@ -67,80 +67,6 @@ class TestGSTR3BReport(unittest.TestCase): self.assertEqual(output["itc_elg"]["itc_avl"][4]["samt"], 22.50) self.assertEqual(output["itc_elg"]["itc_avl"][4]["camt"], 22.50) - def test_gst_rounding(self): - gst_settings = frappe.get_doc('GST Settings') - gst_settings.round_off_gst_values = 1 - gst_settings.save() - - current_country = frappe.flags.country - frappe.flags.country = 'India' - - si = create_sales_invoice(company="_Test Company GST", - customer = '_Test GST Customer', - currency = 'INR', - warehouse = 'Finished Goods - _GST', - debit_to = 'Debtors - _GST', - income_account = 'Sales - _GST', - expense_account = 'Cost of Goods Sold - _GST', - cost_center = 'Main - _GST', - rate=216, - do_not_save=1 - ) - - si.append("taxes", { - "charge_type": "On Net Total", - "account_head": "Output Tax IGST - _GST", - "cost_center": "Main - _GST", - "description": "IGST @ 18.0", - "rate": 18 - }) - - si.save() - # Check for 39 instead of 38.88 - self.assertEqual(si.taxes[0].base_tax_amount_after_discount_amount, 39) - - frappe.flags.country = current_country - gst_settings.round_off_gst_values = 1 - gst_settings.save() - - def test_gst_category_auto_update(self): - if not frappe.db.exists("Customer", "_Test GST Customer With GSTIN"): - customer = frappe.get_doc({ - "customer_group": "_Test Customer Group", - "customer_name": "_Test GST Customer With GSTIN", - "customer_type": "Individual", - "doctype": "Customer", - "territory": "_Test Territory" - }).insert() - - self.assertEqual(customer.gst_category, 'Unregistered') - - if not frappe.db.exists('Address', '_Test GST Category-1-Billing'): - address = frappe.get_doc({ - "address_line1": "_Test Address Line 1", - "address_title": "_Test GST Category-1", - "address_type": "Billing", - "city": "_Test City", - "state": "Test State", - "country": "India", - "doctype": "Address", - "is_primary_address": 1, - "phone": "+91 0000000000", - "gstin": "29AZWPS7135H1ZG", - "gst_state": "Karnataka", - "gst_state_number": "29" - }).insert() - - address.append("links", { - "link_doctype": "Customer", - "link_name": "_Test GST Customer With GSTIN" - }) - - address.save() - - customer.load_from_db() - self.assertEqual(customer.gst_category, 'Registered Regular') - def make_sales_invoice(): si = create_sales_invoice(company="_Test Company GST", customer = '_Test GST Customer', From abb4d99ca8bab882da77749b8b7b075cf07148e9 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 2 Dec 2021 15:01:06 +0530 Subject: [PATCH 05/11] fix: actual tax conversion in case of multicurrency invoices (#28687) --- erpnext/public/js/controllers/transaction.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index ee61e9787af..47097042875 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -940,7 +940,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ $.each(this.frm.doc.taxes || [], function(i, d) { if(d.charge_type == "Actual") { frappe.model.set_value(d.doctype, d.name, "tax_amount", - flt(d.tax_amount) / flt(exchange_rate)); + flt(d.base_tax_amount) / flt(exchange_rate)); } }); }, From 7d1953bb3b9b9c017fdb9319f213b82617eb583c Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 13 Dec 2021 20:13:53 +0530 Subject: [PATCH 06/11] fix: validate if asset account is set against company (cherry picked from commit c3e0de28b192263537b4e7df766210904c788c03) --- .../doctype/purchase_invoice/purchase_invoice.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 4db2460dc11..c9f1c8dcd8c 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -247,8 +247,15 @@ class PurchaseInvoice(BuyingController): else: item.expense_account = stock_not_billed_account elif item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category): - item.expense_account = get_asset_category_account('fixed_asset_account', item=item.item_code, + asset_category_account = get_asset_category_account('fixed_asset_account', item=item.item_code, company = self.company) + if not asset_category_account: + form_link = get_link_to_form('Asset Category', asset_category) + throw( + _("Please set Fixed Asset Account in {} against {}.").format(form_link, self.company), + title=_("Missing Account") + ) + item.expense_account = asset_category_account elif item.is_fixed_asset and item.pr_detail: item.expense_account = asset_received_but_not_billed elif not item.expense_account and for_validate: From 39125a78e0e6e86282d32f1cb2801c12c86f0245 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 14 Dec 2021 17:45:08 +0530 Subject: [PATCH 07/11] fix!: dont allow renaming warehouse primary key (backport #28712) * fix!: dont allow renaming warehouse primary key (cherry picked from commit 72dbc3d6b8e10fc6ee9f7cd8132da90fe9cdb3bb) * fix: remove autocommit from item rename (cherry picked from commit 5caf411be3ffcb5638cf2d3a3cedca233ec9f317) Co-authored-by: Ankush Menat --- erpnext/stock/doctype/item/item.py | 2 - .../stock/doctype/warehouse/test_warehouse.py | 60 +------------------ .../stock/doctype/warehouse/warehouse.json | 3 +- erpnext/stock/doctype/warehouse/warehouse.py | 54 +---------------- 4 files changed, 4 insertions(+), 115 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 917854a3ee0..0ee30d86e9a 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -690,7 +690,6 @@ class Item(WebsiteGenerator): def recalculate_bin_qty(self, new_name): from erpnext.stock.stock_balance import repost_stock - frappe.db.auto_commit_on_many_writes = 1 existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock") frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) @@ -704,7 +703,6 @@ class Item(WebsiteGenerator): repost_stock(new_name, warehouse) frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock) - frappe.db.auto_commit_on_many_writes = 0 def copy_specification_from_item_group(self): self.set("website_specifications", []) diff --git a/erpnext/stock/doctype/warehouse/test_warehouse.py b/erpnext/stock/doctype/warehouse/test_warehouse.py index 121222d7bc3..4ba87ac5fb8 100644 --- a/erpnext/stock/doctype/warehouse/test_warehouse.py +++ b/erpnext/stock/doctype/warehouse/test_warehouse.py @@ -32,64 +32,6 @@ class TestWarehouse(unittest.TestCase): self.assertEqual(p_warehouse.name, child_warehouse.parent_warehouse) self.assertEqual(child_warehouse.is_group, 0) - def test_warehouse_renaming(self): - set_perpetual_inventory(1) - create_warehouse("Test Warehouse for Renaming 1") - account = get_inventory_account("_Test Company", "Test Warehouse for Renaming 1 - _TC") - self.assertTrue(frappe.db.get_value("Warehouse", filters={"account": account})) - - # Rename with abbr - if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 2 - _TC"): - frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC") - rename_doc("Warehouse", "Test Warehouse for Renaming 1 - _TC", "Test Warehouse for Renaming 2 - _TC") - - self.assertTrue(frappe.db.get_value("Warehouse", - filters={"account": "Test Warehouse for Renaming 1 - _TC"})) - - # Rename without abbr - if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 3 - _TC"): - frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 3 - _TC") - - rename_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC", "Test Warehouse for Renaming 3") - - self.assertTrue(frappe.db.get_value("Warehouse", - filters={"account": "Test Warehouse for Renaming 1 - _TC"})) - - # Another rename with multiple dashes - if frappe.db.exists("Warehouse", "Test - Warehouse - Company - _TC"): - frappe.delete_doc("Warehouse", "Test - Warehouse - Company - _TC") - rename_doc("Warehouse", "Test Warehouse for Renaming 3 - _TC", "Test - Warehouse - Company") - - def test_warehouse_merging(self): - set_perpetual_inventory(1) - - create_warehouse("Test Warehouse for Merging 1") - create_warehouse("Test Warehouse for Merging 2") - - make_stock_entry(item_code="_Test Item", target="Test Warehouse for Merging 1 - _TC", - qty=1, rate=100) - make_stock_entry(item_code="_Test Item", target="Test Warehouse for Merging 2 - _TC", - qty=1, rate=100) - - existing_bin_qty = ( - cint(frappe.db.get_value("Bin", - {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 1 - _TC"}, "actual_qty")) - + cint(frappe.db.get_value("Bin", - {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 2 - _TC"}, "actual_qty")) - ) - - rename_doc("Warehouse", "Test Warehouse for Merging 1 - _TC", - "Test Warehouse for Merging 2 - _TC", merge=True) - - self.assertFalse(frappe.db.exists("Warehouse", "Test Warehouse for Merging 1 - _TC")) - - bin_qty = frappe.db.get_value("Bin", - {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 2 - _TC"}, "actual_qty") - - self.assertEqual(bin_qty, existing_bin_qty) - - self.assertTrue(frappe.db.get_value("Warehouse", - filters={"account": "Test Warehouse for Merging 2 - _TC"})) def create_warehouse(warehouse_name, properties=None, company=None): if not company: @@ -145,4 +87,4 @@ def get_group_stock_account(company, company_abbr=None): if not company_abbr: company_abbr = frappe.get_cached_value("Company", company, 'abbr') group_stock_account = "Current Assets - " + company_abbr - return group_stock_account \ No newline at end of file + return group_stock_account diff --git a/erpnext/stock/doctype/warehouse/warehouse.json b/erpnext/stock/doctype/warehouse/warehouse.json index 6e40bc53d07..f66bf334cfb 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.json +++ b/erpnext/stock/doctype/warehouse/warehouse.json @@ -1,6 +1,5 @@ { "allow_import": 1, - "allow_rename": 1, "creation": "2013-03-07 18:50:32", "description": "A logical Warehouse against which stock entries are made.", "doctype": "DocType", @@ -235,7 +234,7 @@ "idx": 1, "is_tree": 1, "links": [], - "modified": "2020-08-03 18:41:52.442502", + "modified": "2021-12-03 04:40:06.414630", "modified_by": "Administrator", "module": "Stock", "name": "Warehouse", diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py index 5a55635d334..f953083d62e 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.py +++ b/erpnext/stock/doctype/warehouse/warehouse.py @@ -7,6 +7,7 @@ from frappe.utils import cint, flt from frappe import throw, _ from collections import defaultdict from frappe.utils.nestedset import NestedSet + from erpnext.stock import get_warehouse_account from frappe.contacts.address_and_contact import load_address_and_contact @@ -63,57 +64,6 @@ class Warehouse(NestedSet): return frappe.db.sql("""select name from `tabWarehouse` where parent_warehouse = %s limit 1""", self.name) - def before_rename(self, old_name, new_name, merge=False): - super(Warehouse, self).before_rename(old_name, new_name, merge) - - # Add company abbr if not provided - new_warehouse = erpnext.encode_company_abbr(new_name, self.company) - - if merge: - if not frappe.db.exists("Warehouse", new_warehouse): - frappe.throw(_("Warehouse {0} does not exist").format(new_warehouse)) - - if self.company != frappe.db.get_value("Warehouse", new_warehouse, "company"): - frappe.throw(_("Both Warehouse must belong to same Company")) - - return new_warehouse - - def after_rename(self, old_name, new_name, merge=False): - super(Warehouse, self).after_rename(old_name, new_name, merge) - - new_warehouse_name = self.get_new_warehouse_name_without_abbr(new_name) - self.db_set("warehouse_name", new_warehouse_name) - - if merge: - self.recalculate_bin_qty(new_name) - - def get_new_warehouse_name_without_abbr(self, name): - company_abbr = frappe.get_cached_value('Company', self.company, "abbr") - parts = name.rsplit(" - ", 1) - - if parts[-1].lower() == company_abbr.lower(): - name = parts[0] - - return name - - def recalculate_bin_qty(self, new_name): - from erpnext.stock.stock_balance import repost_stock - frappe.db.auto_commit_on_many_writes = 1 - existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock") - frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) - - repost_stock_for_items = frappe.db.sql_list("""select distinct item_code - from tabBin where warehouse=%s""", new_name) - - # Delete all existing bins to avoid duplicate bins for the same item and warehouse - frappe.db.sql("delete from `tabBin` where warehouse=%s", new_name) - - for item_code in repost_stock_for_items: - repost_stock(item_code, new_name) - - frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock) - frappe.db.auto_commit_on_many_writes = 0 - def convert_to_group_or_ledger(self): if self.is_group: self.convert_to_ledger() @@ -232,4 +182,4 @@ def get_warehouses_based_on_account(account, company=None): frappe.throw(_("Warehouse not found against the account {0}") .format(account)) - return warehouses \ No newline at end of file + return warehouses From e9dbb46a06dd8732b6960b69e7b4bda6ab9d61cf Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 14 Dec 2021 20:04:37 +0530 Subject: [PATCH 08/11] fix: incorrect amount based on payment days in timesheet salary slip (#28884) --- erpnext/hr/doctype/salary_slip/salary_slip.py | 20 +++++----- .../doctype/salary_slip/test_salary_slip.py | 37 ++++++++++++++++++- .../doctype/timesheet/test_timesheet.py | 7 ++-- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index 2213fa6fb57..bee28180187 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -303,11 +303,11 @@ class SalarySlip(TransactionBase): if self.salary_structure: self.calculate_component_amounts("deductions") - + self.set_loan_repayment() self.set_component_amounts_based_on_payment_days() self.set_net_pay() - + def set_net_pay(self): self.total_deduction = self.get_component_totals("deductions") self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment)) @@ -519,7 +519,7 @@ class SalarySlip(TransactionBase): # Total taxable earnings including additional and other incomes total_taxable_earnings = previous_taxable_earnings + current_structured_taxable_earnings + future_structured_taxable_earnings \ + current_additional_earnings + other_incomes + unclaimed_taxable_benefits - total_exemption_amount - + # Total taxable earnings without additional earnings with full tax total_taxable_earnings_without_full_tax_addl_components = total_taxable_earnings - current_additional_earnings_with_full_tax @@ -527,7 +527,7 @@ class SalarySlip(TransactionBase): total_structured_tax_amount = self.calculate_tax_by_tax_slab( total_taxable_earnings_without_full_tax_addl_components, tax_slab) current_structured_tax_amount = (total_structured_tax_amount - previous_total_paid_taxes) / remaining_sub_periods - + # Total taxable earnings with additional earnings with full tax full_tax_on_additional_earnings = 0.0 if current_additional_earnings_with_full_tax: @@ -563,7 +563,7 @@ class SalarySlip(TransactionBase): select sum(sd.amount) from `tabSalary Detail` sd join `tabSalary Slip` ss on sd.parent=ss.name - where + where sd.parentfield='earnings' and sd.is_tax_applicable=1 and is_flexible_benefit=0 @@ -676,9 +676,11 @@ class SalarySlip(TransactionBase): def get_amount_based_on_payment_days(self, row, joining_date, relieving_date): amount, additional_amount = row.amount, row.additional_amount + timesheet_component = frappe.db.get_value("Salary Structure", self.salary_structure, "salary_component") + if (self.salary_structure and - cint(row.depends_on_payment_days) and cint(self.total_working_days) and - (not self.salary_slip_based_on_timesheet or + cint(row.depends_on_payment_days) and cint(self.total_working_days) + and (row.salary_component != timesheet_component or getdate(self.start_date) < joining_date or (relieving_date and getdate(self.end_date) > relieving_date) )): @@ -687,7 +689,7 @@ class SalarySlip(TransactionBase): amount = flt((flt(row.default_amount) * flt(self.payment_days) / cint(self.total_working_days)), row.precision("amount")) + additional_amount - elif not self.payment_days and not self.salary_slip_based_on_timesheet and cint(row.depends_on_payment_days): + elif not self.payment_days and row.salary_component != timesheet_component and cint(row.depends_on_payment_days): amount, additional_amount = 0, 0 elif not row.amount: amount = flt(row.default_amount) + flt(row.additional_amount) @@ -782,7 +784,7 @@ class SalarySlip(TransactionBase): if flt(d.max_taxable_income) and flt(d.max_taxable_income) < annual_taxable_earning: continue - + tax_amount += tax_amount * flt(d.percent) / 100 return tax_amount diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py index 7572e00359a..7dce77b3bdc 100644 --- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py @@ -115,6 +115,41 @@ class TestSalarySlip(unittest.TestCase): frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active") + def test_payment_days_in_salary_slip_based_on_timesheet(self): + from erpnext.projects.doctype.timesheet.test_timesheet import ( + make_salary_structure_for_timesheet, + make_timesheet, + ) + from erpnext.projects.doctype.timesheet.timesheet import ( + make_salary_slip as make_salary_slip_for_timesheet, + ) + + # Holidays included in working days + frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0) + + emp = make_employee("test_employee_timesheet1@salary.com", company=erpnext.get_default_company()) + frappe.db.set_value("Employee", emp, {"relieving_date": None, "status": "Active"}) + + # salary structure based on timesheet + make_salary_structure_for_timesheet(emp) + timesheet = make_timesheet(emp, simulate=True) + salary_slip = make_salary_slip_for_timesheet(timesheet.name) + salary_slip.start_date = get_first_day(nowdate()) + salary_slip.end_date = get_last_day(nowdate()) + salary_slip.save() + salary_slip.submit() + + no_of_days = self.get_no_of_days() + days_in_month = no_of_days[0] + no_of_holidays = no_of_days[1] + + self.assertEqual(salary_slip.payment_days, days_in_month - no_of_holidays) + + # gross pay calculation based on attendance (payment days) + gross_pay = 78100 - ((78000 / (days_in_month - no_of_holidays)) * flt(salary_slip.leave_without_pay)) + + self.assertEqual(salary_slip.gross_pay, flt(gross_pay, 2)) + def test_employee_salary_slip_read_permission(self): make_employee("test_employee@salary.com") @@ -175,7 +210,7 @@ class TestSalarySlip(unittest.TestCase): # as per assigned salary structure 40500 in monthly salary so 236000*5/100/12 frappe.db.sql("""delete from `tabPayroll Period`""") frappe.db.sql("""delete from `tabSalary Component`""") - + payroll_period = create_payroll_period() create_tax_slab(payroll_period, allow_tax_exemption=True) diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py index 32f0428fcd8..2ecac86de83 100644 --- a/erpnext/projects/doctype/timesheet/test_timesheet.py +++ b/erpnext/projects/doctype/timesheet/test_timesheet.py @@ -20,10 +20,6 @@ class TestTimesheet(unittest.TestCase): for dt in ["Salary Slip", "Salary Structure", "Salary Structure Assignment", "Timesheet"]: frappe.db.sql("delete from `tab%s`" % dt) - if not frappe.db.exists("Salary Component", "Timesheet Component"): - frappe.get_doc({"doctype": "Salary Component", "salary_component": "Timesheet Component"}).insert() - - def test_timesheet_billing_amount(self): make_salary_structure_for_timesheet("_T-Employee-00001") timesheet = make_timesheet("_T-Employee-00001", simulate=True, billable=1) @@ -177,6 +173,9 @@ def make_salary_structure_for_timesheet(employee): salary_structure_name = "Timesheet Salary Structure Test" frequency = "Monthly" + if not frappe.db.exists("Salary Component", "Timesheet Component"): + frappe.get_doc({"doctype": "Salary Component", "salary_component": "Timesheet Component"}).insert() + salary_structure = make_salary_structure(salary_structure_name, frequency, dont_submit=True) salary_structure.salary_component = "Timesheet Component" salary_structure.salary_slip_based_on_timesheet = 1 From c9927efcae1282be89e9be64105fa1c9ef44b099 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 1 Dec 2021 17:31:17 +0530 Subject: [PATCH 09/11] test: dynamic fiscal year creation in tests (#28667) (cherry picked from commit fdffa037b5aa7fe368caa44c365e679401263c96) fix: resolve conflict fix --- .../doctype/fiscal_year/test_fiscal_year.py | 32 ++++++++- .../doctype/fiscal_year/test_records.json | 69 ------------------- 2 files changed, 30 insertions(+), 71 deletions(-) delete mode 100644 erpnext/accounts/doctype/fiscal_year/test_records.json diff --git a/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py b/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py index f7b77827668..1f38172ea8f 100644 --- a/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py +++ b/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py @@ -3,11 +3,13 @@ from __future__ import unicode_literals -import frappe, unittest +import unittest + +import frappe +from frappe.utils import now_datetime from erpnext.accounts.doctype.fiscal_year.fiscal_year import FiscalYearIncorrectDate -test_records = frappe.get_test_records('Fiscal Year') test_ignore = ["Company"] class TestFiscalYear(unittest.TestCase): @@ -23,3 +25,29 @@ class TestFiscalYear(unittest.TestCase): }) self.assertRaises(FiscalYearIncorrectDate, fy.insert) + + +def test_record_generator(): + test_records = [ + { + "doctype": "Fiscal Year", + "year": "_Test Short Fiscal Year 2011", + "is_short_year": 1, + "year_end_date": "2011-04-01", + "year_start_date": "2011-12-31" + } + ] + + start = 2012 + end = now_datetime().year + 5 + for year in range(start, end): + test_records.append({ + "doctype": "Fiscal Year", + "year": f"_Test Fiscal Year {year}", + "year_start_date": f"{year}-01-01", + "year_end_date": f"{year}-12-31" + }) + + return test_records + +test_records = test_record_generator() diff --git a/erpnext/accounts/doctype/fiscal_year/test_records.json b/erpnext/accounts/doctype/fiscal_year/test_records.json deleted file mode 100644 index 47be54f026f..00000000000 --- a/erpnext/accounts/doctype/fiscal_year/test_records.json +++ /dev/null @@ -1,69 +0,0 @@ -[ - { - "doctype": "Fiscal Year", - "year": "_Test Fiscal Year 2012", - "year_end_date": "2012-12-31", - "year_start_date": "2012-01-01" - }, - { - "doctype": "Fiscal Year", - "year": "_Test Fiscal Year 2013", - "year_end_date": "2013-12-31", - "year_start_date": "2013-01-01" - }, - { - "doctype": "Fiscal Year", - "year": "_Test Fiscal Year 2014", - "year_end_date": "2014-12-31", - "year_start_date": "2014-01-01" - }, - { - "doctype": "Fiscal Year", - "year": "_Test Fiscal Year 2015", - "year_end_date": "2015-12-31", - "year_start_date": "2015-01-01" - }, - { - "doctype": "Fiscal Year", - "year": "_Test Fiscal Year 2016", - "year_end_date": "2016-12-31", - "year_start_date": "2016-01-01" - }, - { - "doctype": "Fiscal Year", - "year": "_Test Fiscal Year 2017", - "year_end_date": "2017-12-31", - "year_start_date": "2017-01-01" - }, - { - "doctype": "Fiscal Year", - "year": "_Test Fiscal Year 2018", - "year_end_date": "2018-12-31", - "year_start_date": "2018-01-01" - }, - { - "doctype": "Fiscal Year", - "year": "_Test Fiscal Year 2019", - "year_end_date": "2019-12-31", - "year_start_date": "2019-01-01" - }, - { - "doctype": "Fiscal Year", - "year": "_Test Fiscal Year 2020", - "year_end_date": "2020-12-31", - "year_start_date": "2020-01-01" - }, - { - "doctype": "Fiscal Year", - "year": "_Test Fiscal Year 2021", - "year_end_date": "2021-12-31", - "year_start_date": "2021-01-01" - }, - { - "doctype": "Fiscal Year", - "year": "_Test Short Fiscal Year 2021", - "is_short_year": 1, - "year_end_date": "2021-12-31", - "year_start_date": "2021-04-01" - } -] From ce2aa767b2d05146d0e4347bfa103111759633a4 Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Thu, 23 Dec 2021 12:04:15 +0530 Subject: [PATCH 10/11] fix: Use depreciation cost center for creating credit entries in JEs (#28908) --- erpnext/assets/doctype/asset/depreciation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 8f0afb42b2c..251fe3fa493 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -59,7 +59,7 @@ def make_depreciation_entry(asset_name, date=None): "credit_in_account_currency": d.depreciation_amount, "reference_type": "Asset", "reference_name": asset.name, - "cost_center": "" + "cost_center": depreciation_cost_center } debit_entry = { From fbbf29e829f264adae07ffe45c2db99d121a224d Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 29 Dec 2021 00:21:00 +0530 Subject: [PATCH 11/11] fix: travis failing --- erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py b/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py index 1f38172ea8f..1dc4a9e4b98 100644 --- a/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py +++ b/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py @@ -43,9 +43,9 @@ def test_record_generator(): for year in range(start, end): test_records.append({ "doctype": "Fiscal Year", - "year": f"_Test Fiscal Year {year}", - "year_start_date": f"{year}-01-01", - "year_end_date": f"{year}-12-31" + "year": "_Test Fiscal Year {}".format(year), + "year_start_date": "{}-01-01".format(year), + "year_end_date": "{}-12-31".format(year) }) return test_records