Merge branch 'develop' into taxjar-nexus-display-condition

This commit is contained in:
Saqib 2021-12-02 11:35:26 +05:30 committed by GitHub
commit 92860f46ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 187 additions and 78 deletions

View File

@ -5,10 +5,10 @@
import unittest import unittest
import frappe import frappe
from frappe.utils import now_datetime
from erpnext.accounts.doctype.fiscal_year.fiscal_year import FiscalYearIncorrectDate from erpnext.accounts.doctype.fiscal_year.fiscal_year import FiscalYearIncorrectDate
test_records = frappe.get_test_records('Fiscal Year')
test_ignore = ["Company"] test_ignore = ["Company"]
class TestFiscalYear(unittest.TestCase): class TestFiscalYear(unittest.TestCase):
@ -25,3 +25,29 @@ class TestFiscalYear(unittest.TestCase):
}) })
self.assertRaises(FiscalYearIncorrectDate, fy.insert) 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()

View File

@ -1,69 +0,0 @@
[
{
"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"
},
{
"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"
}
]

View File

@ -80,20 +80,20 @@ frappe.ui.form.on('Asset', {
if (frm.doc.docstatus==1) { if (frm.doc.docstatus==1) {
if (in_list(["Submitted", "Partially Depreciated", "Fully Depreciated"], frm.doc.status)) { if (in_list(["Submitted", "Partially Depreciated", "Fully Depreciated"], frm.doc.status)) {
frm.add_custom_button("Transfer Asset", function() { frm.add_custom_button(__("Transfer Asset"), function() {
erpnext.asset.transfer_asset(frm); erpnext.asset.transfer_asset(frm);
}, __("Manage")); }, __("Manage"));
frm.add_custom_button("Scrap Asset", function() { frm.add_custom_button(__("Scrap Asset"), function() {
erpnext.asset.scrap_asset(frm); erpnext.asset.scrap_asset(frm);
}, __("Manage")); }, __("Manage"));
frm.add_custom_button("Sell Asset", function() { frm.add_custom_button(__("Sell Asset"), function() {
frm.trigger("make_sales_invoice"); frm.trigger("make_sales_invoice");
}, __("Manage")); }, __("Manage"));
} else if (frm.doc.status=='Scrapped') { } else if (frm.doc.status=='Scrapped') {
frm.add_custom_button("Restore Asset", function() { frm.add_custom_button(__("Restore Asset"), function() {
erpnext.asset.restore_asset(frm); erpnext.asset.restore_asset(frm);
}, __("Manage")); }, __("Manage"));
} }
@ -121,7 +121,7 @@ frappe.ui.form.on('Asset', {
} }
if (frm.doc.purchase_receipt || !frm.doc.is_existing_asset) { if (frm.doc.purchase_receipt || !frm.doc.is_existing_asset) {
frm.add_custom_button("View General Ledger", function() { frm.add_custom_button(__("View General Ledger"), function() {
frappe.route_options = { frappe.route_options = {
"voucher_no": frm.doc.name, "voucher_no": frm.doc.name,
"from_date": frm.doc.available_for_use_date, "from_date": frm.doc.available_for_use_date,

View File

@ -21,9 +21,10 @@ 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.stock_entry import test_stock_entry
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.utils import get_bin from erpnext.stock.utils import get_bin
from erpnext.tests.utils import ERPNextTestCase, timeout
class TestWorkOrder(unittest.TestCase): class TestWorkOrder(ERPNextTestCase):
def setUp(self): def setUp(self):
self.warehouse = '_Test Warehouse 2 - _TC' self.warehouse = '_Test Warehouse 2 - _TC'
self.item = '_Test Item' self.item = '_Test Item'
@ -376,6 +377,7 @@ class TestWorkOrder(unittest.TestCase):
self.assertEqual(len(ste.additional_costs), 1) self.assertEqual(len(ste.additional_costs), 1)
self.assertEqual(ste.total_additional_costs, 1000) self.assertEqual(ste.total_additional_costs, 1000)
@timeout(seconds=60)
def test_job_card(self): def test_job_card(self):
stock_entries = [] stock_entries = []
bom = frappe.get_doc('BOM', { bom = frappe.get_doc('BOM', {
@ -769,6 +771,7 @@ class TestWorkOrder(unittest.TestCase):
total_pl_qty total_pl_qty
) )
@timeout(seconds=60)
def test_job_card_scrap_item(self): def test_job_card_scrap_item(self):
items = ['Test FG Item for Scrap Item Test', 'Test RM Item 1 for Scrap Item Test', items = ['Test FG Item for Scrap Item Test', 'Test RM Item 1 for Scrap Item Test',
'Test RM Item 2 for Scrap Item Test'] 'Test RM Item 2 for Scrap Item Test']

View File

@ -302,6 +302,109 @@ class TestQuotation(unittest.TestCase):
enable_calculate_bundle_price(enable=0) enable_calculate_bundle_price(enable=0)
def test_product_bundle_price_calculation_for_multiple_product_bundles_when_calculate_bundle_price_is_checked(self):
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
from erpnext.stock.doctype.item.test_item import make_item
make_item("_Test Product Bundle 1", {"is_stock_item": 0})
make_item("_Test Product Bundle 2", {"is_stock_item": 0})
make_item("_Test Bundle Item 1", {"is_stock_item": 1})
make_item("_Test Bundle Item 2", {"is_stock_item": 1})
make_item("_Test Bundle Item 3", {"is_stock_item": 1})
make_product_bundle("_Test Product Bundle 1",
["_Test Bundle Item 1", "_Test Bundle Item 2"])
make_product_bundle("_Test Product Bundle 2",
["_Test Bundle Item 2", "_Test Bundle Item 3"])
enable_calculate_bundle_price()
item_list = [
{
"item_code": "_Test Product Bundle 1",
"warehouse": "",
"qty": 1,
"rate": 400,
"delivered_by_supplier": 1,
"supplier": '_Test Supplier'
},
{
"item_code": "_Test Product Bundle 2",
"warehouse": "",
"qty": 1,
"rate": 400,
"delivered_by_supplier": 1,
"supplier": '_Test Supplier'
}
]
quotation = make_quotation(item_list=item_list, do_not_submit=1)
quotation.packed_items[0].rate = 100
quotation.packed_items[1].rate = 200
quotation.packed_items[2].rate = 200
quotation.packed_items[3].rate = 300
quotation.save()
expected_values = [300, 500]
for item in quotation.items:
self.assertEqual(item.amount, expected_values[item.idx-1])
enable_calculate_bundle_price(enable=0)
def test_packed_items_indices_are_reset_when_product_bundle_is_deleted_from_items_table(self):
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
from erpnext.stock.doctype.item.test_item import make_item
make_item("_Test Product Bundle 1", {"is_stock_item": 0})
make_item("_Test Product Bundle 2", {"is_stock_item": 0})
make_item("_Test Product Bundle 3", {"is_stock_item": 0})
make_item("_Test Bundle Item 1", {"is_stock_item": 1})
make_item("_Test Bundle Item 2", {"is_stock_item": 1})
make_item("_Test Bundle Item 3", {"is_stock_item": 1})
make_product_bundle("_Test Product Bundle 1",
["_Test Bundle Item 1", "_Test Bundle Item 2"])
make_product_bundle("_Test Product Bundle 2",
["_Test Bundle Item 2", "_Test Bundle Item 3"])
make_product_bundle("_Test Product Bundle 3",
["_Test Bundle Item 3", "_Test Bundle Item 1"])
item_list = [
{
"item_code": "_Test Product Bundle 1",
"warehouse": "",
"qty": 1,
"rate": 400,
"delivered_by_supplier": 1,
"supplier": '_Test Supplier'
},
{
"item_code": "_Test Product Bundle 2",
"warehouse": "",
"qty": 1,
"rate": 400,
"delivered_by_supplier": 1,
"supplier": '_Test Supplier'
},
{
"item_code": "_Test Product Bundle 3",
"warehouse": "",
"qty": 1,
"rate": 400,
"delivered_by_supplier": 1,
"supplier": '_Test Supplier'
}
]
quotation = make_quotation(item_list=item_list, do_not_submit=1)
del quotation.items[1]
quotation.save()
for id, item in enumerate(quotation.packed_items):
expected_index = id + 1
self.assertEqual(item.idx, expected_index)
test_records = frappe.get_test_records('Quotation') test_records = frappe.get_test_records('Quotation')
def enable_calculate_bundle_price(enable=1): def enable_calculate_bundle_price(enable=1):

View File

@ -925,6 +925,7 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None):
"supplier", "supplier",
"pricing_rules" "pricing_rules"
], ],
"condition": lambda doc: doc.parent_item in items_to_map
} }
}, target_doc, set_missing_values) }, target_doc, set_missing_values)

View File

@ -108,9 +108,32 @@ def cleanup_packing_list(doc, parent_items):
packed_items = doc.get("packed_items") packed_items = doc.get("packed_items")
doc.set("packed_items", []) doc.set("packed_items", [])
for d in packed_items: for d in packed_items:
if d not in delete_list: if d not in delete_list:
doc.append("packed_items", d) add_item_to_packing_list(doc, d)
def add_item_to_packing_list(doc, packed_item):
doc.append("packed_items", {
'parent_item': packed_item.parent_item,
'item_code': packed_item.item_code,
'item_name': packed_item.item_name,
'uom': packed_item.uom,
'qty': packed_item.qty,
'rate': packed_item.rate,
'conversion_factor': packed_item.conversion_factor,
'description': packed_item.description,
'warehouse': packed_item.warehouse,
'batch_no': packed_item.batch_no,
'actual_batch_qty': packed_item.actual_batch_qty,
'serial_no': packed_item.serial_no,
'target_warehouse': packed_item.target_warehouse,
'actual_qty': packed_item.actual_qty,
'projected_qty': packed_item.projected_qty,
'incoming_rate': packed_item.incoming_rate,
'prevdoc_doctype': packed_item.prevdoc_doctype,
'parent_detail_docname': packed_item.parent_detail_docname
})
def update_product_bundle_price(doc, parent_items): def update_product_bundle_price(doc, parent_items):
"""Updates the prices of Product Bundles based on the rates of the Items in the bundle.""" """Updates the prices of Product Bundles based on the rates of the Items in the bundle."""
@ -128,7 +151,8 @@ def update_product_bundle_price(doc, parent_items):
else: else:
update_parent_item_price(doc, parent_items[parent_items_index][0], bundle_price) update_parent_item_price(doc, parent_items[parent_items_index][0], bundle_price)
bundle_price = 0 bundle_item_rate = bundle_item.rate if bundle_item.rate else 0
bundle_price = bundle_item.qty * bundle_item_rate
parent_items_index += 1 parent_items_index += 1
# for the last product bundle # for the last product bundle

View File

@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
import copy import copy
import signal
import unittest import unittest
from contextlib import contextmanager from contextlib import contextmanager
from typing import Any, Dict, NewType, Optional from typing import Any, Dict, NewType, Optional
@ -135,3 +136,23 @@ def execute_script_report(
report_execute_fn(filter_with_optional_param) report_execute_fn(filter_with_optional_param)
return report_data return report_data
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