Merge branch 'master' into staging-fixes
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 0d5ac9d..4197d54 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
-__version__ = '10.1.74'
+__version__ = '10.1.76'
def get_default_company(user=None):
'''Get default company for user'''
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index ed761ce..3c4ef2b 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -91,6 +91,7 @@
self.party_account_currency = get_party_account_currency("Supplier", self.supplier, self.company)
def validate_minimum_order_qty(self):
+ if not self.get("items"): return
items = list(set([d.item_code for d in self.get("items")]))
itemwise_min_order_qty = frappe._dict(frappe.db.sql("""select name, min_order_qty
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index ee6dc2a..541e56d 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -678,7 +678,7 @@
frappe.db.sql("delete from `tabSerial No` where purchase_document_no=%s", self.name)
def validate_schedule_date(self):
- if not self.schedule_date:
+ if not self.schedule_date and self.get("items"):
self.schedule_date = min([d.schedule_date for d in self.get("items")])
if self.schedule_date:
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index cb4c190..66d9bad 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -62,8 +62,8 @@
def validate_user_details(self):
data = frappe.db.get_value('User',
self.user_id, ['enabled', 'user_image'], as_dict=1)
-
- self.image = data.get("user_image")
+ if data.get("user_image"):
+ self.image = data.get("user_image")
self.validate_for_enabled_user_id(data.get("enabled", 0))
self.validate_duplicate_user_id()
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 3913178..de45ec3 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -258,13 +258,13 @@
self.total_purchase_cost = total_purchase_cost and total_purchase_cost[0][0] or 0
def update_sales_amount(self):
- total_sales_amount = frappe.db.sql("""select sum(base_grand_total)
+ total_sales_amount = frappe.db.sql("""select sum(base_net_total)
from `tabSales Order` where project = %s and docstatus=1""", self.name)
self.total_sales_amount = total_sales_amount and total_sales_amount[0][0] or 0
def update_billed_amount(self):
- total_billed_amount = frappe.db.sql("""select sum(base_grand_total)
+ total_billed_amount = frappe.db.sql("""select sum(base_net_total)
from `tabSales Invoice` where project = %s and docstatus=1""", self.name)
self.total_billed_amount = total_billed_amount and total_billed_amount[0][0] or 0
diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js
index 82d6f6e..9beba6a 100644
--- a/erpnext/public/js/setup_wizard.js
+++ b/erpnext/public/js/setup_wizard.js
@@ -97,6 +97,9 @@
if (!this.values.company_abbr) {
return false;
}
+ if (this.values.company_abbr.length > 5) {
+ return false;
+ }
return true;
}
},
diff --git a/erpnext/selling/README.md b/erpnext/selling/README.md
index db05132..d186133 100644
--- a/erpnext/selling/README.md
+++ b/erpnext/selling/README.md
@@ -1,6 +1,11 @@
-Selling management module. Includes forms for capturing / managing the sales process.
+Selling management module. Includes forms for capturing / managing the sales process:
+
+- Customer
+- Campaign
+- Quotation
+- Sales Order
+
+Moved to CRM Module:
- Lead
- Opportunity
-- Quotation
-- Sales Order
\ No newline at end of file
diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json
index 3b1c480..7ea8397 100644
--- a/erpnext/selling/doctype/quotation_item/quotation_item.json
+++ b/erpnext/selling/doctype/quotation_item/quotation_item.json
@@ -871,10 +871,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -993,6 +995,7 @@
"label": "Net Rate",
"length": 0,
"no_copy": 0,
+ "options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
@@ -1910,7 +1913,7 @@
"istable": 1,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2018-08-22 16:15:52.750381",
+ "modified": "2018-12-12 05:52:46.135944",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation Item",
@@ -1925,4 +1928,4 @@
"track_changes": 1,
"track_seen": 0,
"track_views": 0
-}
\ No newline at end of file
+}
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 9a35aed..229f4f6 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -623,7 +623,7 @@
def update_item(source, target, source_parent):
target.amount = flt(source.amount) - flt(source.billed_amt)
target.base_amount = target.amount * flt(source_parent.conversion_rate)
- target.qty = target.amount / flt(source.rate) if (source.rate and source.billed_amt) else source.qty
+ target.qty = target.amount / flt(source.rate) if (source.rate and source.billed_amt) else source.qty - source.returned_qty
if source_parent.project:
target.cost_center = frappe.db.get_value("Project", source_parent.project, "cost_center")
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index ab624d1..50996ed 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -391,8 +391,24 @@
return invoiced_qty_map
+def get_returned_qty_map(sales_orders):
+ """returns a map: {so_detail: returned_qty}"""
+ returned_qty_map = {}
+
+ for name, returned_qty in frappe.get_all('Sales Order Item', fields = ["name", "returned_qty"],
+ filters = {'parent': ('in', sales_orders), 'docstatus': 1}, as_list=1):
+ if not returned_qty_map.get(name):
+ returned_qty_map[name] = 0
+ returned_qty_map[name] += returned_qty
+
+ return returned_qty_map
+
@frappe.whitelist()
def make_sales_invoice(source_name, target_doc=None):
+ doc = frappe.get_doc('Delivery Note', source_name)
+ sales_orders = [d.against_sales_order for d in doc.items]
+ returned_qty_map = get_returned_qty_map(sales_orders)
+
invoiced_qty_map = get_invoiced_qty_map(source_name)
def set_missing_values(source, target):
@@ -412,7 +428,9 @@
target.update(get_fetch_values("Sales Invoice", 'company_address', target.company_address))
def update_item(source_doc, target_doc, source_parent):
- target_doc.qty = source_doc.qty - invoiced_qty_map.get(source_doc.name, 0)
+ target_doc.qty = (source_doc.qty -
+ invoiced_qty_map.get(source_doc.name, 0) - returned_qty_map.get(source_doc.so_detail, 0))
+
if source_doc.serial_no and source_parent.per_billed > 0:
target_doc.serial_no = get_delivery_note_serial_no(source_doc.item_code,
target_doc.qty, source_parent.name)
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_list.js b/erpnext/stock/doctype/delivery_note/delivery_note_list.js
index 6a50c5a..6fc51ec 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note_list.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note_list.js
@@ -1,7 +1,8 @@
frappe.listview_settings['Delivery Note'] = {
- add_fields: ["grand_total", "is_return", "per_billed", "status", "currency"],
- get_indicator: function (doc) {
- if (cint(doc.is_return) == 1) {
+ add_fields: ["customer", "customer_name", "base_grand_total", "per_installed", "per_billed",
+ "transporter_name", "grand_total", "is_return", "status", "currency"],
+ get_indicator: function(doc) {
+ if(cint(doc.is_return)==1) {
return [__("Return"), "darkgrey", "is_return,=,Yes"];
} else if (doc.status === "Closed") {
return [__("Closed"), "green", "status,=,Closed"];
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 026d83c..0c5a71c 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -636,6 +636,24 @@
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
set_perpetual_inventory(0, company)
+
+ def test_make_sales_invoice_from_dn_for_returned_qty(self):
+ from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
+ from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
+
+ so = make_sales_order(qty=2)
+ so.submit()
+
+ dn = make_delivery_note(so.name)
+ dn.submit()
+
+ dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-1, do_not_submit=True)
+ dn1.items[0].against_sales_order = so.name
+ dn1.items[0].so_detail = so.items[0].name
+ dn1.submit()
+
+ si = make_sales_invoice(dn.name)
+ self.assertEquals(si.items[0].qty, 1)
def create_delivery_note(**args):
dn = frappe.new_doc("Delivery Note")
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
index e1d5b08..e81f323 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
@@ -1,7 +1,8 @@
frappe.listview_settings['Purchase Receipt'] = {
- add_fields: ["is_return", "grand_total", "status", "per_billed"],
- get_indicator: function (doc) {
- if (cint(doc.is_return) == 1) {
+ add_fields: ["supplier", "supplier_name", "base_grand_total", "is_subcontracted",
+ "transporter_name", "is_return", "status", "per_billed", "currency"],
+ get_indicator: function(doc) {
+ if(cint(doc.is_return)==1) {
return [__("Return"), "darkgrey", "is_return,=,Yes"];
} else if (doc.status === "Closed") {
return [__("Closed"), "green", "status,=,Closed"];