Merge branch 'hotfix'

This commit is contained in:
Sahil Khan
2019-06-26 15:53:52 +05:30
66 changed files with 466 additions and 184 deletions

View File

@@ -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

View File

@@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
__version__ = '11.1.39'
__version__ = '11.1.40'
def get_default_company(user=None):
'''Get default company for user'''

View File

@@ -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

View File

@@ -18,9 +18,6 @@ class TestPricingRule(unittest.TestCase):
frappe.db.sql("delete from `tabPricing Rule`")
def test_pricing_rule_for_discount(self):
from erpnext.stock.get_item_details import get_item_details
from frappe import MandatoryError
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule",
@@ -94,9 +91,6 @@ class TestPricingRule(unittest.TestCase):
self.assertEquals(details.get("discount_percentage"), 15)
def test_pricing_rule_for_margin(self):
from erpnext.stock.get_item_details import get_item_details
from frappe import MandatoryError
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule",
@@ -139,9 +133,6 @@ class TestPricingRule(unittest.TestCase):
self.assertEquals(details.get("margin_rate_or_amount"), 10)
def test_pricing_rule_for_variants(self):
from erpnext.stock.get_item_details import get_item_details
from frappe import MandatoryError
if not frappe.db.exists("Item", "Test Variant PRT"):
frappe.get_doc({
"doctype": "Item",

View File

@@ -487,7 +487,7 @@ class SalesInvoice(SellingController):
"""Set against account for debit to account"""
against_acc = []
for d in self.get('items'):
if d.income_account not in against_acc:
if d.income_account and d.income_account not in against_acc:
against_acc.append(d.income_account)
self.against_income_account = ','.join(against_acc)

View File

@@ -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)

View File

@@ -10,4 +10,10 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"fieldtype": "Check",
"default": 1
});
frappe.query_reports["Balance Sheet"]["filters"].push({
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"fieldtype": "Check"
});
});

View File

@@ -15,4 +15,10 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"label": __("Accumulated Values"),
"fieldtype": "Check"
});
frappe.query_reports["Cash Flow"]["filters"].push({
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"fieldtype": "Check"
});
});

View File

