Merge branch 'develop' into bom_convert_uom

This commit is contained in:
bcornwellmott 2017-05-24 12:35:12 -07:00 committed by GitHub
commit 8fa1e03367
27 changed files with 118 additions and 477 deletions

View File

@ -2,7 +2,7 @@
from __future__ import unicode_literals
import frappe
__version__ = '8.0.36'
__version__ = '8.0.38'
def get_default_company(user=None):

View File

@ -415,10 +415,10 @@ class SalesInvoice(SellingController):
throw(_("Customer {0} does not belong to project {1}").format(self.customer,self.project))
def validate_pos(self):
if flt(self.paid_amount) + flt(self.write_off_amount) \
- flt(self.grand_total) > 1/(10**(self.precision("grand_total") + 1)) and self.is_return:
frappe.throw(_("""Paid amount + Write Off Amount can not be greater than Grand Total"""))
if self.is_return:
if flt(self.paid_amount) + flt(self.write_off_amount) - flt(self.grand_total) < \
1/(10**(self.precision("grand_total") + 1)):
frappe.throw(_("Paid amount + Write Off Amount can not be greater than Grand Total"))
def validate_item_code(self):
for d in self.get('items'):

View File

@ -7,10 +7,13 @@ import frappe
import datetime
from frappe import _, msgprint, scrub
from frappe.defaults import get_user_permissions
from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff, add_years, get_timestamp
from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff, \
add_years, get_timestamp, nowdate
from frappe.geo.doctype.address.address import get_address_display, get_default_address
from frappe.email.doctype.contact.contact import get_contact_details, get_default_contact
from erpnext.exceptions import PartyFrozen, InvalidCurrency, PartyDisabled, InvalidAccountCurrency
from erpnext.accounts.utils import get_fiscal_year
from erpnext import get_default_currency
class DuplicatePartyAccountError(frappe.ValidationError): pass
@ -359,4 +362,37 @@ def get_timeline_data(doctype, name):
timestamp = get_timestamp(date)
out.update({ timestamp: count })
return out
return out
def get_dashboard_info(party_type, party):
current_fiscal_year = get_fiscal_year(nowdate(), as_dict=True)
party_account_currency = get_party_account_currency(party_type, party, frappe.db.get_default("company"))
company_default_currency = get_default_currency()
if party_account_currency==company_default_currency:
total_field = "base_grand_total"
else:
total_field = "grand_total"
doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
billing_this_year = frappe.db.sql("""
select sum({0})
from `tab{1}`
where {2}=%s and docstatus=1 and posting_date between %s and %s
""".format(total_field, doctype, party_type.lower()),
(party, current_fiscal_year.year_start_date, current_fiscal_year.year_end_date))
total_unpaid = frappe.db.sql("""
select sum(debit_in_account_currency) - sum(credit_in_account_currency)
from `tabGL Entry`
where party_type = %s and party=%s""", (party_type, party))
info = {}
info["billing_this_year"] = billing_this_year[0][0] if billing_this_year else 0
info["currency"] = party_account_currency
info["total_unpaid"] = total_unpaid[0][0] if total_unpaid else 0
if party_type == "Supplier":
info["total_unpaid"] = -1 * info["total_unpaid"]
return info

View File

@ -6,11 +6,9 @@ import frappe
import frappe.defaults
from frappe import msgprint, _
from frappe.model.naming import make_autoname
from frappe.geo.address_and_contact import (load_address_and_contact,
delete_contact_and_address)
from frappe.geo.address_and_contact import load_address_and_contact, delete_contact_and_address
from erpnext.utilities.transaction_base import TransactionBase
from erpnext.accounts.party import validate_party_accounts, get_timeline_data # keep this
from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this
class Supplier(TransactionBase):
def get_feed(self):
@ -22,22 +20,7 @@ class Supplier(TransactionBase):
self.load_dashboard_info()
def load_dashboard_info(self):
billing_this_year = frappe.db.sql("""
select sum(credit_in_account_currency) - sum(debit_in_account_currency)
from `tabGL Entry`
where voucher_type='Purchase Invoice' and party_type = 'Supplier'
and party=%s and fiscal_year = %s""",
(self.name, frappe.db.get_default("fiscal_year")))
total_unpaid = frappe.db.sql("""select sum(outstanding_amount)
from `tabPurchase Invoice`
where supplier=%s and docstatus = 1""", self.name)
info = {}
info["billing_this_year"] = billing_this_year[0][0] if billing_this_year else 0
info["total_unpaid"] = total_unpaid[0][0] if total_unpaid else 0
info = get_dashboard_info(self.doctype, self.name)
self.set_onload('dashboard_info', info)
def autoname(self):

