mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-18 00:55:02 +00:00
Merge branch 'hotfix' into fix_bom_include_exploded_item
This commit is contained in:
25
.travis.yml
25
.travis.yml
@@ -3,6 +3,11 @@ dist: trusty
|
||||
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.6"
|
||||
|
||||
env:
|
||||
- TEST_TYPE="Server Side Test"
|
||||
- TEST_TYPE="Patch Test"
|
||||
|
||||
services:
|
||||
- mysql
|
||||
@@ -39,18 +44,8 @@ before_script:
|
||||
- bench start &
|
||||
- sleep 10
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: test
|
||||
script:
|
||||
- set -e
|
||||
- bench run-tests --app erpnext --coverage
|
||||
after_script:
|
||||
- coveralls -b apps/erpnext -d ../../sites/.coverage
|
||||
env: Server Side Test
|
||||
- # stage
|
||||
script:
|
||||
- wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
|
||||
- bench --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
|
||||
- bench migrate
|
||||
env: Patch Testing
|
||||
script:
|
||||
- bash $TRAVIS_BUILD_DIR/travis/run-tests.sh
|
||||
|
||||
after_script:
|
||||
- coveralls -b apps/erpnext -d ../../sites/.coverage
|
||||
|
||||
@@ -350,7 +350,7 @@ def filter_pricing_rules(args, pricing_rules):
|
||||
if len(pricing_rules) > 1:
|
||||
rate_or_discount = list(set([d.rate_or_discount for d in pricing_rules]))
|
||||
if len(rate_or_discount) == 1 and rate_or_discount[0] == "Discount Percentage":
|
||||
pricing_rules = filter(lambda x: x.for_price_list==args.price_list, pricing_rules) \
|
||||
pricing_rules = list(filter(lambda x: x.for_price_list==args.price_list, pricing_rules)) \
|
||||
or pricing_rules
|
||||
|
||||
if len(pricing_rules) > 1 and not args.for_shopping_cart:
|
||||
@@ -373,7 +373,7 @@ def apply_internal_priority(pricing_rules, field_set, args):
|
||||
filtered_rules = []
|
||||
for field in field_set:
|
||||
if args.get(field):
|
||||
filtered_rules = filter(lambda x: x[field]==args[field], pricing_rules)
|
||||
filtered_rules = list(filter(lambda x: x[field]==args[field], pricing_rules))
|
||||
if filtered_rules: break
|
||||
|
||||
return filtered_rules or pricing_rules
|
||||
|
||||
@@ -22,7 +22,7 @@ class TestTaxWithholdingCategory(unittest.TestCase):
|
||||
invoices = []
|
||||
|
||||
# create invoices for lower than single threshold tax rate
|
||||
for _ in xrange(2):
|
||||
for _ in range(2):
|
||||
pi = create_purchase_invoice(supplier = "Test TDS Supplier")
|
||||
pi.submit()
|
||||
invoices.append(pi)
|
||||
|
||||
@@ -47,8 +47,8 @@ class TestSalesPaymentSummary(unittest.TestCase):
|
||||
pe.submit()
|
||||
|
||||
mop = get_mode_of_payments(filters)
|
||||
self.assertTrue('Credit Card' in mop.values()[0])
|
||||
self.assertTrue('Cash' in mop.values()[0])
|
||||
self.assertTrue('Credit Card' in list(mop.values())[0])
|
||||
self.assertTrue('Cash' in list(mop.values())[0])
|
||||
|
||||
# Cancel all Cash payment entry and check if this mode of payment is still fetched.
|
||||
payment_entries = frappe.get_all("Payment Entry", filters={"mode_of_payment": "Cash", "docstatus": 1}, fields=["name", "docstatus"])
|
||||
@@ -57,8 +57,8 @@ class TestSalesPaymentSummary(unittest.TestCase):
|
||||
pe.cancel()
|
||||
|
||||
mop = get_mode_of_payments(filters)
|
||||
self.assertTrue('Credit Card' in mop.values()[0])
|
||||
self.assertTrue('Cash' not in mop.values()[0])
|
||||
self.assertTrue('Credit Card' in list(mop.values())[0])
|
||||
self.assertTrue('Cash' not in list(mop.values())[0])
|
||||
|
||||
def test_get_mode_of_payments_details(self):
|
||||
filters = get_filters()
|
||||
@@ -84,7 +84,7 @@ class TestSalesPaymentSummary(unittest.TestCase):
|
||||
|
||||
mopd = get_mode_of_payment_details(filters)
|
||||
|
||||
mopd_values = mopd.values()[0]
|
||||
mopd_values = list(mopd.values())[0]
|
||||
for mopd_value in mopd_values:
|
||||
if mopd_value[0] == "Credit Card":
|
||||
cc_init_amount = mopd_value[1]
|
||||
@@ -96,7 +96,7 @@ class TestSalesPaymentSummary(unittest.TestCase):
|
||||
pe.cancel()
|
||||
|
||||
mopd = get_mode_of_payment_details(filters)
|
||||
mopd_values = mopd.values()[0]
|
||||
mopd_values = list(mopd.values())[0]
|
||||
for mopd_value in mopd_values:
|
||||
if mopd_value[0] == "Credit Card":
|
||||
cc_final_amount = mopd_value[1]
|
||||
|
||||
@@ -36,7 +36,7 @@ class AssetValueAdjustment(Document):
|
||||
fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account = \
|
||||
get_depreciation_accounts(asset)
|
||||
|
||||
depreciation_cost_center, depreciation_series = frappe.get_cached_value('Company', asset.company,
|
||||
depreciation_cost_center, depreciation_series = frappe.get_cached_value('Company', asset.company,
|
||||
["depreciation_cost_center", "series_for_depreciation_entry"])
|
||||
|
||||
je = frappe.new_doc("Journal Entry")
|
||||
@@ -75,8 +75,8 @@ class AssetValueAdjustment(Document):
|
||||
rate_per_day = flt(d.value_after_depreciation) / flt(total_days)
|
||||
from_date = self.date
|
||||
else:
|
||||
no_of_depreciations = len([e.name for e in asset.schedules
|
||||
if (cint(s.finance_book_id) == d.idx and not e.journal_entry)])
|
||||
no_of_depreciations = len([s.name for s in asset.schedules
|
||||
if (cint(s.finance_book_id) == d.idx and not s.journal_entry)])
|
||||
|
||||
value_after_depreciation = d.value_after_depreciation
|
||||
for data in asset.schedules:
|
||||
|
||||
@@ -25,9 +25,12 @@ class TestLocation(unittest.TestCase):
|
||||
temp['features'][0]['properties']['feature_of'] = location
|
||||
formatted_locations.extend(temp['features'])
|
||||
|
||||
formatted_location_string = str(formatted_locations)
|
||||
test_location = frappe.get_doc('Location', 'Test Location Area')
|
||||
test_location.save()
|
||||
|
||||
self.assertEqual(formatted_location_string, str(json.loads(test_location.get('location'))['features']))
|
||||
test_location_features = json.loads(test_location.get('location'))['features']
|
||||
ordered_test_location_features = sorted(test_location_features, key=lambda x: x['properties']['feature_of'])
|
||||
ordered_formatted_locations = sorted(formatted_locations, key=lambda x: x['properties']['feature_of'])
|
||||
|
||||
self.assertEqual(ordered_formatted_locations, ordered_test_location_features)
|
||||
self.assertEqual(area, test_location.get('area'))
|
||||
|
||||
@@ -40,7 +40,7 @@ def get_products_details():
|
||||
products_response = call_mws_method(products.get_matching_product,marketplaceid=marketplace,
|
||||
asins=asin_list)
|
||||
|
||||
matching_products_list = products_response.parsed
|
||||
matching_products_list = products_response.parsed
|
||||
for product in matching_products_list:
|
||||
skus = [row["sku"] for row in sku_asin if row["asin"]==product.ASIN]
|
||||
for sku in skus:
|
||||
@@ -116,7 +116,7 @@ def call_mws_method(mws_method, *args, **kwargs):
|
||||
mws_settings = frappe.get_doc("Amazon MWS Settings")
|
||||
max_retries = mws_settings.max_retry_limit
|
||||
|
||||
for x in xrange(0, max_retries):
|
||||
for x in range(0, max_retries):
|
||||
try:
|
||||
response = mws_method(*args, **kwargs)
|
||||
return response
|
||||
|
||||
@@ -18,6 +18,7 @@ from erpnext.stock.stock_balance import get_planned_qty, update_bin_qty
|
||||
from frappe.utils.csvutils import getlink
|
||||
from erpnext.stock.utils import get_bin, validate_warehouse_company, get_latest_stock_qty
|
||||
from erpnext.utilities.transaction_base import validate_uom_is_integer
|
||||
from six import text_type
|
||||
|
||||
class OverProductionError(frappe.ValidationError): pass
|
||||
class StockOverProductionError(frappe.ValidationError): pass
|
||||
@@ -591,10 +592,10 @@ def make_timesheet(production_order, company):
|
||||
|
||||
@frappe.whitelist()
|
||||
def add_timesheet_detail(timesheet, args):
|
||||
if isinstance(timesheet, unicode):
|
||||
if isinstance(timesheet, text_type):
|
||||
timesheet = frappe.get_doc('Timesheet', timesheet)
|
||||
|
||||
if isinstance(args, unicode):
|
||||
if isinstance(args, text_type):
|
||||
args = json.loads(args)
|
||||
|
||||
timesheet.append('time_logs', args)
|
||||
|
||||
@@ -533,7 +533,7 @@ erpnext.patches.v11_0.create_department_records_for_each_company
|
||||
erpnext.patches.v11_0.make_location_from_warehouse
|
||||
erpnext.patches.v11_0.make_asset_finance_book_against_old_entries
|
||||
erpnext.patches.v11_0.check_buying_selling_in_currency_exchange
|
||||
erpnext.patches.v11_0.move_item_defaults_to_child_table_for_multicompany #02-07-2018
|
||||
erpnext.patches.v11_0.move_item_defaults_to_child_table_for_multicompany #02-07-2018 #19-06-2019
|
||||
erpnext.patches.v11_0.refactor_erpnext_shopify #2018-09-07
|
||||
erpnext.patches.v11_0.rename_overproduction_percent_field
|
||||
erpnext.patches.v11_0.update_backflush_subcontract_rm_based_on_bom
|
||||
|
||||
@@ -17,10 +17,8 @@ def execute():
|
||||
frappe.reload_doc('stock', 'doctype', 'item_default')
|
||||
frappe.reload_doc('stock', 'doctype', 'item')
|
||||
|
||||
if frappe.db.a_row_exists('Item Default'): return
|
||||
|
||||
companies = frappe.get_all("Company")
|
||||
if len(companies) == 1:
|
||||
if len(companies) == 1 and not frappe.get_all("Item Default", limit=1):
|
||||
try:
|
||||
frappe.db.sql('''
|
||||
INSERT INTO `tabItem Default`
|
||||
@@ -35,32 +33,64 @@ def execute():
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
item_details = frappe.get_all("Item", fields=["name", "default_warehouse", "buying_cost_center",
|
||||
"expense_account", "selling_cost_center", "income_account"], limit=100)
|
||||
item_details = frappe.db.sql(""" SELECT name, default_warehouse,
|
||||
buying_cost_center, expense_account, selling_cost_center, income_account
|
||||
FROM tabItem
|
||||
WHERE
|
||||
name not in (select distinct parent from `tabItem Default`) and ifnull(disabled, 0) = 0"""
|
||||
, as_dict=1)
|
||||
|
||||
for item in item_details:
|
||||
item_defaults = []
|
||||
items_default_data = {}
|
||||
for item_data in item_details:
|
||||
for d in [["default_warehouse", "Warehouse"], ["expense_account", "Account"],
|
||||
["income_account", "Account"], ["buying_cost_center", "Cost Center"],
|
||||
["selling_cost_center", "Cost Center"]]:
|
||||
if item_data.get(d[0]):
|
||||
company = frappe.get_value(d[1], item_data.get(d[0]), "company", cache=True)
|
||||
|
||||
def insert_into_item_defaults(doc_field_name, doc_field_value, company):
|
||||
for d in item_defaults:
|
||||
if d.get("company") == company:
|
||||
d[doc_field_name] = doc_field_value
|
||||
return
|
||||
item_defaults.append({
|
||||
"company": company,
|
||||
doc_field_name: doc_field_value
|
||||
})
|
||||
if item_data.name not in items_default_data:
|
||||
items_default_data[item_data.name] = {}
|
||||
|
||||
for d in [
|
||||
["default_warehouse", "Warehouse"], ["expense_account", "Account"], ["income_account", "Account"],
|
||||
["buying_cost_center", "Cost Center"], ["selling_cost_center", "Cost Center"]
|
||||
]:
|
||||
if item.get(d[0]):
|
||||
company = frappe.get_value(d[1], item.get(d[0]), "company", cache=True)
|
||||
insert_into_item_defaults(d[0], item.get(d[0]), company)
|
||||
company_wise_data = items_default_data[item_data.name]
|
||||
|
||||
doc = frappe.get_doc("Item", item.name)
|
||||
doc.extend("item_defaults", item_defaults)
|
||||
if company not in company_wise_data:
|
||||
company_wise_data[company] = {}
|
||||
|
||||
for child_doc in doc.item_defaults:
|
||||
child_doc.db_insert()
|
||||
default_data = company_wise_data[company]
|
||||
default_data[d[0]] = item_data.get(d[0])
|
||||
|
||||
to_insert_data = []
|
||||
|
||||
# items_default_data data structure will be as follow
|
||||
# {
|
||||
# 'item_code 1': {'company 1': {'default_warehouse': 'Test Warehouse 1'}},
|
||||
# 'item_code 2': {
|
||||
# 'company 1': {'default_warehouse': 'Test Warehouse 1'},
|
||||
# 'company 2': {'default_warehouse': 'Test Warehouse 1'}
|
||||
# }
|
||||
# }
|
||||
|
||||
for item_code, companywise_item_data in items_default_data.items():
|
||||
for company, item_default_data in companywise_item_data.items():
|
||||
to_insert_data.append((
|
||||
frappe.generate_hash("", 10),
|
||||
item_code,
|
||||
'Item',
|
||||
'item_defaults',
|
||||
company,
|
||||
item_default_data.get('default_warehouse'),
|
||||
item_default_data.get('expense_account'),
|
||||
item_default_data.get('income_account'),
|
||||
item_default_data.get('buying_cost_center'),
|
||||
item_default_data.get('selling_cost_center'),
|
||||
))
|
||||
|
||||
if to_insert_data:
|
||||
frappe.db.sql('''
|
||||
INSERT INTO `tabItem Default`
|
||||
(
|
||||
`name`, `parent`, `parenttype`, `parentfield`, `company`, `default_warehouse`,
|
||||
`expense_account`, `income_account`, `buying_cost_center`, `selling_cost_center`
|
||||
)
|
||||
VALUES {}
|
||||
'''.format(', '.join(['%s'] * len(to_insert_data))), tuple(to_insert_data))
|
||||
@@ -103,8 +103,8 @@ class TestTimesheet(unittest.TestCase):
|
||||
{
|
||||
"billable": 1,
|
||||
"activity_type": "_Test Activity Type",
|
||||
"from_type": now_datetime(),
|
||||
"hours": 3,
|
||||
"from_time": now_datetime(),
|
||||
"to_time": now_datetime() + datetime.timedelta(hours=3),
|
||||
"company": "_Test Company"
|
||||
}
|
||||
)
|
||||
@@ -113,8 +113,8 @@ class TestTimesheet(unittest.TestCase):
|
||||
{
|
||||
"billable": 1,
|
||||
"activity_type": "_Test Activity Type",
|
||||
"from_type": now_datetime(),
|
||||
"hours": 3,
|
||||
"from_time": now_datetime(),
|
||||
"to_time": now_datetime() + datetime.timedelta(hours=3),
|
||||
"company": "_Test Company"
|
||||
}
|
||||
)
|
||||
|
||||
@@ -69,13 +69,13 @@ def get_gl_entries(filters):
|
||||
|
||||
gl_entries = frappe.db.sql("""
|
||||
select
|
||||
gl.posting_date as GlPostDate, gl.name as GlName, gl.account, gl.transaction_date,
|
||||
gl.posting_date as GlPostDate, gl.name as GlName, gl.account, gl.transaction_date,
|
||||
sum(gl.debit) as debit, sum(gl.credit) as credit,
|
||||
sum(gl.debit_in_account_currency) as debitCurr, sum(gl.credit_in_account_currency) as creditCurr,
|
||||
gl.voucher_type, gl.voucher_no, gl.against_voucher_type,
|
||||
gl.against_voucher, gl.account_currency, gl.against,
|
||||
gl.voucher_type, gl.voucher_no, gl.against_voucher_type,
|
||||
gl.against_voucher, gl.account_currency, gl.against,
|
||||
gl.party_type, gl.party,
|
||||
inv.name as InvName, inv.title as InvTitle, inv.posting_date as InvPostDate,
|
||||
inv.name as InvName, inv.title as InvTitle, inv.posting_date as InvPostDate,
|
||||
pur.name as PurName, pur.title as PurTitle, pur.posting_date as PurPostDate,
|
||||
jnl.cheque_no as JnlRef, jnl.posting_date as JnlPostDate, jnl.title as JnlTitle,
|
||||
pay.name as PayName, pay.posting_date as PayPostDate, pay.title as PayTitle,
|
||||
@@ -84,7 +84,7 @@ def get_gl_entries(filters):
|
||||
emp.employee_name, emp.name as empName,
|
||||
stu.title as student_name, stu.name as stuName,
|
||||
member_name, mem.name as memName
|
||||
|
||||
|
||||
from `tabGL Entry` gl
|
||||
left join `tabSales Invoice` inv on gl.voucher_no = inv.name
|
||||
left join `tabPurchase Invoice` pur on gl.voucher_no = pur.name
|
||||
@@ -124,7 +124,7 @@ def get_result_as_list(data, filters):
|
||||
if account_number[0] is not None:
|
||||
CompteNum = account_number[0]
|
||||
else:
|
||||
frappe.throw(_("Account number for account {0} is not available.<br> Please setup your Chart of Accounts correctly.").format(account.name))
|
||||
frappe.throw(_("Account number for account {0} is not available.<br> Please setup your Chart of Accounts correctly.").format(d.get("account")))
|
||||
|
||||
if d.get("party_type") == "Customer":
|
||||
CompAuxNum = d.get("cusName")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from frappe.utils import flt, add_days, nowdate, add_months
|
||||
from frappe.utils import flt, add_days, nowdate, add_months, getdate
|
||||
import unittest
|
||||
|
||||
test_dependencies = ["Product Bundle"]
|
||||
@@ -18,7 +18,7 @@ class TestQuotation(unittest.TestCase):
|
||||
|
||||
self.assertTrue(quotation.payment_schedule)
|
||||
|
||||
def test_make_sales_order_terms_not_copied(self):
|
||||
def test_make_sales_order_terms_copied(self):
|
||||
from erpnext.selling.doctype.quotation.quotation import make_sales_order
|
||||
|
||||
quotation = frappe.copy_doc(test_records[0])
|
||||
@@ -29,7 +29,7 @@ class TestQuotation(unittest.TestCase):
|
||||
|
||||
sales_order = make_sales_order(quotation.name)
|
||||
|
||||
self.assertFalse(sales_order.get('payment_schedule'))
|
||||
self.assertTrue(sales_order.get('payment_schedule'))
|
||||
|
||||
def test_make_sales_order_with_different_currency(self):
|
||||
from erpnext.selling.doctype.quotation.quotation import make_sales_order
|
||||
@@ -109,10 +109,10 @@ class TestQuotation(unittest.TestCase):
|
||||
sales_order.insert()
|
||||
|
||||
self.assertEqual(sales_order.payment_schedule[0].payment_amount, 8906.00)
|
||||
self.assertEqual(sales_order.payment_schedule[0].due_date, quotation.transaction_date)
|
||||
self.assertEqual(sales_order.payment_schedule[0].due_date, getdate(quotation.transaction_date))
|
||||
self.assertEqual(sales_order.payment_schedule[1].payment_amount, 8906.00)
|
||||
self.assertEqual(
|
||||
sales_order.payment_schedule[1].due_date, add_days(quotation.transaction_date, 30)
|
||||
sales_order.payment_schedule[1].due_date, getdate(add_days(quotation.transaction_date, 30))
|
||||
)
|
||||
|
||||
def test_valid_till(self):
|
||||
|
||||
@@ -8,7 +8,7 @@ from frappe.utils import flt, cint, nowdate
|
||||
|
||||
from frappe import throw, _
|
||||
import frappe.defaults
|
||||
from frappe.utils import getdate
|
||||
from frappe.utils import getdate, cint
|
||||
from erpnext.controllers.buying_controller import BuyingController
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from frappe.desk.notifications import clear_doctype_notifications
|
||||
@@ -128,7 +128,7 @@ class PurchaseReceipt(BuyingController):
|
||||
self.company, self.base_grand_total)
|
||||
|
||||
self.update_prevdoc_status()
|
||||
if self.per_billed < 100:
|
||||
if cint(self.per_billed) < 100:
|
||||
self.update_billing_status()
|
||||
else:
|
||||
self.status = "Completed"
|
||||
|
||||
@@ -562,7 +562,7 @@ class TestStockEntry(unittest.TestCase):
|
||||
for d in stock_entry.get("items"):
|
||||
if d.item_code != "_Test FG Item 2":
|
||||
rm_cost += flt(d.amount)
|
||||
fg_cost = filter(lambda x: x.item_code=="_Test FG Item 2", stock_entry.get("items"))[0].amount
|
||||
fg_cost = list(filter(lambda x: x.item_code=="_Test FG Item 2", stock_entry.get("items")))[0].amount
|
||||
self.assertEqual(fg_cost,
|
||||
flt(rm_cost + bom_operation_cost + work_order.additional_operating_cost, 2))
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ from jinja2 import utils
|
||||
from html2text import html2text
|
||||
from frappe.utils import sanitize_html
|
||||
from frappe.utils.global_search import search
|
||||
from six import text_type
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
@@ -12,7 +13,7 @@ def get_context(context):
|
||||
query = str(utils.escape(sanitize_html(frappe.form_dict.q)))
|
||||
context.title = _('Help Results for')
|
||||
context.query = query
|
||||
|
||||
|
||||
context.route = '/search_help'
|
||||
d = frappe._dict()
|
||||
d.results_sections = get_help_results_sections(query)
|
||||
@@ -73,7 +74,7 @@ def prepare_api_results(api, topics_data):
|
||||
for topic in topics_data:
|
||||
route = api.base_url + '/' + (api.post_route + '/' if api.post_route else "")
|
||||
for key in api.post_route_key_list.split(','):
|
||||
route += unicode(topic[key])
|
||||
route += text_type(topic[key])
|
||||
|
||||
results.append(frappe._dict({
|
||||
'title': topic[api.post_title_key],
|
||||
|
||||
12
travis/run-tests.sh
Executable file
12
travis/run-tests.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [[ $TEST_TYPE == 'Server Side Test' ]]; then
|
||||
bench run-tests --app erpnext --coverage
|
||||
|
||||
elif [[ $TEST_TYPE == 'Patch Test' ]]; then
|
||||
wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
|
||||
bench --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
|
||||
bench migrate
|
||||
fi
|
||||
Reference in New Issue
Block a user