@@ -14,8 +14,8 @@ def execute(filters=None):
if cint(frappe.db.get_single_value('Accounts Settings', 'use_custom_cash_flow')):
from erpnext.accounts.report.cash_flow.custom_cash_flow import execute as execute_custom
return execute_custom(filters=filters)
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.periodicity, filters.accumulated_values, filters.company)
cash_flow_accounts = get_cash_flow_accounts()
@@ -25,18 +25,18 @@ def execute(filters=None):
accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
expense = get_data(filters.company, "Expense", "Debit", period_list, filters=filters,
accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
net_profit_loss = get_net_profit_loss(income, expense, period_list, filters.company)
data = []
company_currency = frappe.get_cached_value('Company', filters.company, "default_currency")
for cash_flow_account in cash_flow_accounts:
section_data = []
data.append({
"account_name": cash_flow_account['section_header'],
"account_name": cash_flow_account['section_header'],
"parent_account": None,
"indent": 0.0,
"indent": 0.0,
"account": cash_flow_account['section_header']
})
@@ -44,18 +44,18 @@ def execute(filters=None):
# add first net income in operations section
if net_profit_loss:
net_profit_loss.update({
"indent": 1,
"indent": 1,
"parent_account": cash_flow_accounts[0]['section_header']
})
data.append(net_profit_loss)
section_data.append(net_profit_loss)
for account in cash_flow_account['account_types']:
account_data = get_account_type_based_data(filters.company,
account['account_type'], period_list, filters.accumulated_values)
account_data = get_account_type_based_data(filters.company,
account['account_type'], period_list, filters.accumulated_values, filters)
account_data.update({
"account_name": account['label'],
"account": account['label'],
"account": account['label'],
"indent": 1,
"parent_account": cash_flow_account['section_header'],
"currency": company_currency
@@ -63,7 +63,7 @@ def execute(filters=None):
data.append(account_data)
section_data.append(account_data)
add_total_row_account(data, section_data, cash_flow_account['section_footer'],
add_total_row_account(data, section_data, cash_flow_account['section_footer'],
period_list, company_currency)
add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency)
@@ -105,13 +105,15 @@ def get_cash_flow_accounts():
# combine all cash flow accounts for iteration
return [operation_accounts, investing_accounts, financing_accounts]
def get_account_type_based_data(company, account_type, period_list, accumulated_values):
def get_account_type_based_data(company, account_type, period_list, accumulated_values, filters):
data = {}
total = 0
for period in period_list:
start_date = get_start_date(period, accumulated_values, company)
amount = get_account_type_based_gl_data(company, start_date, period['to_date'], account_type)
amount = get_account_type_based_gl_data(company, start_date,
period['to_date'], account_type, filters)
if amount and account_type == "Depreciation":
amount *= -1
@@ -121,14 +123,24 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_
data["total"] = total
return data
def get_account_type_based_gl_data(company, start_date, end_date, account_type):
def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters):
cond = ""
if filters.finance_book:
cond = " and finance_book = '%s'" %(frappe.db.escape(filters.finance_book))
if filters.include_default_book_entries:
company_fb = frappe.db.get_value("Company", company, 'default_finance_book')
cond = """ and finance_book in ('%s', '%s')
""" %(frappe.db.escape(filters.finance_book), frappe.db.escape(company_fb))
gl_sum = frappe.db.sql_list("""
select sum(credit) - sum(debit)
from `tabGL Entry`
where company=%s and posting_date >= %s and posting_date <= %s
and voucher_type != 'Period Closing Voucher'
and account in ( SELECT name FROM tabAccount WHERE account_type = %s)
""", (company, start_date, end_date, account_type))
and account in ( SELECT name FROM tabAccount WHERE account_type = %s) {cond}
""".format(cond=cond), (company, start_date, end_date, account_type))
return gl_sum[0] if gl_sum and gl_sum[0] else 0
@@ -154,7 +166,7 @@ def add_total_row_account(out, data, label, period_list, currency, consolidated
key = period if consolidated else period['key']
total_row.setdefault(key, 0.0)
total_row[key] += row.get(key, 0.0)
total_row.setdefault("total", 0.0)
total_row["total"] += row["total"]

View File

@@ -55,5 +55,10 @@ frappe.query_reports["Consolidated Financial Statement"] = {
"fieldtype": "Check",
"default": 0
},
{
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"fieldtype": "Check"
}
]
}

View File

@@ -355,7 +355,8 @@ def set_gl_entries_by_account(from_date, to_date, root_lft, root_rgt, filters, g
"lft": root_lft,
"rgt": root_rgt,
"company": d.name,
"finance_book": filters.get("finance_book")
"finance_book": filters.get("finance_book"),
"company_fb": frappe.db.get_value("Company", d.name, 'default_finance_book')
},
as_dict=True)
@@ -386,7 +387,10 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
additional_conditions.append("gl.posting_date >= %(from_date)s")
if filters.get("finance_book"):
additional_conditions.append("ifnull(finance_book, '') in (%(finance_book)s, '')")
if filters.get("include_default_book_entries"):
additional_conditions.append("finance_book in (%(finance_book)s, %(company_fb)s)")
else:
additional_conditions.append("finance_book in (%(finance_book)s)")
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""

View File

@@ -359,7 +359,8 @@ def set_gl_entries_by_account(
"to_date": to_date,
"cost_center": filters.cost_center,
"project": filters.project,
"finance_book": filters.get("finance_book")
"finance_book": filters.get("finance_book"),
"company_fb": frappe.db.get_value("Company", company, 'default_finance_book')
},
as_dict=True)
@@ -393,7 +394,10 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
additional_conditions.append("cost_center in %(cost_center)s")
if filters.get("finance_book"):
additional_conditions.append("ifnull(finance_book, '') in (%(finance_book)s, '')")
if filters.get("include_default_book_entries"):
additional_conditions.append("finance_book in (%(finance_book)s, %(company_fb)s)")
else:
additional_conditions.append("finance_book in (%(finance_book)s)")
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""

View File

@@ -216,6 +216,11 @@ frappe.query_reports["General Ledger"] = {
"fieldname": "show_opening_entries",
"label": __("Show Opening Entries"),
"fieldtype": "Check"
},
{
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"fieldtype": "Check"
}
]
}

View File

@@ -133,6 +133,10 @@ def get_gl_entries(filters):
sum(debit_in_account_currency) as debit_in_account_currency,
sum(credit_in_account_currency) as credit_in_account_currency"""
if filters.get("include_default_book_entries"):
filters['company_fb'] = frappe.db.get_value("Company",
filters.get("company"), 'default_finance_book')
gl_entries = frappe.db.sql(
"""
select
@@ -188,7 +192,10 @@ def get_conditions(filters):
conditions.append("project in %(project)s")
if filters.get("finance_book"):
conditions.append("ifnull(finance_book, '') in (%(finance_book)s, '')")
if filters.get("include_default_book_entries"):
conditions.append("finance_book in (%(finance_book)s, %(company_fb)s)")
else:
conditions.append("finance_book in (%(finance_book)s)")
from frappe.desk.reportview import build_match_conditions
match_conditions = build_match_conditions("GL Entry")

View File

@@ -12,20 +12,21 @@ def get_ordered_to_be_billed_data(args):
child_tab = doctype + " Item"
precision = get_field_precision(frappe.get_meta(child_tab).get_field("billed_amt"),
currency=get_default_currency()) or 2
project_field = get_project_field(doctype, party)
return frappe.db.sql("""
Select
`{parent_tab}`.name, `{parent_tab}`.{date_field}, `{parent_tab}`.{party}, `{parent_tab}`.{party}_name,
{project_field}, `{child_tab}`.item_code, `{child_tab}`.base_amount,
(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)),
(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)),
(`{child_tab}`.base_amount - (`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1))),
`{child_tab}`.item_name, `{child_tab}`.description, `{parent_tab}`.company
from
`{parent_tab}`, `{child_tab}`
where
`{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1 and `{parent_tab}`.status != 'Closed'
`{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1
and `{parent_tab}`.status not in ('Closed', 'Completed')
and `{child_tab}`.amount > 0 and round(`{child_tab}`.billed_amt *
ifnull(`{parent_tab}`.conversion_rate, 1), {precision}) < `{child_tab}`.base_amount
order by

View File

@@ -41,6 +41,11 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"fieldname": "accumulated_values",
"label": __("Accumulated Values"),
"fieldtype": "Check"
},
{
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"fieldtype": "Check"
}
);
});

View File

@@ -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]

View File

@@ -105,7 +105,7 @@ def get_rootwise_opening_balances(filters, report_type):
if filters.finance_book:
fb_conditions = " and finance_book = %(finance_book)s"
if filters.include_default_book_entries:
fb_conditions = " and (finance_book in (%(finance_book)s, %(company_fb)s) or finance_book is null)"
fb_conditions = " and (finance_book in (%(finance_book)s, %(company_fb)s))"
additional_conditions += fb_conditions

View File

@@ -6,7 +6,6 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
from frappe import _
class Disease(Document):
def validate(self):

View File

@@ -7,7 +7,6 @@ import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import flt, cint
from frappe import _
class SoilTexture(Document):
soil_edit_order = [2, 1, 0]
@@ -35,8 +34,8 @@ class SoilTexture(Document):
if sum(self.soil_edit_order) < 5: return
last_edit_index = self.soil_edit_order.index(min(self.soil_edit_order))
# set composition of the last edited soil
self.set( self.soil_types[last_edit_index],
# set composition of the last edited soil
self.set( self.soil_types[last_edit_index],
100 - sum(cint(self.get(soil_type)) for soil_type in self.soil_types) + cint(self.get(self.soil_types[last_edit_index])))
# calculate soil type

View File

@@ -6,7 +6,6 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
from frappe import _
class WaterAnalysis(Document):
def load_contents(self):

View File

@@ -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:

View File

@@ -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'))

View File

@@ -104,7 +104,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
if(doc.docstatus == 1 && !in_list(["Closed", "Delivered"], doc.status)) {
if (this.frm.has_perm("submit")) {
if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100) {
if(flt(doc.per_billed, 6) < 100 || flt(doc.per_received, 6) < 100) {
cur_frm.add_custom_button(__('Close'), this.close_purchase_order, __("Status"));
}
}

View File

@@ -20,6 +20,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "supplier_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -53,6 +54,7 @@
"collapsible": 0,
"columns": 0,
"default": "{supplier_name}",
"fetch_if_empty": 0,
"fieldname": "title",
"fieldtype": "Data",
"hidden": 1,
@@ -86,6 +88,7 @@
"collapsible": 0,
"columns": 0,
"default": "",
"fetch_if_empty": 0,
"fieldname": "naming_series",
"fieldtype": "Select",
"hidden": 0,
@@ -121,6 +124,7 @@
"collapsible": 0,
"columns": 0,
"description": "",
"fetch_if_empty": 0,
"fieldname": "supplier",
"fieldtype": "Link",
"hidden": 0,
@@ -156,6 +160,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.supplier && doc.docstatus===0 && (!(doc.items && doc.items.length) || (doc.items.length==1 && !doc.items[0].item_code))",
"fetch_if_empty": 0,
"fieldname": "get_items_from_open_material_requests",
"fieldtype": "Button",
"hidden": 0,
@@ -189,6 +194,7 @@
"collapsible": 0,
"columns": 0,
"fetch_from": "supplier.supplier_name",
"fetch_if_empty": 0,
"fieldname": "supplier_name",
"fieldtype": "Data",
"hidden": 0,
@@ -222,6 +228,7 @@
"collapsible": 0,
"columns": 0,
"description": "",
"fetch_if_empty": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
@@ -256,6 +263,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break1",
"fieldtype": "Column Break",
"hidden": 0,
@@ -290,6 +298,7 @@
"collapsible": 0,
"columns": 0,
"default": "Today",
"fetch_if_empty": 0,
"fieldname": "transaction_date",
"fieldtype": "Date",
"hidden": 0,
@@ -324,6 +333,7 @@
"collapsible": 0,
"columns": 0,
"default": "",
"fetch_if_empty": 0,
"fieldname": "schedule_date",
"fieldtype": "Date",
"hidden": 0,
@@ -357,6 +367,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.docstatus===1",
"fetch_if_empty": 0,
"fieldname": "order_confirmation_no",
"fieldtype": "Data",
"hidden": 0,
@@ -390,6 +401,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.order_confirmation_no",
"fetch_if_empty": 0,
"fieldname": "order_confirmation_date",
"fieldtype": "Date",
"hidden": 0,
@@ -422,6 +434,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
@@ -457,6 +470,7 @@
"collapsible": 0,
"collapsible_depends_on": "",
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "drop_ship",
"fieldtype": "Section Break",
"hidden": 0,
@@ -490,6 +504,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fetch_if_empty": 0,
"fieldname": "customer",
"fieldtype": "Link",
"hidden": 0,
@@ -524,6 +539,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fetch_if_empty": 0,
"fieldname": "customer_name",
"fieldtype": "Data",
"hidden": 0,
@@ -556,6 +572,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_19",
"fieldtype": "Column Break",
"hidden": 0,
@@ -588,6 +605,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fetch_if_empty": 0,
"fieldname": "customer_contact_person",
"fieldtype": "Link",
"hidden": 0,
@@ -621,6 +639,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "customer_contact_display",
"fieldtype": "Small Text",
"hidden": 1,
@@ -653,6 +672,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "customer_contact_mobile",
"fieldtype": "Small Text",
"hidden": 1,
@@ -685,6 +705,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "customer_contact_email",
"fieldtype": "Code",
"hidden": 1,
@@ -718,6 +739,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_addresses",
"fieldtype": "Section Break",
"hidden": 0,
@@ -750,6 +772,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "supplier_address",
"fieldtype": "Link",
"hidden": 0,
@@ -782,6 +805,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "contact_person",
"fieldtype": "Link",
"hidden": 0,
@@ -815,6 +839,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fetch_if_empty": 0,
"fieldname": "address_display",
"fieldtype": "Small Text",
"hidden": 0,
@@ -846,6 +871,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "contact_display",
"fieldtype": "Small Text",
"hidden": 0,
@@ -877,6 +903,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "contact_mobile",
"fieldtype": "Small Text",
"hidden": 0,
@@ -908,6 +935,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "contact_email",
"fieldtype": "Small Text",
"hidden": 0,
@@ -939,6 +967,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "col_break_address",
"fieldtype": "Column Break",
"hidden": 0,
@@ -971,6 +1000,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fetch_if_empty": 0,
"fieldname": "shipping_address",
"fieldtype": "Link",
"hidden": 0,
@@ -1004,6 +1034,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "shipping_address_display",
"fieldtype": "Small Text",
"hidden": 0,
@@ -1036,6 +1067,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "currency_and_price_list",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1068,6 +1100,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "currency",
"fieldtype": "Link",
"hidden": 0,
@@ -1103,6 +1136,7 @@
"collapsible": 0,
"columns": 0,
"description": "",
"fetch_if_empty": 0,
"fieldname": "conversion_rate",
"fieldtype": "Float",
"hidden": 0,
@@ -1137,6 +1171,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "cb_price_list",
"fieldtype": "Column Break",
"hidden": 0,
@@ -1167,6 +1202,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "buying_price_list",
"fieldtype": "Link",
"hidden": 0,
@@ -1199,6 +1235,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "price_list_currency",
"fieldtype": "Link",
"hidden": 0,
@@ -1231,6 +1268,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "plc_conversion_rate",
"fieldtype": "Float",
"hidden": 0,
@@ -1263,6 +1301,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "ignore_pricing_rule",
"fieldtype": "Check",
"hidden": 0,
@@ -1294,6 +1333,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "sec_warehouse",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1325,6 +1365,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "set_warehouse",
"fieldtype": "Link",
"hidden": 0,
@@ -1358,6 +1399,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "col_break_warehouse",
"fieldtype": "Column Break",
"hidden": 0,
@@ -1390,6 +1432,7 @@
"collapsible": 0,
"columns": 0,
"default": "No",
"fetch_if_empty": 0,
"fieldname": "is_subcontracted",
"fieldtype": "Select",
"hidden": 0,
@@ -1423,6 +1466,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_subcontracted==\"Yes\"",
"fetch_if_empty": 0,
"fieldname": "supplier_warehouse",
"fieldtype": "Link",
"hidden": 0,
@@ -1456,6 +1500,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "items_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1489,6 +1534,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "scan_barcode",
"fieldtype": "Data",
"hidden": 0,
@@ -1521,6 +1567,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "items",
"fieldtype": "Table",
"hidden": 0,
@@ -1556,6 +1603,7 @@
"collapsible": 0,
"collapsible_depends_on": "supplied_items",
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "raw_material_details",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1589,6 +1637,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fetch_if_empty": 0,
"fieldname": "supplied_items",
"fieldtype": "Table",
"hidden": 0,
@@ -1623,6 +1672,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "sb_last_purchase",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1653,6 +1703,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "total_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -1685,6 +1736,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -1718,6 +1770,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_net_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -1752,6 +1805,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_26",
"fieldtype": "Column Break",
"hidden": 0,
@@ -1782,6 +1836,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "total",
"fieldtype": "Currency",
"hidden": 0,
@@ -1815,6 +1870,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "net_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -1849,6 +1905,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "total_net_weight",
"fieldtype": "Float",
"hidden": 0,
@@ -1881,6 +1938,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "taxes_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1915,6 +1973,7 @@
"collapsible": 0,
"columns": 0,
"description": "",
"fetch_if_empty": 0,
"fieldname": "taxes_and_charges",
"fieldtype": "Link",
"hidden": 0,
@@ -1949,6 +2008,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_50",
"fieldtype": "Column Break",
"hidden": 0,
@@ -1980,6 +2040,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "shipping_rule",
"fieldtype": "Link",
"hidden": 0,
@@ -2013,6 +2074,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_52",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2044,6 +2106,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "taxes",
"fieldtype": "Table",
"hidden": 0,
@@ -2078,6 +2141,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "sec_tax_breakup",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2110,6 +2174,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "other_charges_calculation",
"fieldtype": "Text",
"hidden": 0,
@@ -2142,6 +2207,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "totals",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2175,6 +2241,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_taxes_and_charges_added",
"fieldtype": "Currency",
"hidden": 0,
@@ -2209,6 +2276,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_taxes_and_charges_deducted",
"fieldtype": "Currency",
"hidden": 0,
@@ -2243,6 +2311,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_total_taxes_and_charges",
"fieldtype": "Currency",
"hidden": 0,
@@ -2277,6 +2346,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_39",
"fieldtype": "Column Break",
"hidden": 0,
@@ -2308,6 +2378,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "taxes_and_charges_added",
"fieldtype": "Currency",
"hidden": 0,
@@ -2342,6 +2413,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "taxes_and_charges_deducted",
"fieldtype": "Currency",
"hidden": 0,
@@ -2376,6 +2448,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "total_taxes_and_charges",
"fieldtype": "Currency",
"hidden": 0,
@@ -2410,6 +2483,7 @@
"collapsible": 1,
"collapsible_depends_on": "discount_amount",
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "discount_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2443,6 +2517,7 @@
"collapsible": 0,
"columns": 0,
"default": "Grand Total",
"fetch_if_empty": 0,
"fieldname": "apply_discount_on",
"fieldtype": "Select",
"hidden": 0,
@@ -2476,6 +2551,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_discount_amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -2509,6 +2585,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_45",
"fieldtype": "Column Break",
"hidden": 0,
@@ -2540,6 +2617,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "additional_discount_percentage",
"fieldtype": "Float",
"hidden": 0,
@@ -2572,6 +2650,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "discount_amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -2605,6 +2684,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "totals_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2636,6 +2716,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_grand_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -2670,6 +2751,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_rounding_adjustment",
"fieldtype": "Currency",
"hidden": 0,
@@ -2704,6 +2786,7 @@
"collapsible": 0,
"columns": 0,
"description": "In Words will be visible once you save the Purchase Order.",
"fetch_if_empty": 0,
"fieldname": "base_in_words",
"fieldtype": "Data",
"hidden": 0,
@@ -2737,6 +2820,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_rounded_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -2771,6 +2855,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break4",
"fieldtype": "Column Break",
"hidden": 0,
@@ -2802,6 +2887,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "grand_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -2836,6 +2922,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "rounding_adjustment",
"fieldtype": "Currency",
"hidden": 0,
@@ -2869,6 +2956,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "rounded_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -2881,6 +2969,7 @@
"label": "Rounded Total",
"length": 0,
"no_copy": 0,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -2901,6 +2990,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
"hidden": 0,
@@ -2933,6 +3023,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "in_words",
"fieldtype": "Data",
"hidden": 0,
@@ -2966,6 +3057,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "advance_paid",
"fieldtype": "Currency",
"hidden": 0,
@@ -2998,6 +3090,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "payment_schedule_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -3030,6 +3123,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "payment_terms_template",
"fieldtype": "Link",
"hidden": 0,
@@ -3063,6 +3157,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "payment_schedule",
"fieldtype": "Table",
"hidden": 0,
@@ -3097,6 +3192,7 @@
"collapsible": 1,
"collapsible_depends_on": "terms",
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "terms_section_break",
"fieldtype": "Section Break",
"hidden": 0,
@@ -3130,6 +3226,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "tc_name",
"fieldtype": "Link",
"hidden": 0,
@@ -3164,6 +3261,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "terms",
"fieldtype": "Text Editor",
"hidden": 0,
@@ -3197,6 +3295,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "more_info",
"fieldtype": "Section Break",
"hidden": 0,
@@ -3230,6 +3329,7 @@
"collapsible": 0,
"columns": 0,
"default": "Draft",
"fetch_if_empty": 0,
"fieldname": "status",
"fieldtype": "Select",
"hidden": 0,
@@ -3264,6 +3364,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "ref_sq",
"fieldtype": "Data",
"hidden": 1,
@@ -3297,6 +3398,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "party_account_currency",
"fieldtype": "Link",
"hidden": 1,
@@ -3330,6 +3432,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_74",
"fieldtype": "Column Break",
"hidden": 0,
@@ -3363,6 +3466,7 @@
"columns": 0,
"depends_on": "eval:!doc.__islocal",
"description": "",
"fetch_if_empty": 0,
"fieldname": "per_received",
"fieldtype": "Percent",
"hidden": 0,
@@ -3398,6 +3502,7 @@
"columns": 0,
"depends_on": "eval:!doc.__islocal",
"description": "",
"fetch_if_empty": 0,
"fieldname": "per_billed",
"fieldtype": "Percent",
"hidden": 0,
@@ -3431,6 +3536,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break5",
"fieldtype": "Section Break",
"hidden": 0,
@@ -3465,6 +3571,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "letter_head",
"fieldtype": "Link",
"hidden": 0,
@@ -3499,6 +3606,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "select_print_heading",
"fieldtype": "Link",
"hidden": 0,
@@ -3533,6 +3641,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_86",
"fieldtype": "Column Break",
"hidden": 0,
@@ -3565,6 +3674,7 @@
"collapsible": 0,
"columns": 0,
"description": "",
"fetch_if_empty": 0,
"fieldname": "group_same_items",
"fieldtype": "Check",
"hidden": 0,
@@ -3598,6 +3708,7 @@
"collapsible": 0,
"columns": 0,
"default": "",
"fetch_if_empty": 0,
"fieldname": "language",
"fieldtype": "Data",
"hidden": 0,
@@ -3631,6 +3742,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "subscription_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -3665,6 +3777,7 @@
"columns": 0,
"depends_on": "",
"description": "",
"fetch_if_empty": 0,
"fieldname": "from_date",
"fieldtype": "Date",
"hidden": 0,
@@ -3698,6 +3811,7 @@
"columns": 0,
"depends_on": "",
"description": "",
"fetch_if_empty": 0,
"fieldname": "to_date",
"fieldtype": "Date",
"hidden": 0,
@@ -3729,6 +3843,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_97",
"fieldtype": "Column Break",
"hidden": 0,
@@ -3760,6 +3875,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "auto_repeat",
"fieldtype": "Link",
"hidden": 0,
@@ -3794,6 +3910,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval: doc.auto_repeat",
"fetch_if_empty": 0,
"fieldname": "update_auto_repeat_reference",
"fieldtype": "Button",
"hidden": 0,
@@ -3831,7 +3948,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-01-07 16:51:56.739693",
"modified": "2019-06-24 20:55:03.466766",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",

View File

@@ -1915,7 +1915,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"default": "0",
"depends_on": "eval:parent.is_subcontracted == 'Yes'",
"fieldname": "include_exploded_items",
"fieldtype": "Check",
@@ -2344,7 +2344,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2019-01-07 16:51:57.546323",
"modified": "2019-06-23 20:03:13.818917",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",
@@ -2359,4 +2359,4 @@
"track_changes": 1,
"track_seen": 0,
"track_views": 0
}
}

View File

@@ -747,7 +747,12 @@ class AccountsController(TransactionBase):
count += 1
item.qty = group_item_qty[item.item_code]
item.amount = group_item_amount[item.item_code]
item.rate = flt(flt(item.amount) / flt(item.qty), item.precision("rate"))
if item.qty:
item.rate = flt(flt(item.amount) / flt(item.qty), item.precision("rate"))
else:
item.rate = 0
item.idx = count
del group_item_qty[item.item_code]
else:

View File

@@ -428,8 +428,9 @@ class BuyingController(StockController):
elif not flt(d.rejected_qty):
d.rejected_qty = flt(d.received_qty) - flt(d.qty)
val = flt(d.qty) + flt(d.rejected_qty)
# Check Received Qty = Accepted Qty + Rejected Qty
if ((flt(d.qty) + flt(d.rejected_qty)) != flt(d.received_qty)):
if (flt(val, d.precision("received_qty")) != flt(d.received_qty, d.precision("received_qty"))):
frappe.throw(_("Accepted + Rejected Qty must be equal to Received quantity for Item {0}").format(d.item_code))
def validate_negative_quantity(self, item_row, field_list):

View File

@@ -27,7 +27,7 @@ status_map = {
],
"Quotation": [
["Draft", None],
["Submitted", "eval:self.docstatus==1"],
["Open", "eval:self.docstatus==1"],
["Lost", "eval:self.status=='Lost'"],
["Ordered", "has_sales_order"],
["Cancelled", "eval:self.docstatus==2"],

View File

@@ -22,7 +22,16 @@ def verify_request():
frappe.set_user(woocommerce_settings.creation_user)
@frappe.whitelist(allow_guest=True)
def order():
def order(*args, **kwargs):
try:
_order(*args, **kwargs)
except Exception:
error_message = frappe.get_traceback()+"\n\n Request Data: \n"+json.loads(frappe.request.data).__str__()
frappe.log_error(error_message, "WooCommerce Error")
raise
def _order(*args, **kwargs):
woocommerce_settings = frappe.get_doc("Woocommerce Settings")
if frappe.flags.woocomm_test_order_data:
fd = frappe.flags.woocomm_test_order_data

View File

@@ -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

View File

@@ -42,7 +42,7 @@ update_and_get_user_progress = "erpnext.utilities.user_progress_utils.update_def
on_session_creation = "erpnext.shopping_cart.utils.set_cart_count"
on_logout = "erpnext.shopping_cart.utils.clear_cart_count"
treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Group', 'Sales Person', 'Territory', 'Assessment Group']
treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Group', 'Sales Person', 'Territory', 'Assessment Group', 'Department']
# website
update_website_context = "erpnext.shopping_cart.utils.update_website_context"

View File

@@ -2,8 +2,8 @@
// For license information, please see license.txt
frappe.views.calendar["Attendance"] = {
field_map: {
"start": "date",
"end": "date",
"start": "attendance_date",
"end": "attendance_date",
"id": "name",
"docstatus": 1
},

View File

@@ -4,7 +4,7 @@
frappe.ui.form.on('Department', {
refresh: function(frm) {
// read-only for root department
if(!frm.doc.parent_department) {
if(!frm.doc.parent_department && !frm.is_new()) {
frm.set_read_only();
frm.set_intro(__("This is a root department and cannot be edited."));
}

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
@@ -19,6 +20,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "department_name",
"fieldtype": "Data",
"hidden": 0,
@@ -52,6 +54,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "parent_department",
"fieldtype": "Link",
"hidden": 0,
@@ -85,6 +88,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
@@ -118,6 +122,7 @@
"bold": 1,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "is_group",
"fieldtype": "Check",
"hidden": 0,
@@ -150,6 +155,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "disabled",
"fieldtype": "Check",
"hidden": 0,
@@ -182,6 +188,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"hidden": 0,
@@ -214,6 +221,7 @@
"collapsible": 0,
"columns": 0,
"description": "Days for which Holidays are blocked for this department.",
"fetch_if_empty": 0,
"fieldname": "leave_block_list",
"fieldtype": "Link",
"hidden": 0,
@@ -246,6 +254,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "leave_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -279,6 +288,7 @@
"collapsible": 0,
"columns": 0,
"description": "The first Leave Approver in the list will be set as the default Leave Approver.",
"fetch_if_empty": 0,
"fieldname": "leave_approvers",
"fieldtype": "Table",
"hidden": 0,
@@ -312,6 +322,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "expense_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -345,6 +356,7 @@
"collapsible": 0,
"columns": 0,
"description": "The first Expense Approver in the list will be set as the default Expense Approver.",
"fetch_if_empty": 0,
"fieldname": "expense_approvers",
"fieldtype": "Table",
"hidden": 0,
@@ -378,6 +390,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "lft",
"fieldtype": "Int",
"hidden": 1,
@@ -410,6 +423,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "rgt",
"fieldtype": "Int",
"hidden": 1,
@@ -442,6 +456,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "old_parent",
"fieldtype": "Data",
"hidden": 1,
@@ -479,7 +494,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-08-29 06:26:12.995703",
"modified": "2019-06-25 18:43:05.550387",
"modified_by": "Administrator",
"module": "HR",
"name": "Department",
@@ -543,7 +558,7 @@
"write": 1
}
],
"quick_entry": 1,
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 1,

View File

@@ -2,9 +2,8 @@ frappe.ui.form.on("Employee Attendance Tool", {
refresh: function(frm) {
frm.disable_save();
},
onload: function(frm) {
frm.doc.department = frm.doc.branch = frm.doc.company = "All";
frm.set_value("date", frappe.datetime.get_today());
erpnext.employee_attendance_tool.load_employees(frm);
},
@@ -24,7 +23,7 @@ frappe.ui.form.on("Employee Attendance Tool", {
company: function(frm) {
erpnext.employee_attendance_tool.load_employees(frm);
}
});

View File

@@ -17,12 +17,11 @@ def get_employees(date, department = None, branch = None, company = None):
attendance_not_marked = []
attendance_marked = []
filters = {"status": "Active", "date_of_joining": ["<=", date]}
if department != "All":
filters["department"] = department
if branch != "All":
filters["branch"] = branch
if company != "All":
filters["company"] = company
for field, value in {'department': department,
'branch': branch, 'company': company}.items():
if value:
filters[field] = value
employee_list = frappe.get_list("Employee", fields=["employee", "employee_name"], filters=filters, order_by="employee_name")
marked_employee = {}

View File

@@ -25,5 +25,13 @@ frappe.ui.form.on("Job Applicant", {
}
}
frm.set_query("job_title", function() {
return {
filters: {
'status': 'Open'
}
};
});
}
});

View File

@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe, erpnext
import datetime, math
from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words, getdate
from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words
from frappe.model.naming import make_autoname
from frappe import msgprint, _

View File

@@ -90,7 +90,7 @@ class TestBOM(unittest.TestCase):
self.assertEqual(bom.base_total_cost, 486000)
def test_bom_cost_multi_uom_multi_currency_based_on_price_list(self):
frappe.db.set_value("Price List", "_Test Price List", "price_not_uom_dependant", 1)
frappe.db.set_value("Price List", "_Test Price List", "price_not_uom_dependent", 1)
for item_code, rate in (("_Test Item", 3600), ("_Test Item Home Desktop Manufactured", 3000)):
frappe.db.sql("delete from `tabItem Price` where price_list='_Test Price List' and item_code=%s",
item_code)

View File

@@ -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)

View File

@@ -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
@@ -586,7 +586,7 @@ erpnext.patches.v11_0.add_permissions_in_gst_settings
erpnext.patches.v11_1.setup_guardian_role
execute:frappe.delete_doc('DocType', 'Notification Control')
erpnext.patches.v11_0.remove_barcodes_field_from_copy_fields_to_variants
erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019
erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019 #25-06-2019
erpnext.patches.v11_0.make_italian_localization_fields # 26-03-2019
erpnext.patches.v11_1.make_job_card_time_logs
erpnext.patches.v11_1.set_variant_based_on
@@ -601,4 +601,5 @@ execute:frappe.delete_doc("Report", "Inactive Items")
erpnext.patches.v11_1.delete_scheduling_tool
erpnext.patches.v11_1.update_bank_transaction_status
erpnext.patches.v11_1.renamed_delayed_item_report
erpnext.patches.v11_1.set_missing_opportunity_from
erpnext.patches.v11_1.set_missing_opportunity_from
erpnext.patches.v11_1.set_quotation_status

View File

@@ -7,9 +7,10 @@ import frappe
def execute():
if frappe.get_all("Item Barcode", limit=1): return
frappe.reload_doc("stock", "doctype", "item_barcode")
items_barcode = frappe.get_all('Item', ['name', 'barcode'], { 'barcode': ('!=', '') })
items_barcode = frappe.db.sql("select name, barcode from tabItem where barcode is not null", as_dict=True)
frappe.reload_doc("stock", "doctype", "item")

View File

@@ -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))

View File

@@ -0,0 +1,7 @@
from __future__ import unicode_literals
import frappe
def execute():
frappe.db.sql(""" UPDATE `tabQuotation` set status = 'Open'
where docstatus = 1 and status = 'Submitted' """)

View File

@@ -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"
}
)

View File

@@ -1290,7 +1290,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
},
callback: function(r) {
if(!r.exc) {
me.frm.set_value("taxes", r.message);
for (let tax of r.message) {
me.frm.add_child("taxes", tax);
}
me.calculate_taxes_and_totals();
}
}

View File

@@ -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")

View File

@@ -29,7 +29,20 @@ frappe.query_reports["HSN-wise-summary of outward supplies"] = {
"placeholder":"Company GSTIN",
"options": [""],
"width": "80"
}
},
{
"fieldname":"from_date",
"label": __("From Date"),
"fieldtype": "Date",
"width": "80"
},
{
"fieldname":"to_date",
"label": __("To Date"),
"fieldtype": "Date",
"width": "80"
},
],
onload: (report) => {
fetch_gstins(report);

View File

@@ -88,7 +88,9 @@ def get_conditions(filters):
for opts in (("company", " and company=%(company)s"),
("gst_hsn_code", " and gst_hsn_code=%(gst_hsn_code)s"),
("company_gstin", " and company_gstin=%(company_gstin)s")):
("company_gstin", " and company_gstin=%(company_gstin)s"),
("from_date", " and posting_date >= %(from_date)s"),
("to_date", "and posting_date <= %(to_date)s")):
if filters.get(opts[0]):
conditions += opts[1]

View File

@@ -3096,7 +3096,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
"options": "Draft\nSubmitted\nOrdered\nLost\nCancelled\nOpen\nReplied",
"options": "Draft\nOpen\nReplied\nOrdered\nLost\nCancelled",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
@@ -3224,7 +3224,7 @@
"istable": 0,
"max_attachments": 1,
"menu_index": 0,
"modified": "2019-05-11 19:26:50.735628",
"modified": "2019-06-25 15:31:04.724730",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation",

View File

@@ -161,6 +161,10 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
"Sales Team": {
"doctype": "Sales Team",
"add_if_empty": True
},
"Payment Schedule": {
"doctype": "Payment Schedule",
"add_if_empty": True
}
}, target_doc, set_missing_values, ignore_permissions=ignore_permissions)

View File

@@ -13,11 +13,11 @@ frappe.listview_settings['Quotation'] = {
},
get_indicator: function(doc) {
if(doc.status==="Submitted") {
if(doc.status==="Open") {
if (doc.valid_till && doc.valid_till < frappe.datetime.nowdate()) {
return [__("Expired"), "darkgrey", "valid_till,<," + frappe.datetime.nowdate()];
} else {
return [__("Submitted"), "blue", "status,=,Submitted"];
return [__("Open"), "orange", "status,=,Open"];
}
} else if(doc.status==="Ordered") {
return [__("Ordered"), "green", "status,=,Ordered"];

View File

@@ -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):

View File

@@ -133,7 +133,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
if (this.frm.has_perm("submit")) {
// close
if(flt(doc.per_delivered, 6) < 100 || flt(doc.per_billed) < 100) {
if(flt(doc.per_delivered, 6) < 100 || flt(doc.per_billed, 6) < 100) {
this.frm.add_custom_button(__('Close'),
function() { me.close_sales_order() }, __("Status"))
}

View File

@@ -574,8 +574,8 @@ def make_delivery_note(source_name, target_doc=None):
if item:
target.cost_center = frappe.db.get_value("Project", source_parent.project, "cost_center") \
or item.get("selling_cost_center") \
or item_group.get("selling_cost_center")
or item.get("buying_cost_center") \
or item_group.get("buying_cost_center")
target_doc = get_mapped_doc("Sales Order", source_name, {
"Sales Order": {

View File

@@ -443,7 +443,12 @@ def make_sales_invoice(source_name, target_doc=None):
def get_pending_qty(item_row):
pending_qty = item_row.qty - invoiced_qty_map.get(item_row.name, 0)
returned_qty = flt(returned_qty_map.get(item_row.item_code, 0))
returned_qty = 0
if returned_qty_map.get(item_row.item_code) > 0:
returned_qty = flt(returned_qty_map.get(item_row.item_code, 0))
returned_qty_map[item_row.item_code] -= pending_qty
if returned_qty:
if returned_qty >= pending_qty:
pending_qty = 0
@@ -451,6 +456,7 @@ def make_sales_invoice(source_name, target_doc=None):
else:
pending_qty -= returned_qty
returned_qty = 0
return pending_qty, returned_qty
doc = get_mapped_doc("Delivery Note", source_name, {

View File

@@ -20,8 +20,7 @@ class DeliveryTrip(Document):
# Google Maps returns distances in meters by default
self.default_distance_uom = frappe.db.get_single_value("Global Defaults", "default_distance_unit") or "Meter"
self.uom_conversion_factor = frappe.db.get_value("UOM Conversion Factor",
{"from_uom": "Meter", "to_uom": self.default_distance_uom},
"value")
{"from_uom": "Meter", "to_uom": self.default_distance_uom}, "value")
def validate(self):
self.validate_stop_addresses()
@@ -139,7 +138,7 @@ class DeliveryTrip(Document):
# Include last leg in the final distance calculation
self.uom = self.default_distance_uom
total_distance = sum([leg.get("distance", {}).get("value", 0.0)
for leg in directions.get("legs")]) # in meters
for leg in directions.get("legs")]) # in meters
self.total_distance = total_distance * self.uom_conversion_factor
else:
idx += len(route) - 1
@@ -358,8 +357,12 @@ def notify_customers(delivery_trip):
email_recipients = []
for stop in delivery_trip.delivery_stops:
contact_info = frappe.db.get_value("Contact", stop.contact,
["first_name", "last_name", "email_id", "gender"], as_dict=1)
contact_info = frappe.db.get_value("Contact", stop.contact, ["first_name", "last_name", "email_id"], as_dict=1)
context.update({"items": []})
if stop.delivery_note:
items = frappe.get_all("Delivery Note Item", filters={"parent": stop.delivery_note, "docstatus": 1}, fields=["*"])
context.update({"items": items})
if contact_info and contact_info.email_id:
context.update(stop.as_dict())
@@ -369,9 +372,9 @@ def notify_customers(delivery_trip):
dispatch_template = frappe.get_doc("Email Template", dispatch_template_name)
frappe.sendmail(recipients=contact_info.email_id,
subject=dispatch_template.subject,
message=frappe.render_template(dispatch_template.response, context),
attachments=get_attachments(stop))
subject=dispatch_template.subject,
message=frappe.render_template(dispatch_template.response, context),
attachments=get_attachments(stop))
stop.db_set("email_sent_to", contact_info.email_id)
email_recipients.append(contact_info.email_id)
@@ -388,9 +391,7 @@ def get_attachments(delivery_stop):
return []
dispatch_attachment = frappe.db.get_single_value("Delivery Settings", "dispatch_attachment")
attachments = frappe.attach_print("Delivery Note",
delivery_stop.delivery_note,
file_name="Delivery Note",
print_format=dispatch_attachment)
attachments = frappe.attach_print("Delivery Note", delivery_stop.delivery_note,
file_name="Delivery Note", print_format=dispatch_attachment)
return [attachments]

View File

@@ -67,8 +67,6 @@ class Item(WebsiteGenerator):
from frappe.model.naming import set_name_by_naming_series
set_name_by_naming_series(self)
self.item_code = self.name
elif not self.item_code:
msgprint(_("Item Code is mandatory because Item is not automatically numbered"), raise_exception=1)
self.item_code = strip(self.item_code)
self.name = self.item_code

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
@@ -22,6 +23,7 @@
"collapsible": 0,
"columns": 0,
"default": "1",
"fetch_if_empty": 0,
"fieldname": "enabled",
"fieldtype": "Check",
"hidden": 0,
@@ -53,6 +55,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "sb_1",
"fieldtype": "Section Break",
"hidden": 0,
@@ -83,6 +86,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "price_list_name",
"fieldtype": "Data",
"hidden": 0,
@@ -116,6 +120,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "currency",
"fieldtype": "Link",
"hidden": 0,
@@ -148,6 +153,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "buying",
"fieldtype": "Check",
"hidden": 0,
@@ -179,6 +185,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "selling",
"fieldtype": "Check",
"hidden": 0,
@@ -210,7 +217,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "price_not_uom_dependant",
"fetch_if_empty": 0,
"fieldname": "price_not_uom_dependent",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -219,7 +227,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Price Not UOM Dependant",
"label": "Price Not UOM Dependent",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -242,6 +250,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
@@ -272,6 +281,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "countries",
"fieldtype": "Table",
"hidden": 0,
@@ -310,7 +320,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 1,
"modified": "2018-08-29 06:35:16.546274",
"modified": "2019-06-24 17:16:28.027302",
"modified_by": "Administrator",
"module": "Stock",
"name": "Price List",

View File

@@ -7,7 +7,7 @@ QUnit.test("test price list with uom dependancy", function(assert) {
() => frappe.set_route('Form', 'Price List', 'Standard Buying'),
() => {
cur_frm.set_value('price_not_uom_dependant','1');
cur_frm.set_value('price_not_uom_dependent','1');
frappe.timeout(1);
},
() => cur_frm.save(),

View File

@@ -4,11 +4,10 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, cint, nowdate
from frappe.utils import flt, cint, nowdate, getdate
from frappe import throw, _
import frappe.defaults
from frappe.utils import getdate
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 +127,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"

View File

@@ -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))

View File

@@ -834,12 +834,12 @@ def get_price_list_currency(price_list):
def get_price_list_uom_dependant(price_list):
if price_list:
result = frappe.db.get_value("Price List", {"name": price_list,
"enabled": 1}, ["name", "price_not_uom_dependant"], as_dict=True)
"enabled": 1}, ["name", "price_not_uom_dependent"], as_dict=True)
if not result:
throw(_("Price List {0} is disabled or does not exist").format(price_list))
return not result.price_not_uom_dependant
return not result.price_not_uom_dependent
def get_price_list_currency_and_exchange_rate(args):

View File

@@ -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
View 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