Resolved merge conflicts
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 356e9af..2dfd6e1 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.42'
+__version__ = '10.1.43'
def get_default_company(user=None):
'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py
index 43a0d01..b67b61c 100755
--- a/erpnext/accounts/doctype/sales_invoice/pos.py
+++ b/erpnext/accounts/doctype/sales_invoice/pos.py
@@ -573,5 +573,6 @@
name_list.append(name)
except Exception:
frappe.log_error(frappe.get_traceback())
+ frappe.db.rollback()
return name_list
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 7f1a660..3d261d4 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -15,6 +15,7 @@
"engine": "InnoDB",
"fields": [
{
+<<<<<<< HEAD
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
@@ -681,6 +682,66 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_21",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 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_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "eval: doc.is_return && doc.return_against",
+ "fieldname": "update_billed_amount_in_sales_order",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Update Billed Amount in Sales Order",
+ "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_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 0f2a4d5..2c4125f 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -128,7 +128,7 @@
self.check_prev_docstatus()
- if self.is_return:
+ if self.is_return and not self.update_billed_amount_in_sales_order:
# NOTE status updating bypassed for is_return
self.status_updater = []
@@ -185,7 +185,7 @@
if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
unlink_ref_doc_from_payment_entries(self)
- if self.is_return:
+ if self.is_return and not self.update_billed_amount_in_sales_order:
# NOTE status updating bypassed for is_return
self.status_updater = []
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 2cfca24..b1b3260 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -21,18 +21,20 @@
class DuplicatePartyAccountError(frappe.ValidationError): pass
@frappe.whitelist()
-def get_party_details(party=None, account=None, party_type="Customer", company=None,
- posting_date=None, bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False):
+def get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None,
+ bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False, fetch_payment_terms_template=True):
if not party:
return {}
if not frappe.db.exists(party_type, party):
frappe.throw(_("{0}: {1} does not exists").format(party_type, party))
return _get_party_details(party, account, party_type,
- company, posting_date, bill_date, price_list, currency, doctype, ignore_permissions)
+ company, posting_date, bill_date, price_list, currency, doctype, ignore_permissions, fetch_payment_terms_template)
-def _get_party_details(party=None, account=None, party_type="Customer", company=None,
- posting_date=None, bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False):
+def _get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None,
+ bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False, fetch_payment_terms_template=True):
+
+ out = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, doctype))
out = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype))
party = out[party_type.lower()]
@@ -50,6 +52,11 @@
set_other_values(out, party, party_type)
set_price_list(out, party, party_type, price_list)
+ out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_type)
+
+ if fetch_payment_terms_template:
+ out["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
+
if not out.get("currency"):
out["currency"] = currency
@@ -282,6 +289,7 @@
if (bill_date or posting_date) and party:
due_date = bill_date or posting_date
template_name = get_pyt_term_template(party, party_type, company)
+
if template_name:
due_date = get_due_date_from_template(template_name, posting_date, bill_date).strftime("%Y-%m-%d")
else:
@@ -315,11 +323,14 @@
due_date = max(due_date, add_months(get_last_day(due_date), term.credit_months))
return due_date
-def validate_due_date(posting_date, due_date, party_type, party, company=None, bill_date=None):
+def validate_due_date(posting_date, due_date, party_type, party, company=None, bill_date=None, template_name=None):
if getdate(due_date) < getdate(posting_date):
frappe.throw(_("Due Date cannot be before Posting Date"))
else:
- default_due_date = get_due_date(posting_date, party_type, party, company, bill_date)
+ if not template_name: return
+
+ default_due_date = get_due_date_from_template(template_name, posting_date, bill_date).strftime("%Y-%m-%d")
+
if not default_due_date:
return
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py
index 60252ea..2b0d5e7 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/gross_profit.py
@@ -169,7 +169,7 @@
row.qty += returned_item_row.qty
row.base_amount += returned_item_row.base_amount
row.buying_amount = row.qty * row.buying_rate
- if row.qty:
+ if row.qty or row.base_amount:
row = self.set_average_rate(row)
self.grouped_data.append(row)
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 2021ddd..58b96ff 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -31,6 +31,14 @@
}
};
});
+
+ frm.set_query("cost_center", function() {
+ return {
+ "filters": {
+ "company": frm.doc.company,
+ }
+ };
+ });
},
refresh: function(frm) {
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index 1da8760..6b6518d 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -483,6 +483,37 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Cost Center",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Cost Center",
+ "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_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "department",
"fieldtype": "Link",
"hidden": 0,
@@ -1848,7 +1879,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-06-18 19:20:27.668745",
+ "modified": "2018-07-17 06:30:25.506194",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index 8111dae..446066c 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -38,6 +38,8 @@
depreciation_cost_center, depreciation_series = frappe.db.get_value("Company", asset.company,
["depreciation_cost_center", "series_for_depreciation_entry"])
+ depreciation_cost_center = asset.cost_center or depreciation_cost_center
+
for d in asset.get("schedules"):
if not d.journal_entry and getdate(d.schedule_date) <= getdate(date):
je = frappe.new_doc("Journal Entry")
@@ -156,6 +158,7 @@
def get_gl_entries_on_asset_disposal(asset, selling_amount=0):
fixed_asset_account, accumulated_depr_account, depr_expense_account = get_depreciation_accounts(asset)
disposal_account, depreciation_cost_center = get_disposal_account_and_cost_center(asset.company)
+ depreciation_cost_center = asset.cost_center or depreciation_cost_center
accumulated_depr_amount = flt(asset.gross_purchase_amount) - flt(asset.value_after_depreciation)
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json
index add0fd5..45b22d9 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.json
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.json
@@ -265,41 +265,7 @@
"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,
- "columns": 0,
- "default": "0",
- "description": "If enabled, last purchase details of items will not be fetched from previous purchase order or purchase receipt",
- "fieldname": "disable_fetch_last_purchase_rate",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Disable Fetching Last Purchase Details in Purchase Order",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -378,7 +344,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-06-12 03:41:41.739193",
+ "modified": "2018-07-18 07:52:38.062488",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index bc5472f..ea5c6f7 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -53,12 +53,7 @@
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});
-
- if (frm.doc.__onload) {
- frm.toggle_display('get_last_purchase_rate',
- frm.doc.__onload.disable_fetch_last_purchase_rate);
- }
- },
+ }
});
frappe.ui.form.on("Purchase Order Item", {
@@ -339,6 +334,73 @@
})
}, __("Add items from"));
+ this.frm.add_custom_button(__('Update rate as per last purchase'),
+ function() {
+ frappe.call({
+ "method": "get_last_purchase_rate",
+ "doc": me.frm.doc,
+ callback: function(r, rt) {
+ me.frm.dirty();
+ me.frm.cscript.calculate_taxes_and_totals();
+ }
+ })
+ }, __("Tools"));
+
+ this.frm.add_custom_button(__('Link to Material Request'),
+ function() {
+ var my_items = [];
+ for (var i in me.frm.doc.items) {
+ if(!me.frm.doc.items[i].material_request){
+ my_items.push(me.frm.doc.items[i].item_code);
+ }
+ }
+ frappe.call({
+ method: "erpnext.buying.utils.get_linked_material_requests",
+ args:{
+ items: my_items
+ },
+ callback: function(r) {
+ if(r.exc) return;
+
+ var i = 0;
+ var item_length = me.frm.doc.items.length;
+ while (i < item_length) {
+ var qty = me.frm.doc.items[i].qty;
+ (r.message[0] || []).forEach(function(d) {
+ if (d.qty > 0 && qty > 0 && me.frm.doc.items[i].item_code == d.item_code && !me.frm.doc.items[i].material_request_item)
+ {
+ me.frm.doc.items[i].material_request = d.mr_name;
+ me.frm.doc.items[i].material_request_item = d.mr_item;
+ var my_qty = Math.min(qty, d.qty);
+ qty = qty - my_qty;
+ d.qty = d.qty - my_qty;
+ me.frm.doc.items[i].stock_qty = my_qty * me.frm.doc.items[i].conversion_factor;
+ me.frm.doc.items[i].qty = my_qty;
+
+ frappe.msgprint("Assigning " + d.mr_name + " to " + d.item_code + " (row " + me.frm.doc.items[i].idx + ")");
+ if (qty > 0) {
+ frappe.msgprint("Splitting " + qty + " units of " + d.item_code);
+ var new_row = frappe.model.add_child(me.frm.doc, me.frm.doc.items[i].doctype, "items");
+ item_length++;
+
+ for (var key in me.frm.doc.items[i]) {
+ new_row[key] = me.frm.doc.items[i][key];
+ }
+
+ new_row.idx = item_length;
+ new_row["stock_qty"] = new_row.conversion_factor * qty;
+ new_row["qty"] = qty;
+ new_row["material_request"] = "";
+ new_row["material_request_item"] = "";
+ }
+ }
+ });
+ i++;
+ }
+ refresh_field("items");
+ }
+ });
+ }, __("Tools"));
},
tc_name: function() {
@@ -367,17 +429,6 @@
cur_frm.cscript.update_status('Deliver', 'Delivered')
},
- get_last_purchase_rate: function() {
- frappe.call({
- "method": "get_last_purchase_rate",
- "doc": cur_frm.doc,
- callback: function(r, rt) {
- cur_frm.dirty();
- cur_frm.cscript.calculate_taxes_and_totals();
- }
- })
- },
-
items_on_form_rendered: function() {
set_schedule_date(this.frm);
},
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index c6fb2a1..8286885 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -1426,72 +1426,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "depends_on": "eval:doc.docstatus===0 && (doc.items && doc.items.length)",
- "fieldname": "get_last_purchase_rate",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Get last purchase rate",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.docstatus===0 && (doc.items && doc.items.length)",
- "fieldname": "link_to_mrs",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Link to material requests",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "sb_last_purchase",
"fieldtype": "Section Break",
"hidden": 0,
@@ -3737,7 +3671,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-07-17 11:00:05.037716",
+ "modified": "2018-07-18 07:49:53.131408",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 5b8204a..b63c256 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -36,12 +36,6 @@
'percent_join_field': 'material_request'
}]
- def onload(self):
- super(PurchaseOrder, self).onload()
-
- self.set_onload('disable_fetch_last_purchase_rate',
- cint(frappe.db.get_single_value("Buying Settings", "disable_fetch_last_purchase_rate")))
-
def validate(self):
super(PurchaseOrder, self).validate()
@@ -125,7 +119,6 @@
def get_last_purchase_rate(self):
"""get last purchase rates for all items"""
- if cint(frappe.db.get_single_value("Buying Settings", "disable_fetch_last_purchase_rate")): return
conversion_rate = flt(self.get('conversion_rate')) or 1.0
for d in self.get("items"):
@@ -303,7 +296,6 @@
def item_last_purchase_rate(name, conversion_rate, item_code, conversion_factor= 1.0):
"""get last purchase rate for an item"""
- if cint(frappe.db.get_single_value("Buying Settings", "disable_fetch_last_purchase_rate")): return
conversion_rate = flt(conversion_rate) or 1.0
diff --git a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_last_purchase_rate.js b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_last_purchase_rate.js
deleted file mode 100644
index 8ccf1b6..0000000
--- a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_last_purchase_rate.js
+++ /dev/null
@@ -1,156 +0,0 @@
-QUnit.module('Buying');
-
-QUnit.test("test: purchase order with last purchase rate", function(assert) {
- assert.expect(9);
- let done = assert.async();
-
- frappe.run_serially([
- () => {
- return frappe.tests.make('Purchase Order', [
- {supplier: 'Test Supplier'},
- {is_subcontracted: 'No'},
- {currency: 'INR'},
- {items: [
- [
- {"item_code": 'Test Product 4'},
- {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
- {"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
- {"qty": 1},
- {"rate": 800},
- {"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
- ],
- [
- {"item_code": 'Test Product 1'},
- {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
- {"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
- {"qty": 1},
- {"rate": 400},
- {"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
- ]
- ]}
- ]);
- },
-
- () => {
- // Get item details
- assert.ok(cur_frm.doc.items[0].item_name == 'Test Product 4', "Item 1 name correct");
- assert.ok(cur_frm.doc.items[1].item_name == 'Test Product 1', "Item 2 name correct");
- },
-
- () => frappe.timeout(1),
-
- () => frappe.tests.click_button('Submit'),
- () => frappe.tests.click_button('Yes'),
- () => frappe.timeout(3),
-
- () => frappe.tests.click_button('Close'),
- () => frappe.timeout(1),
-
- () => {
- return frappe.tests.make('Purchase Order', [
- {supplier: 'Test Supplier'},
- {is_subcontracted: 'No'},
- {currency: 'INR'},
- {items: [
- [
- {"item_code": 'Test Product 4'},
- {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
- {"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
- {"qty": 1},
- {"rate": 600},
- {"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
- ],
- [
- {"item_code": 'Test Product 1'},
- {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
- {"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
- {"qty": 1},
- {"rate": 200},
- {"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
- ]
- ]}
- ]);
- },
-
- () => frappe.timeout(2),
-
- // Get the last purchase rate of items
- () => {
- assert.ok(cur_frm.doc.items[0].last_purchase_rate == 800, "Last purchase rate of item 1 correct");
- assert.ok(cur_frm.doc.items[1].last_purchase_rate != 0);
- },
- () => {
- assert.ok(cur_frm.doc.items[1].last_purchase_rate == 400, "Last purchase rate of item 2 correct");
- assert.ok(cur_frm.doc.items[1].last_purchase_rate != 0);
- },
-
- () => frappe.tests.click_button('Submit'),
- () => frappe.tests.click_button('Yes'),
- () => frappe.timeout(3),
-
- () => frappe.tests.click_button('Close'),
-
- () => frappe.timeout(1),
-
- () => {
- assert.ok(cur_frm.doc.status == 'To Receive and Bill', "Submitted successfully");
- },
-
- // enable allow_last_purchase_rate
- () => {
- return frappe.tests.make('Buying Settings', [
- // values to be set
- {"disable_fetch_last_purchase_rate": 1}
- ]);
- },
-
- () => {
- return frappe.tests.make('Purchase Order', [
- {supplier: 'Test Supplier'},
- {is_subcontracted: 'No'},
- {currency: 'INR'},
- {items: [
- [
- {"item_code": 'Test Product 4'},
- {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
- {"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
- {"qty": 1},
- {"rate": 800},
- {"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
- ],
- [
- {"item_code": 'Test Product 1'},
- {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
- {"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
- {"qty": 1},
- {"rate": 400},
- {"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
- ]
- ]}
- ]);
- },
-
- () => {
- // Get item details
- assert.ok(cur_frm.doc.items[0].last_purchase_rate == 0);
- assert.ok(cur_frm.doc.items[1].last_purchase_rate == 0);
- },
-
- () => frappe.timeout(1),
-
- () => frappe.tests.click_button('Submit'),
- () => frappe.tests.click_button('Yes'),
- () => frappe.timeout(3),
-
- () => frappe.tests.click_button('Close'),
- () => frappe.timeout(1),
-
- // enable allow_last_purchase_rate
- () => frappe.tests.make('Buying Settings', [
- // values to be set
- {"disable_fetch_last_purchase_rate": 0}
- ]),
-
- () => done()
- ]);
-});
\ No newline at end of file
diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
index e49f6c4..2623078 100755
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
@@ -723,7 +723,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
- "read_only": 0,
+ "read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@@ -2309,7 +2309,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2018-06-15 13:05:44.702506",
+ "modified": "2018-07-18 07:53:54.677844",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",
diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py
index b87f4bc..0c7b122 100644
--- a/erpnext/config/hr.py
+++ b/erpnext/config/hr.py
@@ -43,6 +43,16 @@
},
{
"type": "doctype",
+ "name": "Job Opening",
+ "description": _("Opening for a Job."),
+ },
+ {
+ "type": "doctype",
+ "name": "Job Applicant",
+ "description": _("Applicant for a Job."),
+ },
+ {
+ "type": "doctype",
"name": "Leave Application",
},
{
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index fe8e34e..b8fa0ec 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -165,9 +165,11 @@
if not self.due_date:
frappe.throw(_("Due Date is mandatory"))
- validate_due_date(self.posting_date, self.due_date, "Customer", self.customer, self.company)
+ validate_due_date(self.posting_date, self.due_date,
+ "Customer", self.customer, self.company, self.payment_terms_template)
elif self.doctype == "Purchase Invoice":
- validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier, self.company, self.bill_date)
+ validate_due_date(self.posting_date, self.due_date,
+ "Supplier", self.supplier, self.company, self.bill_date, self.payment_terms_template)
def set_price_list_currency(self, buying_or_selling):
if self.meta.get_field("posting_date"):
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 3451c62..a1e2919 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -52,9 +52,15 @@
def set_missing_lead_customer_details(self):
if getattr(self, "customer", None):
from erpnext.accounts.party import _get_party_details
+ fetch_payment_terms_template = False
+ if (self.get("__islocal") or
+ self.company != frappe.db.get_value(self.doctype, self.name, 'company')):
+ fetch_payment_terms_template = True
+
party_details = _get_party_details(self.customer,
ignore_permissions=self.flags.ignore_permissions,
- doctype=self.doctype, company=self.company)
+ doctype=self.doctype, company=self.company,
+ fetch_payment_terms_template=fetch_payment_terms_template)
if not self.meta.get_field("sales_team"):
party_details.pop("sales_team")
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index 7d80817..ed44d63 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -24,6 +24,7 @@
]
for leave_type in leave_types:
+ columns.append(_(leave_type) + " " + _("Opening") + ":Float:160")
columns.append(_(leave_type) + " " + _("Taken") + ":Float:160")
columns.append(_(leave_type) + " " + _("Balance") + ":Float:160")
@@ -32,6 +33,7 @@
def get_data(filters, leave_types):
user = frappe.session.user
allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date)
+ allocation_records_based_on_from_date = get_leave_allocation_records(filters.from_date)
active_employees = frappe.get_all("Employee",
filters = { "status": "Active", "company": filters.company},
@@ -47,12 +49,16 @@
# leaves taken
leaves_taken = get_approved_leaves_for_period(employee.name, leave_type,
filters.from_date, filters.to_date)
-
+
+ # opening balance
+ opening = get_leave_balance_on(employee.name, leave_type, filters.from_date,
+ allocation_records_based_on_from_date.get(employee.name, frappe._dict()))
+
# closing balance
closing = get_leave_balance_on(employee.name, leave_type, filters.to_date,
allocation_records_based_on_to_date.get(employee.name, frappe._dict()))
- row += [leaves_taken, closing]
+ row += [opening, leaves_taken, closing]
data.append(row)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index f66f2a2..a9958cb 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -267,7 +267,6 @@
erpnext.patches.v6_27.fix_recurring_order_status
erpnext.patches.v6_20x.update_product_bundle_description
erpnext.patches.v7_0.update_party_status #2016-09-22
-erpnext.patches.v7_0.update_item_projected
erpnext.patches.v7_0.remove_features_setup
erpnext.patches.v7_0.update_home_page
execute:frappe.delete_doc_if_exists("Page", "financial-analytics")
@@ -560,3 +559,4 @@
erpnext.patches.v11_0.update_allow_transfer_for_manufacture
erpnext.patches.v11_0.rename_healthcare_doctype_and_fields
erpnext.patches.v11_0.add_item_group_defaults
+erpnext.patches.v10_0.update_address_template_for_india
diff --git a/erpnext/patches/v10_0/update_address_template_for_india.py b/erpnext/patches/v10_0/update_address_template_for_india.py
new file mode 100644
index 0000000..5897b43
--- /dev/null
+++ b/erpnext/patches/v10_0/update_address_template_for_india.py
@@ -0,0 +1,12 @@
+# Copyright (c) 2017, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from erpnext.regional.india.setup import update_address_template
+
+def execute():
+ if frappe.db.get_value('Company', {'country': 'India'}, 'name'):
+ address_template = frappe.db.get_value('Address Template', 'India', 'template')
+ if not address_template or "gstin" not in address_template:
+ update_address_template()
diff --git a/erpnext/patches/v7_0/repost_bin_qty_and_item_projected_qty.py b/erpnext/patches/v7_0/repost_bin_qty_and_item_projected_qty.py
index 5d76304..a5cf22c 100644
--- a/erpnext/patches/v7_0/repost_bin_qty_and_item_projected_qty.py
+++ b/erpnext/patches/v7_0/repost_bin_qty_and_item_projected_qty.py
@@ -9,7 +9,7 @@
def repost_bin_qty():
for bin in frappe.db.sql(""" select name from `tabBin`
- where (actual_qty + ordered_qty + indented_qty + planned_qty- reserved_qty - reserved_qty_for_production) != projected_qty """, as_dict=1):
+ where (actual_qty + ordered_qty + indented_qty + planned_qty - reserved_qty - reserved_qty_for_production - reserved_qty_for_sub_contract) != projected_qty """, as_dict=1):
bin_doc = frappe.get_doc('Bin', bin.name)
bin_doc.set_projected_qty()
bin_doc.db_set("projected_qty", bin_doc.projected_qty, update_modified = False)
diff --git a/erpnext/patches/v7_0/update_item_projected.py b/erpnext/patches/v7_0/update_item_projected.py
deleted file mode 100644
index 71b54af..0000000
--- a/erpnext/patches/v7_0/update_item_projected.py
+++ /dev/null
@@ -1,7 +0,0 @@
-import frappe
-
-def execute():
- frappe.reload_doctype("Item")
- from erpnext.stock.doctype.bin.bin import update_item_projected_qty
- for item in frappe.get_all("Item", filters={"is_stock_item": 1}):
- update_item_projected_qty(item.name)
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index a80ffa8..e420a48 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -226,62 +226,6 @@
tc_name: function() {
this.get_terms();
},
- link_to_mrs: function() {
- var my_items = [];
- for (var i in cur_frm.doc.items) {
- if(!cur_frm.doc.items[i].material_request){
- my_items.push(cur_frm.doc.items[i].item_code);
- }
- }
- frappe.call({
- method: "erpnext.buying.utils.get_linked_material_requests",
- args:{
- items: my_items
- },
- callback: function(r) {
- if(r.exc || !r.message) return;
-
- var i = 0;
- var item_length = cur_frm.doc.items.length;
- while (i < item_length) {
- var qty = cur_frm.doc.items[i].qty;
- (r.message[0] || []).forEach(function(d) {
- if (d.qty > 0 && qty > 0 && cur_frm.doc.items[i].item_code == d.item_code && !cur_frm.doc.items[i].material_request_item)
- {
- cur_frm.doc.items[i].material_request = d.mr_name;
- cur_frm.doc.items[i].material_request_item = d.mr_item;
- var my_qty = Math.min(qty, d.qty);
- qty = qty - my_qty;
- d.qty = d.qty - my_qty;
- cur_frm.doc.items[i].stock_qty = my_qty*cur_frm.doc.items[i].conversion_factor;
- cur_frm.doc.items[i].qty = my_qty;
-
- frappe.msgprint(__("Assigning {0} to {1} (row {2})",
- [d.mr_name, d.item_code, cur_frm.doc.items[i].idx]));
-
- if (qty > 0) {
- frappe.msgprint(__("Splitting {0} units of {1}", [qty, d.item_code]));
- var newrow = frappe.model.add_child(cur_frm.doc, cur_frm.doc.items[i].doctype, "items");
- item_length++;
-
- for (var key in cur_frm.doc.items[i]) {
- newrow[key] = cur_frm.doc.items[i][key];
- }
-
- newrow.idx = item_length;
- newrow["stock_qty"] = newrow.conversion_factor*qty;
- newrow["qty"] = qty;
- newrow["material_request"] = "";
- newrow["material_request_item"] = "";
- }
- }
- });
- i++;
- }
- refresh_field("items");
- }
- });
- },
update_auto_repeat_reference: function(doc) {
if (doc.auto_repeat) {
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index a3993b8..f2919fb 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -56,6 +56,21 @@
si1 = make_sales_invoice(so.name)
self.assertEqual(len(si1.get("items")), 0)
+ def test_so_billed_amount_against_return_entry(self):
+ from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_sales_return
+ so = make_sales_order(do_not_submit=True)
+ so.submit()
+
+ si = make_sales_invoice(so.name)
+ si.insert()
+ si.submit()
+
+ si1 = make_sales_return(si.name)
+ si1.update_billed_amount_in_sales_order = 1
+ si1.submit()
+ so.load_from_db()
+ self.assertEquals(so.per_billed, 0)
+
def test_make_sales_invoice_with_terms(self):
so = make_sales_order(do_not_submit=True)
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 430617f..85b10dd 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -374,7 +374,7 @@
path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(company_doc.country))
if os.path.exists(path.encode("utf-8")):
frappe.get_attr("erpnext.regional.{0}.setup.setup"
- .format(frappe.scrub(company_doc.country)))(company_doc)
+ .format(frappe.scrub(company_doc.country)))(company_doc, False)
def update_company_current_month_sales(company):
current_month_year = formatdate(today(), "MM-yyyy")
diff --git a/erpnext/setup/doctype/naming_series/naming_series.py b/erpnext/setup/doctype/naming_series/naming_series.py
index 2d2a18b..54c5d17 100644
--- a/erpnext/setup/doctype/naming_series/naming_series.py
+++ b/erpnext/setup/doctype/naming_series/naming_series.py
@@ -34,7 +34,14 @@
if options:
prefixes = prefixes + "\n" + options
prefixes.replace("\n\n", "\n")
- prefixes = "\n".join(sorted(prefixes.split("\n")))
+ prefixes = prefixes.split("\n")
+
+ custom_prefixes = frappe.get_all('DocType', fields=["autoname"],
+ filters={"name": ('not in', doctypes), "autoname":('like', '%.#%'), 'module': ('not in', ['Core'])})
+ if custom_prefixes:
+ prefixes = prefixes + [d.autoname.rsplit('.', 1)[0] for d in custom_prefixes]
+
+ prefixes = "\n".join(sorted(prefixes))
return {
"transactions": "\n".join([''] + sorted(doctypes)),
diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py
index 250d377..d86ac5e 100644
--- a/erpnext/setup/utils.py
+++ b/erpnext/setup/utils.py
@@ -115,7 +115,7 @@
if not value:
import requests
- api_url = "https://exchangeratesapi.io/api/{0}".format(transaction_date)
+ api_url = "https://frankfurter.erpnext.org/{0}".format(transaction_date)
response = requests.get(api_url, params={
"base": from_currency,
"symbols": to_currency
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 77f5f41..bd3577f 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -58,7 +58,7 @@
item.current_valuation_rate = rate
self.difference_amount += (flt(item.qty, item.precision("qty")) * \
flt(item.valuation_rate or rate, item.precision("valuation_rate")) \
- - flt(qty) * flt(rate))
+ - flt(qty, item.precision("qty")) * flt(rate, item.precision("valuation_rate")))
return True
items = filter(lambda d: _changed(d), self.items)
@@ -246,7 +246,9 @@
def set_total_qty_and_amount(self):
for d in self.get("items"):
d.amount = flt(d.qty, d.precision("qty")) * flt(d.valuation_rate, d.precision("valuation_rate"))
- d.current_amount = flt(d.current_qty) * flt(d.current_valuation_rate)
+ d.current_amount = (flt(d.current_qty,
+ d.precision("current_qty")) * flt(d.current_valuation_rate, d.precision("current_valuation_rate")))
+
d.quantity_difference = flt(d.qty) - flt(d.current_qty)
d.amount_difference = flt(d.amount) - flt(d.current_amount)
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index 69abeeb..774803f 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -23,32 +23,33 @@
data = []
for (company, item, warehouse) in sorted(iwb_map):
- qty_dict = iwb_map[(company, item, warehouse)]
- item_reorder_level = 0
- item_reorder_qty = 0
- if item + warehouse in item_reorder_detail_map:
- item_reorder_level = item_reorder_detail_map[item + warehouse]["warehouse_reorder_level"]
- item_reorder_qty = item_reorder_detail_map[item + warehouse]["warehouse_reorder_qty"]
+ if item_map.get(item):
+ qty_dict = iwb_map[(company, item, warehouse)]
+ item_reorder_level = 0
+ item_reorder_qty = 0
+ if item + warehouse in item_reorder_detail_map:
+ item_reorder_level = item_reorder_detail_map[item + warehouse]["warehouse_reorder_level"]
+ item_reorder_qty = item_reorder_detail_map[item + warehouse]["warehouse_reorder_qty"]
- report_data = [item, item_map[item]["item_name"],
- item_map[item]["item_group"],
- item_map[item]["brand"],
- item_map[item]["description"], warehouse,
- item_map[item]["stock_uom"], qty_dict.opening_qty,
- qty_dict.opening_val, qty_dict.in_qty,
- qty_dict.in_val, qty_dict.out_qty,
- qty_dict.out_val, qty_dict.bal_qty,
- qty_dict.bal_val, qty_dict.val_rate,
- item_reorder_level,
- item_reorder_qty,
- company
- ]
+ report_data = [item, item_map[item]["item_name"],
+ item_map[item]["item_group"],
+ item_map[item]["brand"],
+ item_map[item]["description"], warehouse,
+ item_map[item]["stock_uom"], qty_dict.opening_qty,
+ qty_dict.opening_val, qty_dict.in_qty,
+ qty_dict.in_val, qty_dict.out_qty,
+ qty_dict.out_val, qty_dict.bal_qty,
+ qty_dict.bal_val, qty_dict.val_rate,
+ item_reorder_level,
+ item_reorder_qty,
+ company
+ ]
- if filters.get('show_variant_attributes', 0) == 1:
- variants_attributes = get_variants_attributes()
- report_data += [item_map[item].get(i) for i in variants_attributes]
+ if filters.get('show_variant_attributes', 0) == 1:
+ variants_attributes = get_variants_attributes()
+ report_data += [item_map[item].get(i) for i in variants_attributes]
- data.append(report_data)
+ data.append(report_data)
if filters.get('show_variant_attributes', 0) == 1:
columns += ["{}:Data:100".format(i) for i in get_variants_attributes()]
@@ -202,12 +203,12 @@
item_details = {}
if not items:
items = list(set([d.item_code for d in sle]))
-
+
if items:
for item in frappe.db.sql("""
select name, item_name, description, item_group, brand, stock_uom
from `tabItem`
- where name in ({0})
+ where name in ({0}) and ifnull(disabled, 0) = 0
""".format(', '.join(['"' + frappe.db.escape(i, percent=False) + '"' for i in items])), as_dict=1):
item_details.setdefault(item.name, item)