View File

@ -24,5 +24,3 @@ There are two major ways in which ERPNext values your items.
* **Moving Average:** In this method, ERPNext assumes that the value of the item at any point is the average price of the units of that Item in stock. For example, if the value of an Item is X in a Warehouse with quantity Y and another quantity Y1 is added to the Warehouse at cost X1, the new value X2 would be:
> New Value X2 = (X * Y + X1 * Y1) / (Y + Y1)
{next}

View File

@ -1586,32 +1586,12 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-04-10 12:13:59.630780",
"modified": "2017-05-20 13:10:59.630780",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "All",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
@ -1662,4 +1642,4 @@
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}
}

View File

@ -397,4 +397,5 @@ erpnext.patches.v8_0.rename_total_margin_to_rate_with_margin # 11-05-2017
erpnext.patches.v8_0.fix_status_for_invoices_with_negative_outstanding
erpnext.patches.v8_0.make_payments_table_blank_for_non_pos_invoice
erpnext.patches.v8_0.set_sales_invoice_serial_number_from_delivery_note
erpnext.patches.v8_0.update_stock_qty_value_in_bom_item
erpnext.patches.v8_0.delete_schools_depricated_doctypes

View File

@ -3,26 +3,32 @@ from frappe.model.utils.rename_field import rename_field
def execute():
#Rename Grading Structure to Grading Scale
frappe.rename_doc("DocType", "Grading Structure", "Grading Scale", force=True)
frappe.rename_doc("DocType", "Grade Interval", "Grading Scale Interval", force=True)
if not frappe.db.exists("DocType", "Grading Scale"):
frappe.rename_doc("DocType", "Grading Structure", "Grading Scale", force=True)
if not frappe.db.exists("DocType", "Grading Scale Interval"):
frappe.rename_doc("DocType", "Grade Interval", "Grading Scale Interval", force=True)
frappe.reload_doc("schools", "doctype", "grading_scale_interval")
rename_field("Grading Scale Interval", "to_score", "threshold")
if "to_score" in frappe.db.get_table_columns("Grading Scale Interval"):
rename_field("Grading Scale Interval", "to_score", "threshold")
frappe.rename_doc("DocType", "Assessment", "Assessment Plan", force=True)
if not frappe.db.exists("DocType", "Assessment Plan"):
frappe.rename_doc("DocType", "Assessment", "Assessment Plan", force=True)
#Rename Assessment Results
frappe.reload_doc("schools", "doctype", "assessment_plan")
rename_field("Assessment Plan", "grading_structure", "grading_scale")
if "grading_structure" in frappe.db.get_table_columns("Assessment Plan"):
rename_field("Assessment Plan", "grading_structure", "grading_scale")
frappe.reload_doc("schools", "doctype", "assessment_result")
frappe.reload_doc("schools", "doctype", "assessment_result_detail")
frappe.reload_doc("schools", "doctype", "assessment_criteria")
for assessment in frappe.get_all("Assessment Plan", fields=["name", "grading_scale"], filters = [["docstatus", "!=", 2 ]]):
print assessment
for stud_result in frappe.db.sql("select * from `tabAssessment Result` where parent= %s", assessment.name, as_dict=True):
for assessment in frappe.get_all("Assessment Plan",
fields=["name", "grading_scale"], filters = [["docstatus", "!=", 2 ]]):
for stud_result in frappe.db.sql("select * from `tabAssessment Result` where parent= %s",
assessment.name, as_dict=True):
if stud_result.result:
assessment_result = frappe.new_doc("Assessment Result")
assessment_result.student = stud_result.student

View File

@ -0,0 +1,14 @@
# Copyright (c) 2017, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
""" delete doctypes """
if frappe.db.exists("DocType", "Grading Structure"):
frappe.delete_doc("DocType", "Grading Structure", force=1)
if frappe.db.exists("DocType", "Grade Interval"):
frappe.delete_doc("DocType", "Grade Interval", force=1)

View File

