Merge branch 'develop' into taxjar-nexus-display-condition
This commit is contained in:
commit
92860f46ac
@ -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()
|
||||||
|
|||||||
@ -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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@ -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,
|
||||||
|
|||||||
@ -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']
|
||||||
|
|||||||
@ -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):
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user