Merge pull request #4174 from saurabh6790/shopping_cart
[fix] order.html rate display
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 5697b77..d4a5fa1 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -421,7 +421,7 @@
if self.bill_no:
if cint(frappe.db.get_single_value("Accounts Settings", "check_supplier_invoice_uniqueness")):
pi = frappe.db.exists("Purchase Invoice", {"bill_no": self.bill_no,
- "fiscal_year": self.fiscal_year, "name": ("!=", self.name)})
+ "fiscal_year": self.fiscal_year, "name": ("!=", self.name), "docstatus": ("<", 2)})
if pi:
frappe.throw("Supplier Invoice No exists in Purchase Invoice {0}".format(pi))
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 4b58b3c..2a9fa17 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -47,7 +47,7 @@
# from warehouse account
self.check_expense_account(detail)
-
+
gl_list.append(self.get_gl_dict({
"account": warehouse_account[sle.warehouse]["name"],
"against": detail.expense_account,
@@ -56,7 +56,7 @@
"debit": flt(sle.stock_value_difference, 2),
}, warehouse_account[sle.warehouse]["account_currency"]))
- # to target warehouse / expense account
+ # to target warehouse / expense account
gl_list.append(self.get_gl_dict({
"account": detail.expense_account,
"against": warehouse_account[sle.warehouse]["name"],
@@ -70,7 +70,7 @@
if warehouse_with_no_account:
msgprint(_("No accounting entries for the following warehouses") + ": \n" +
"\n".join(warehouse_with_no_account))
-
+
return process_gl_map(gl_list)
def get_voucher_details(self, default_expense_account, default_cost_center, sle_map):
@@ -223,7 +223,7 @@
if against_document and item_code:
incoming_rate = frappe.db.sql("""select abs(ifnull(stock_value_difference, 0) / actual_qty)
from `tabStock Ledger Entry`
- where voucher_type = %s and voucher_no = %s
+ where voucher_type = %s and voucher_no = %s
and item_code = %s and warehouse=%s limit 1""",
(self.doctype, against_document, item_code, warehouse))
incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
@@ -257,25 +257,25 @@
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 and flt(d.qty):
return_rate = 0
if cint(self.is_return) and self.return_against and self.docstatus==1:
- return_rate = self.get_incoming_rate_for_sales_return(d.item_code,
+ return_rate = self.get_incoming_rate_for_sales_return(d.item_code,
d.warehouse, self.return_against)
-
+
# On cancellation or if return entry submission, make stock ledger entry for
# target warehouse first, to update serial no values properly
- if d.warehouse and ((not cint(self.is_return) and self.docstatus==1)
+ if d.warehouse and ((not cint(self.is_return) and self.docstatus==1)
or (cint(self.is_return) and self.docstatus==2)):
sl_entries.append(self.get_sl_entries(d, {
"actual_qty": -1*flt(d.qty),
"incoming_rate": return_rate
}))
-
+
if d.target_warehouse:
target_warehouse_sle = self.get_sl_entries(d, {
"actual_qty": flt(d.qty),
"warehouse": d.target_warehouse
})
-
+
if self.docstatus == 1:
if not cint(self.is_return):
args = frappe._dict({
@@ -294,14 +294,14 @@
"outgoing_rate": return_rate
})
sl_entries.append(target_warehouse_sle)
-
- if d.warehouse and ((not cint(self.is_return) and self.docstatus==2)
+
+ if d.warehouse and ((not cint(self.is_return) and self.docstatus==2)
or (cint(self.is_return) and self.docstatus==1)):
sl_entries.append(self.get_sl_entries(d, {
"actual_qty": -1*flt(d.qty),
"incoming_rate": return_rate
}))
-
+
self.make_sl_entries(sl_entries)
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
@@ -374,7 +374,7 @@
def get_warehouse_account():
warehouse_account = frappe._dict()
-
+
for d in frappe.db.sql("""select warehouse, name, account_currency from tabAccount
where account_type = 'Warehouse' and ifnull(warehouse, '') != ''""", as_dict=1):
warehouse_account.setdefault(d.warehouse, d)
diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py
index 5480613..cb642f9 100644
--- a/erpnext/setup/utils.py
+++ b/erpnext/setup/utils.py
@@ -63,21 +63,30 @@
@frappe.whitelist()
def get_exchange_rate(from_currency, to_currency):
- try:
- cache = frappe.cache()
- key = "currency_exchange_rate:{0}:{1}".format(from_currency, to_currency)
- value = cache.get(key)
- if not value:
- import requests
- response = requests.get("http://api.fixer.io/latest", params={
- "base": from_currency,
- "symbols": to_currency
- })
- # expire in 24 hours
- response.raise_for_status()
- value = response.json()["rates"][to_currency]
- cache.setex(key, value, 24 * 60 * 60)
- return flt(value)
- except:
- exchange = "%s-%s" % (from_currency, to_currency)
- return flt(frappe.db.get_value("Currency Exchange", exchange, "exchange_rate"))
+ exchange = "%s-%s" % (from_currency, to_currency)
+ value = flt(frappe.db.get_value("Currency Exchange", exchange, "exchange_rate"))
+
+ if not value:
+ try:
+ cache = frappe.cache()
+ key = "currency_exchange_rate:{0}:{1}".format(from_currency, to_currency)
+ value = cache.get(key)
+
+ print value
+
+ if not value:
+ import requests
+ response = requests.get("http://api.fixer.io/latest", params={
+ "base": from_currency,
+ "symbols": to_currency
+ })
+ # expire in 24 hours
+ response.raise_for_status()
+ value = response.json()["rates"][to_currency]
+ cache.setex(key, value, 24 * 60 * 60)
+ return flt(value)
+ except:
+ frappe.msgprint(_("Unable to find exchange rate"))
+ return 0.0
+ else:
+ return value
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index af52c7a..760d63b 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -181,99 +181,99 @@
serial_no = frappe.get_doc("Serial No", serial_no)
for field, value in field_values.items():
self.assertEquals(cstr(serial_no.get(field)), value)
-
+
def test_sales_return_for_non_bundled_items(self):
set_perpetual_inventory()
-
+
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
-
+
actual_qty_0 = get_qty_after_transaction()
-
+
dn = create_delivery_note(qty=5, rate=500)
actual_qty_1 = get_qty_after_transaction()
self.assertEquals(actual_qty_0 - 5, actual_qty_1)
-
+
# outgoing_rate
- outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note",
+ outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note",
"voucher_no": dn.name}, "stock_value_difference") / 5
-
+
# return entry
dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-2, rate=500)
actual_qty_2 = get_qty_after_transaction()
-
+
self.assertEquals(actual_qty_1 + 2, actual_qty_2)
-
- incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
- {"voucher_type": "Delivery Note", "voucher_no": dn1.name},
+
+ incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
+ {"voucher_type": "Delivery Note", "voucher_no": dn1.name},
["incoming_rate", "stock_value_difference"])
-
+
self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
-
- gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
+
+ gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
"voucher_no": dn1.name, "account": "_Test Warehouse - _TC"}, "debit")
-
+
self.assertEquals(gle_warehouse_amount, stock_value_difference)
-
+
set_perpetual_inventory(0)
-
+
def test_return_single_item_from_bundled_items(self):
set_perpetual_inventory()
-
+
create_stock_reconciliation(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, rate=100)
- create_stock_reconciliation(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC",
+ create_stock_reconciliation(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC",
qty=50, rate=100)
-
+
dn = create_delivery_note(item_code="_Test Product Bundle Item", qty=5, rate=500)
# Qty after delivery
actual_qty_1 = get_qty_after_transaction()
self.assertEquals(actual_qty_1, 25)
-
+
# outgoing_rate
- outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note",
+ outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note",
"voucher_no": dn.name, "item_code": "_Test Item"}, "stock_value_difference") / 25
-
+
# return 'test item' from packed items
dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-10, rate=500)
# qty after return
actual_qty_2 = get_qty_after_transaction()
self.assertEquals(actual_qty_2, 35)
-
+
# Check incoming rate for return entry
- incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
- {"voucher_type": "Delivery Note", "voucher_no": dn1.name},
+ incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
+ {"voucher_type": "Delivery Note", "voucher_no": dn1.name},
["incoming_rate", "stock_value_difference"])
-
+
self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
-
+
# Check gl entry for warehouse
- gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
+ gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
"voucher_no": dn1.name, "account": "_Test Warehouse - _TC"}, "debit")
-
+
self.assertEquals(gle_warehouse_amount, stock_value_difference)
-
+
set_perpetual_inventory(0)
-
+
def test_return_entire_bundled_items(self):
set_perpetual_inventory()
-
+
create_stock_reconciliation(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, rate=100)
- create_stock_reconciliation(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC",
+ create_stock_reconciliation(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC",
qty=50, rate=100)
-
+
dn = create_delivery_note(item_code="_Test Product Bundle Item", qty=5, rate=500)
-
+
# return bundled item
- dn1 = create_delivery_note(item_code='_Test Product Bundle Item', is_return=1,
+ dn1 = create_delivery_note(item_code='_Test Product Bundle Item', is_return=1,
return_against=dn.name, qty=-2, rate=500)
# qty after return
actual_qty = get_qty_after_transaction()
self.assertEquals(actual_qty, 35)
-
+
# Check incoming rate for return entry
incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
{"voucher_type": "Delivery Note", "voucher_no": dn1.name},
@@ -284,11 +284,11 @@
# Check gl entry for warehouse
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
"voucher_no": dn1.name, "account": "_Test Warehouse - _TC"}, "debit")
-
+
self.assertEquals(gle_warehouse_amount, 1400)
-
+
set_perpetual_inventory(0)
-
+
def test_return_for_serialized_items(self):
se = make_serialized_item()
serial_no = get_serial_nos(se.get("items")[0].serial_no)[0]
@@ -301,65 +301,71 @@
})
# return entry
- dn1 = create_delivery_note(item_code="_Test Serialized Item With Series",
+ dn1 = create_delivery_note(item_code="_Test Serialized Item With Series",
is_return=1, return_against=dn.name, qty=-1, rate=500, serial_no=serial_no)
self.check_serial_no_values(serial_no, {
"warehouse": "_Test Warehouse - _TC",
"delivery_document_no": ""
})
-
+
dn1.cancel()
-
+
self.check_serial_no_values(serial_no, {
"warehouse": "",
"delivery_document_no": dn.name
})
-
+
dn.cancel()
-
+
self.check_serial_no_values(serial_no, {
"warehouse": "_Test Warehouse - _TC",
"delivery_document_no": "",
"purchase_document_no": se.name
})
-
+
def test_delivery_of_bundled_items_to_target_warehouse(self):
set_perpetual_inventory()
-
- create_stock_reconciliation(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, rate=100)
- create_stock_reconciliation(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC",
- qty=50, rate=100)
-
+ frappe.db.set_value("Item", "_Test Item", "valuation_method", "FIFO")
+
+ for warehouse in ("_Test Warehouse - _TC", "_Test Warehouse 1 - _TC"):
+ create_stock_reconciliation(item_code="_Test Item", target=warehouse,
+ qty=50, rate=100)
+ create_stock_reconciliation(item_code="_Test Item Home Desktop 100",
+ target=warehouse, qty=50, rate=100)
+
opening_qty_test_warehouse_1 = get_qty_after_transaction(warehouse="_Test Warehouse 1 - _TC")
-
- dn = create_delivery_note(item_code="_Test Product Bundle Item",
- qty=5, rate=500, target_warehouse="_Test Warehouse 1 - _TC")
-
+
+ dn = create_delivery_note(item_code="_Test Product Bundle Item",
+ qty=5, rate=500, target_warehouse="_Test Warehouse 1 - _TC", do_not_submit=True)
+
+ dn.submit()
+
# qty after delivery
actual_qty = get_qty_after_transaction(warehouse="_Test Warehouse - _TC")
self.assertEquals(actual_qty, 25)
-
+
actual_qty = get_qty_after_transaction(warehouse="_Test Warehouse 1 - _TC")
self.assertEquals(actual_qty, opening_qty_test_warehouse_1 + 25)
-
+
# stock value diff for source warehouse
- stock_value_difference = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note",
- "voucher_no": dn.name, "item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"},
+ stock_value_difference = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note",
+ "voucher_no": dn.name, "item_code": "_Test Item Home Desktop 100", "warehouse": "_Test Warehouse - _TC"},
"stock_value_difference")
-
+
# stock value diff for target warehouse
- stock_value_difference1 = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note",
- "voucher_no": dn.name, "item_code": "_Test Item", "warehouse": "_Test Warehouse 1 - _TC"},
+ stock_value_difference1 = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note",
+ "voucher_no": dn.name, "item_code": "_Test Item Home Desktop 100", "warehouse": "_Test Warehouse 1 - _TC"},
"stock_value_difference")
+
self.assertEquals(abs(stock_value_difference), stock_value_difference1)
# Check gl entries
gl_entries = get_gl_entries("Delivery Note", dn.name)
self.assertTrue(gl_entries)
- stock_value_difference = abs(frappe.db.sql("""select sum(stock_value_difference)
- from `tabStock Ledger Entry` where voucher_type='Delivery Note' and voucher_no=%s
+ stock_value_difference = abs(frappe.db.sql("""select sum(stock_value_difference)
+ from `tabStock Ledger Entry` where voucher_type='Delivery Note' and voucher_no=%s
and warehouse='_Test Warehouse - _TC'""", dn.name)[0][0])
expected_values = {
@@ -368,9 +374,9 @@
}
for i, gle in enumerate(gl_entries):
self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account))
-
+
set_perpetual_inventory(0)
-
+
def create_delivery_note(**args):
dn = frappe.new_doc("Delivery Note")
args = frappe._dict(args)
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index fa2fa13..cfaa499 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -10,6 +10,7 @@
from erpnext.accounts.utils import get_fiscal_year, get_stock_and_account_difference
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after
+from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import EmptyStockReconciliationItemsError
class TestStockReconciliation(unittest.TestCase):
def setUp(self):
@@ -107,7 +108,10 @@
"valuation_rate": args.rate
})
- sr.submit()
+ try:
+ sr.submit()
+ except EmptyStockReconciliationItemsError:
+ pass
return sr
def repost_stock_as_per_valuation_method(valuation_method):
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index c0d5cd0..ce5a0c9 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -109,7 +109,7 @@
def build(self):
# includes current entry!
entries_to_fix = self.get_sle_after_datetime()
-
+
for sle in entries_to_fix:
self.process_sle(sle)
@@ -231,10 +231,10 @@
def get_moving_average_values(self, sle):
actual_qty = flt(sle.actual_qty)
-
+
if actual_qty > 0 or flt(sle.outgoing_rate) > 0:
rate = flt(sle.incoming_rate) if actual_qty > 0 else flt(sle.outgoing_rate)
-
+
if self.qty_after_transaction < 0 and not self.valuation_rate:
# if negative stock, take current valuation rate as incoming rate
self.valuation_rate = rate
@@ -244,11 +244,11 @@
if new_stock_qty:
self.valuation_rate = new_stock_value / flt(new_stock_qty)
-
+
elif not self.valuation_rate and self.qty_after_transaction <= 0:
self.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse, self.allow_zero_rate)
- return abs(flt(self.valuation_rate))
+ self.valuation_rate = abs(flt(self.valuation_rate))
def get_fifo_values(self, sle):
incoming_rate = flt(sle.incoming_rate)
@@ -288,7 +288,7 @@
if v[1] == outgoing_rate:
index = i
break
-
+
# If no entry found with outgoing rate, collapse stack
if index == None:
new_stock_value = sum((d[0]*d[1] for d in self.stock_queue)) - qty_to_pop*outgoing_rate