@ -15,10 +15,10 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
// if rate is greater than price_list_rate, set margin
// or set discount
item.discount_percentage = 0;
item.margin_type = 'Percentage';
item.margin_rate_or_amount = flt(Math.abs(1 - item.rate / item.price_list_rate) * 100.0,
precision("discount_percentage", item));
item.rate_with_margin = item.rate;
item.margin_type = 'Amount';
item.margin_rate_or_amount = flt(item.rate - item.price_list_rate,
precision("margin_rate_or_amount", item));
item.rate_with_margin = item.rate;
} else {
item.discount_percentage = flt((1 - item.rate / item.price_list_rate) * 100.0,
precision("discount_percentage", item));

View File

@ -68,12 +68,12 @@
</div>
<div class="col-xs-6 numeric_keypad hidden-xs" style="display:none">
{% var chartData = [__("Qty"), __("Disc"), __("Price")] %} {% for(var i=0; i
{% var chartData = ["Qty", "Disc", "Price"] %} {% for(var i=0; i
<3; i++) { %} <div class="row text-right">
{% for(var j=i*3; j
<(i+1)*3; j++) { %} <button type="button" class="btn btn-default numeric-keypad" val="{{j+1}}">{{j+1}}</button>
{% } %}
<button type="button" id="pos-item-{{ chartData[i].toLowerCase() }}" class="btn text-center btn-default numeric-keypad pos-operation">{{ chartData[i] }}</button>
<button type="button" id="pos-item-{{ chartData[i].toLowerCase() }}" class="btn text-center btn-default numeric-keypad pos-operation">{{ __(chartData[i]) }}</button>
</div>
{% } %}
<div class="row text-right">
@ -120,8 +120,8 @@
<div class="cell search-item"></div>
</div>
<div class="app-listing item-list image-view-container">
</div>
</div>
</div>
</div>
</div>

View File

@ -1,122 +0,0 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2016-08-26 03:11:09.591049",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "grade_code",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Grade Code",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "min_score",
"fieldtype": "Percent",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Min Score",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "1",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "grade_description",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Grade Description",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-12-14 12:54:56.902465",
"modified_by": "Administrator",
"module": "Schools",
"name": "Grade Interval",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
}

View File

@ -1,11 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class GradeInterval(Document):
def validate(self):
pass

View File

@ -1,8 +0,0 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Grading Structure', {
refresh: function(frm) {
}
});

View File

@ -1,202 +0,0 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 1,
"autoname": "field:grading_system_name",
"beta": 0,
"creation": "2016-08-26 03:06:53.922972",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "grading_system_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Grading System Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "grading_intervals_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Grading Intervals",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "grade_intervals",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Grade Intervals",
"length": 0,
"no_copy": 0,
"options": "Grade Interval",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-12-14 12:35:39.690256",
"modified_by": "Administrator",
"module": "Schools",
"name": "Grading Structure",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Academics User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "grading_system_name",
"track_seen": 0
}

View File

@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe import _
from frappe.utils import cstr
class GradingStructure(Document):
def validate(self):
grade_intervals = self.get("grade_intervals")
check_overlap(grade_intervals, self)
#Check if any of the grade intervals for this grading structure overlap
def check_overlap(grade_intervals, parent_doc):
for interval1 in grade_intervals:
for interval2 in grade_intervals:
if interval1.name == interval2.name:
pass
else:
if (interval1.from_score <= interval2.from_score and interval1.to_score >= interval2.from_score) or (interval1.from_score <= interval2.to_score and interval1.to_score >= interval2.to_score):
frappe.throw(_("""The intervals for Grade Code {0} overlaps with the grade intervals for other grades.
Please check intervals {0} and {1} and try again""".format(interval1.grade_code, interval2.grade_code)))

View File

@ -1,12 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
# test_records = frappe.get_test_records('Grading Structure')
class TestGradingStructure(unittest.TestCase):
pass

View File

@ -10,8 +10,7 @@ from frappe.utils import flt, cint, cstr
from frappe.desk.reportview import build_match_conditions
from erpnext.utilities.transaction_base import TransactionBase
from frappe.geo.address_and_contact import load_address_and_contact, delete_contact_and_address
from erpnext.accounts.party import validate_party_accounts, get_timeline_data # keep this
from erpnext import get_default_currency
from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this
class Customer(TransactionBase):
def get_feed(self):
@ -23,25 +22,9 @@ class Customer(TransactionBase):
self.load_dashboard_info()
def load_dashboard_info(self):
billing_this_year = frappe.db.sql("""
select sum(debit_in_account_currency) - sum(credit_in_account_currency), account_currency
from `tabGL Entry`
where voucher_type='Sales Invoice' and party_type = 'Customer'
and party=%s and fiscal_year = %s""",
(self.name, frappe.db.get_default("fiscal_year")))
total_unpaid = frappe.db.sql("""select sum(outstanding_amount)
from `tabSales Invoice`
where customer=%s and docstatus = 1""", self.name)
info = {}
info["billing_this_year"] = billing_this_year[0][0] if billing_this_year else 0
info["currency"] = billing_this_year[0][1] if billing_this_year else get_default_currency()
info["total_unpaid"] = total_unpaid[0][0] if total_unpaid else 0
info = get_dashboard_info(self.doctype, self.name)
self.set_onload('dashboard_info', info)
def autoname(self):
cust_master_name = frappe.defaults.get_global_default('cust_master_name')
if cust_master_name == 'Customer Name':

