diff --git a/.travis.yml b/.travis.yml
index d6fc930471..a2c0e47349 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,6 +11,7 @@ install:
- pip install flake8==3.3.0
- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
- sudo rm /etc/apt/sources.list.d/docker.list
+ - sudo apt-get install hhvm && rm -rf /home/travis/.kiex/
- sudo apt-get purge -y mysql-common mysql-server mysql-client
- nvm install v7.10.0
- wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 8a247cc745..540e223376 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
-__version__ = '10.1.27'
+__version__ = '10.1.28'
def get_default_company(user=None):
'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 5e67e4423f..98d5880571 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -82,7 +82,7 @@ class JournalEntry(AccountsController):
d.reference_type = ''
d.reference_name = ''
d.db_update()
-
+
def unlink_asset_reference(self):
for d in self.get("accounts"):
if d.reference_type=="Asset" and d.reference_name:
@@ -125,7 +125,7 @@ class JournalEntry(AccountsController):
if (d.party_type == 'Customer' and flt(d.credit) > 0) or \
(d.party_type == 'Supplier' and flt(d.debit) > 0):
if d.is_advance=="No":
- msgprint(_("Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry.").format(d.idx, d.account))
+ msgprint(_("Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry.").format(d.idx, d.account), alert=1)
elif d.reference_type in ("Sales Order", "Purchase Order") and d.is_advance != "Yes":
frappe.throw(_("Row {0}: Payment against Sales/Purchase Order should always be marked as advance").format(d.idx))
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
index 930375d491..f726ec6b80 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
@@ -138,7 +138,8 @@ class OpeningInvoiceCreationTool(Document):
income_expense_account_field = "expense_account"
item = get_item_dict()
- return frappe._dict({
+
+ args = frappe._dict({
"items": [item],
"is_opening": "Yes",
"set_posting_time": 1,
@@ -150,6 +151,11 @@ class OpeningInvoiceCreationTool(Document):
"currency": frappe.db.get_value("Company", self.company, "default_currency")
})
+ if self.invoice_type == "Sales":
+ args["is_pos"] = 0
+
+ return args
+
@frappe.whitelist()
def get_temporary_opening_account(company=None):
if not company:
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
index 5b68f1d2ab..9fefc03716 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
@@ -19,7 +19,13 @@
{%= __(report.report_name) %}
-{%= filters.customer || filters.supplier %}
+
+ {% if (filters.customer_name) { %}
+ {%= filters.customer_name %}
+ {% } else { %}
+ {%= filters.customer || filters.supplier %}
+ {% } %}
+
{% if (filters.tax_id) { %}
{%= __("Tax Id: ")%} {%= filters.tax_id %}
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index f44ea448e7..3f9d167864 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -17,8 +17,9 @@ frappe.query_reports["Accounts Receivable"] = {
"options": "Customer",
on_change: () => {
var customer = frappe.query_report_filters_by_name.customer.get_value();
- frappe.db.get_value('Customer', customer, "tax_id", function(value) {
+ frappe.db.get_value('Customer', customer, ["tax_id", "customer_name"], function(value) {
frappe.query_report_filters_by_name.tax_id.set_value(value["tax_id"]);
+ frappe.query_report_filters_by_name.customer_name.set_value(value["customer_name"]);
});
}
},
@@ -81,6 +82,12 @@ frappe.query_reports["Accounts Receivable"] = {
"label": __("Tax Id"),
"fieldtype": "Data",
"hidden": 1
+ },
+ {
+ "fieldname":"customer_name",
+ "label": __("Customer Name"),
+ "fieldtype": "Data",
+ "hidden": 1
}
],
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index ab189cf1af..62295d4a69 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -83,15 +83,15 @@ def validate_returned_items(doc):
else:
ref = valid_items.get(d.item_code, frappe._dict())
validate_quantity(doc, d, ref, valid_items, already_returned_items)
-
+
if ref.rate and doc.doctype in ("Delivery Note", "Sales Invoice") and flt(d.rate) > ref.rate:
frappe.throw(_("Row # {0}: Rate cannot be greater than the rate used in {1} {2}")
.format(d.idx, doc.doctype, doc.return_against))
-
+
elif ref.batch_no and d.batch_no not in ref.batch_no:
frappe.throw(_("Row # {0}: Batch No must be same as {1} {2}")
.format(d.idx, doc.doctype, doc.return_against))
-
+
elif ref.serial_no:
if not d.serial_no:
frappe.throw(_("Row # {0}: Serial No is mandatory").format(d.idx))
@@ -120,25 +120,30 @@ def validate_quantity(doc, args, ref, valid_items, already_returned_items):
for column in fields:
returned_qty = flt(already_returned_data.get(column, 0)) if len(already_returned_data) > 0 else 0
- reference_qty = (ref.get(column) if column == 'stock_qty'
- else ref.get(column) * ref.get("conversion_factor", 1.0))
+
+ if column == 'stock_qty':
+ reference_qty = ref.get(column)
+ current_stock_qty = args.get(column)
+ else:
+ reference_qty = ref.get(column) * ref.get("conversion_factor", 1.0)
+ current_stock_qty = args.get(column) * args.get("conversion_factor", 1.0)
max_returnable_qty = flt(reference_qty) - returned_qty
label = column.replace('_', ' ').title()
- if reference_qty:
+ if reference_qty:
if flt(args.get(column)) > 0:
frappe.throw(_("{0} must be negative in return document").format(label))
elif returned_qty >= reference_qty and args.get(column):
frappe.throw(_("Item {0} has already been returned")
.format(args.item_code), StockOverReturnError)
- elif (abs(args.get(column)) * args.get("conversion_factor", 1.0)) > max_returnable_qty:
+ elif abs(current_stock_qty) > max_returnable_qty:
frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
.format(args.idx, reference_qty, args.item_code), StockOverReturnError)
def get_ref_item_dict(valid_items, ref_item_row):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
-
+
valid_items.setdefault(ref_item_row.item_code, frappe._dict({
"qty": 0,
"rate": 0,
@@ -160,10 +165,10 @@ def get_ref_item_dict(valid_items, ref_item_row):
if ref_item_row.get("serial_no"):
item_dict["serial_no"] += get_serial_nos(ref_item_row.serial_no)
-
+
if ref_item_row.get("batch_no"):
item_dict["batch_no"].append(ref_item_row.batch_no)
-
+
return valid_items
def get_already_returned_items(doc):
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 699e1c608f..e968e61d74 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -29,6 +29,7 @@ class calculate_taxes_and_totals(object):
self.set_item_wise_tax_breakup()
def _calculate(self):
+ self.validate_conversion_rate()
self.calculate_item_values()
self.initialize_taxes()
self.determine_exclusive_rate()
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.js b/erpnext/hr/doctype/salary_slip/salary_slip.js
index a99a919406..cec53563a6 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.js
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.js
@@ -29,9 +29,10 @@ frappe.ui.form.on("Salary Slip", {
})
},
- start_date: function(frm){
+ start_date: function(frm, dt, dn){
if(frm.doc.start_date){
frm.trigger("set_end_date");
+ get_emp_and_leave_details(frm.doc, dt, dn);
}
},
@@ -65,18 +66,20 @@ frappe.ui.form.on("Salary Slip", {
cur_frm.fields_dict['deductions'].grid.set_column_disp(salary_detail_fields,false);
},
- salary_slip_based_on_timesheet: function(frm) {
+ salary_slip_based_on_timesheet: function(frm, dt, dn) {
frm.trigger("toggle_fields");
- frm.set_value('start_date', '');
+ get_emp_and_leave_details(frm.doc, dt, dn);
},
- payroll_frequency: function(frm) {
+ payroll_frequency: function(frm, dt, dn) {
frm.trigger("toggle_fields");
+ frm.set_value('end_date', '');
frm.set_value('start_date', '');
+ get_emp_and_leave_details(frm.doc, dt, dn);
},
- employee: function(frm){
- frm.set_value('start_date', '');
+ employee: function(frm, dt, dn) {
+ get_emp_and_leave_details(frm.doc, dt, dn);
},
toggle_fields: function(frm) {
@@ -109,7 +112,7 @@ frappe.ui.form.on('Salary Slip Timesheet', {
// Get leave details
//---------------------------------------------------------------------
-cur_frm.cscript.start_date = function(doc, dt, dn){
+var get_emp_and_leave_details = function(doc, dt, dn) {
if(!doc.start_date){
return frappe.call({
method: 'get_emp_and_leave_details',
@@ -122,11 +125,9 @@ cur_frm.cscript.start_date = function(doc, dt, dn){
}
}
-cur_frm.cscript.payroll_frequency = cur_frm.cscript.salary_slip_based_on_timesheet = cur_frm.cscript.start_date;
-
cur_frm.cscript.employee = function(doc,dt,dn){
doc.salary_structure = ''
- cur_frm.cscript.start_date(doc, dt, dn)
+ get_emp_and_leave_details(doc, dt, dn);
}
cur_frm.cscript.leave_without_pay = function(doc,dt,dn){
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js
index 8e6b69bd9e..bdf3c22bc1 100755
--- a/erpnext/hr/doctype/salary_structure/salary_structure.js
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.js
@@ -161,6 +161,28 @@ frappe.ui.form.on('Salary Structure', {
}
});
+frappe.ui.form.on('Salary Structure Employee', {
+ from_date: function(frm, cdt, cdn) {
+ validate_date(frm, cdt, cdn);
+ },
+ to_date: function(frm, cdt, cdn) {
+ validate_date(frm, cdt, cdn);
+ }
+});
+
+var validate_date = function(frm, cdt, cdn) {
+ var doc = locals[cdt][cdn];
+ if(doc.to_date && doc.from_date) {
+ var from_date = frappe.datetime.str_to_obj(doc.from_date);
+ var to_date = frappe.datetime.str_to_obj(doc.to_date);
+
+ if(to_date < from_date) {
+ frappe.model.set_value(cdt, cdn, "to_date", "");
+ frappe.throw(__("From Date cannot be greater than To Date"));
+ }
+ }
+}
+
cur_frm.cscript.amount = function(doc, cdt, cdn){
calculate_totals(doc, cdt, cdn);
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py
index d3b7c5a498..158c4433d5 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.py
+++ b/erpnext/manufacturing/doctype/production_order/production_order.py
@@ -64,7 +64,7 @@ class ProductionOrder(Document):
so.name, so_item.delivery_date, so.project
from
`tabSales Order` so, `tabSales Order Item` so_item, `tabPacked Item` packed_item
- where so.name=%s
+ where so.name=%s
and so.name=so_item.parent
and so.name=packed_item.parent
and so_item.item_code = packed_item.parent_item
@@ -88,7 +88,7 @@ class ProductionOrder(Document):
self.wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse")
if not self.fg_warehouse:
self.fg_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_fg_warehouse")
-
+
def validate_warehouse_belongs_to_company(self):
warehouses = [self.fg_warehouse, self.wip_warehouse]
for d in self.get("required_items"):
@@ -524,7 +524,7 @@ def get_item_details(item, project = None):
if not res["bom_no"]:
if project:
res = get_item_details(item)
- frappe.msgprint(_("Default BOM not found for Item {0} and Project {1}").format(item, project))
+ frappe.msgprint(_("Default BOM not found for Item {0} and Project {1}").format(item, project), alert=1)
else:
frappe.throw(_("Default BOM for {0} not found").format(item))
@@ -642,5 +642,5 @@ def query_sales_order(production_item):
select distinct so.name from `tabSales Order` so, `tabPacked Item` pi_item
where pi_item.parent=so.name and pi_item.item_code=%s and so.docstatus=1
""", (production_item, production_item))
-
+
return out
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 8812d8e821..e56c0912e8 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -122,6 +122,7 @@ class Company(Document):
if not wh_detail["is_group"] else ""
})
warehouse.flags.ignore_permissions = True
+ warehouse.flags.ignore_mandatory = True
warehouse.insert()
def create_default_accounts(self):
diff --git a/erpnext/setup/setup_wizard/operations/company_setup.py b/erpnext/setup/setup_wizard/operations/company_setup.py
index 7fe7f0c2bc..7f9795bcfd 100644
--- a/erpnext/setup/setup_wizard/operations/company_setup.py
+++ b/erpnext/setup/setup_wizard/operations/company_setup.py
@@ -113,8 +113,7 @@ def create_logo(args):
" {1}".format(fileurl, args.get("company_name") ))
def create_website(args):
- if args.get('setup_website'):
- website_maker(args)
+ website_maker(args)
def get_fy_details(fy_start_date, fy_end_date):
start_year = getdate(fy_start_date).year
diff --git a/erpnext/setup/setup_wizard/operations/default_website.py b/erpnext/setup/setup_wizard/operations/default_website.py
index d13767648d..8ca213b1a0 100644
--- a/erpnext/setup/setup_wizard/operations/default_website.py
+++ b/erpnext/setup/setup_wizard/operations/default_website.py
@@ -12,7 +12,7 @@ class website_maker(object):
self.args = args
self.company = args.company_name
self.tagline = args.company_tagline
- self.user = args.name
+ self.user = args.get('email')
self.make_web_page()
self.make_website_settings()
self.make_blog()
@@ -50,6 +50,17 @@ class website_maker(object):
website_settings.save()
def make_blog(self):
+ blog_category = frappe.get_doc({
+ "doctype": "Blog Category",
+ "category_name": "general",
+ "published": 1,
+ "title": _("General")
+ }).insert()
+
+ if not self.user:
+ # Admin setup
+ return
+
blogger = frappe.new_doc("Blogger")
user = frappe.get_doc("User", self.user)
blogger.user = self.user
@@ -58,13 +69,6 @@ class website_maker(object):
blogger.avatar = user.user_image
blogger.insert()
- blog_category = frappe.get_doc({
- "doctype": "Blog Category",
- "category_name": "general",
- "published": 1,
- "title": _("General")
- }).insert()
-
frappe.get_doc({
"doctype": "Blog Post",
"title": "Welcome",
diff --git a/erpnext/templates/pages/home.html b/erpnext/templates/pages/home.html
index 750fa3849f..f36b4e0817 100644
--- a/erpnext/templates/pages/home.html
+++ b/erpnext/templates/pages/home.html
@@ -18,7 +18,8 @@
- {{ product_image_square(item.thumbnail or item.image) }}
+
+ {{ product_image_square(item.image) }}
{{ item.item_name }}