View File

@ -348,9 +348,13 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
margin_type: function(doc, cdt, cdn){
// calculate the revised total margin and rate on margin type changes
item = locals[cdt][cdn];
this.apply_pricing_rule_on_item(item, doc,cdt, cdn)
this.calculate_taxes_and_totals();
cur_frm.refresh_fields();
if(!item.margin_type) {
frappe.model.set_value(cdt, cdn, "margin_rate_or_amount", 0);
} else {
this.apply_pricing_rule_on_item(item, doc,cdt, cdn)
this.calculate_taxes_and_totals();
cur_frm.refresh_fields();
}
}
});

View File

@ -1,6 +1,6 @@
{% macro show_card(card) %}
<div style="width: 50%; float:left; min-height: 80px; padding-top: 20px;">
<h6 style="color: {{ text_muted }}; font-size: 12px; margin-bottom: 0px; margin-top: 0px;">{{ card.label }}
<h6 style="color: {{ text_muted }}; font-size: 12px; margin-bottom: 0px; margin-top: 0px;">{{ _(card.label) }}
{% if card.count %}
<span class="badge">({{ card.count }})</span>
{% endif %}</h6>

View File

@ -91,8 +91,7 @@ def get_exchange_rate(from_currency, to_currency, transaction_date=None):
response.raise_for_status()
value = response.json()["rates"][to_currency]
cache.setex(key, value, 6 * 60 * 60)
return flt(value)
except:
frappe.msgprint(_("Unable to find exchange rate for {0} to {1} for key date {2}").format(from_currency, to_currency, transaction_date))
frappe.msgprint(_("Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually").format(from_currency, to_currency, transaction_date))
return 0.0

View File

@ -44,8 +44,6 @@ frappe.ui.form.on("Item", {
}, __("View"));
}
// make sensitive fields(has_serial_no, is_stock_item, valuation_method)
// read only if any stock ledger entry exists
if(!frm.doc.is_fixed_asset) {
erpnext.item.make_dashboard(frm);
}
@ -77,6 +75,8 @@ frappe.ui.form.on("Item", {
erpnext.item.edit_prices_button(frm);
// make sensitive fields(has_serial_no, is_stock_item, valuation_method, has_batch_no)
// read only if any stock ledger entry exists
if (!frm.doc.__islocal && frm.doc.is_stock_item) {
frm.toggle_enable(['has_serial_no', 'is_stock_item', 'valuation_method', 'has_batch_no'],
(frm.doc.__onload && frm.doc.__onload.sle_exists=="exists") ? false : true);

View File

@ -33,7 +33,7 @@ frappe.ui.form.on("Material Request Item", {
"qty": function(frm, doctype, name) {
var d = locals[doctype][name];
if (flt(d.qty) < flt(d.min_order_qty)) {
alert(__("Warning: Material Requested Qty is less than Minimum Order Qty"));
frappe.msgprint(__("Warning: Material Requested Qty is less than Minimum Order Qty"));
}
}
}

View File

@ -74,7 +74,8 @@ class PurchaseReceipt(BuyingController):
"Purchase Order Item": {
"ref_dn_field": "purchase_order_item",
"compare_fields": [["project", "="], ["uom", "="], ["item_code", "="]],
"is_child_table": True
"is_child_table": True,
"allow_duplicate_prev_row_id": True
}
})

View File

@ -26,3 +26,19 @@ class StockSettings(Document):
# show/hide barcode field
frappe.make_property_setter({'fieldname': 'barcode', 'property': 'hidden',
'value': 0 if self.show_barcode_field else 1})
self.cant_change_valuation_method()
def cant_change_valuation_method(self):
db_valuation_method = frappe.db.get_single_value("Stock Settings", "valuation_method")
if db_valuation_method and db_valuation_method != self.valuation_method:
# check if there are any stock ledger entries against items
# which does not have it's own valuation method
sle = frappe.db.sql("""select name from `tabStock Ledger Entry` sle
where exists(select name from tabItem
where name=sle.item_code and (valuation_method is null or valuation_method=''))
""")
if sle:
frappe.throw(_("Can't change valuation method, as there are transactions against some items which does not have it's own valuation method"))