diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index c3d83c7d74ca..053d42ee5385 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1140,6 +1140,18 @@ def test_gle_made_when_asset_is_returned(self): self.assertEqual(loss_for_si['credit'], loss_for_return_si['debit']) self.assertEqual(loss_for_si['debit'], loss_for_return_si['credit']) + def test_incoming_rate_for_stand_alone_credit_note(self): + return_si = create_sales_invoice(is_return=1, update_stock=1, qty=-1, rate=90000, incoming_rate=10, + company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', debit_to='Debtors - TCP1', + income_account='Sales - TCP1', expense_account='Cost of Goods Sold - TCP1', cost_center='Main - TCP1') + + incoming_rate = frappe.db.get_value('Stock Ledger Entry', {'voucher_no': return_si.name}, 'incoming_rate') + debit_amount = frappe.db.get_value('GL Entry', + {'voucher_no': return_si.name, 'account': 'Stock In Hand - TCP1'}, 'debit') + + self.assertEqual(debit_amount, 10.0) + self.assertEqual(incoming_rate, 10.0) + def test_discount_on_net_total(self): si = frappe.copy_doc(test_records[2]) si.apply_discount_on = "Net Total" @@ -2375,7 +2387,8 @@ def create_sales_invoice(**args): "asset": args.asset or None, "cost_center": args.cost_center or "_Test Cost Center - _TC", "serial_no": args.serial_no, - "conversion_factor": 1 + "conversion_factor": 1, + "incoming_rate": args.incoming_rate or 0 }) if not args.do_not_save: diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index c77076cb90ec..b90f3f090450 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -53,7 +53,6 @@ "column_break_24", "base_net_rate", "base_net_amount", - "incoming_rate", "drop_ship", "delivered_by_supplier", "accounting", @@ -81,6 +80,7 @@ "target_warehouse", "quality_inspection", "batch_no", + "incoming_rate", "col_break5", "allow_zero_valuation_rate", "serial_no", @@ -807,12 +807,12 @@ "read_only": 1 }, { + "depends_on": "eval:parent.is_return && parent.update_stock && !parent.return_against", "fieldname": "incoming_rate", "fieldtype": "Currency", - "label": "Incoming Rate", + "label": "Incoming Rate (Costing)", "no_copy": 1, - "print_hide": 1, - "read_only": 1 + "print_hide": 1 }, { "depends_on": "eval: doc.uom != doc.stock_uom", @@ -833,7 +833,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2021-08-12 20:15:47.668399", + "modified": "2021-08-19 13:41:53.435827", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index 5ee1f2f7fb57..01486fcd65df 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -394,19 +394,6 @@ def get_rate_for_return(voucher_type, voucher_no, item_code, return_against=None if not return_against: return_against = frappe.get_cached_value(voucher_type, voucher_no, "return_against") - if not return_against and voucher_type == 'Sales Invoice' and sle: - return get_incoming_rate({ - "item_code": sle.item_code, - "warehouse": sle.warehouse, - "posting_date": sle.get('posting_date'), - "posting_time": sle.get('posting_time'), - "qty": sle.actual_qty, - "serial_no": sle.get('serial_no'), - "company": sle.company, - "voucher_type": sle.voucher_type, - "voucher_no": sle.voucher_no - }, raise_error_if_no_rate=False) - return_against_item_field = get_return_against_item_fields(voucher_type) filters = get_filters(voucher_type, voucher_no, voucher_detail_no, @@ -417,7 +404,24 @@ def get_rate_for_return(voucher_type, voucher_no, item_code, return_against=None else: select_field = "abs(stock_value_difference / actual_qty)" - return flt(frappe.db.get_value("Stock Ledger Entry", filters, select_field)) + rate = flt(frappe.db.get_value("Stock Ledger Entry", filters, select_field)) + if not (rate and return_against) and voucher_type in ['Sales Invoice', 'Delivery Note']: + rate = frappe.db.get_value(f'{voucher_type} Item', voucher_detail_no, 'incoming_rate') + + if not rate and sle: + rate = get_incoming_rate({ + "item_code": sle.item_code, + "warehouse": sle.warehouse, + "posting_date": sle.get('posting_date'), + "posting_time": sle.get('posting_time'), + "qty": sle.actual_qty, + "serial_no": sle.get('serial_no'), + "company": sle.company, + "voucher_type": sle.voucher_type, + "voucher_no": sle.voucher_no + }, raise_error_if_no_rate=False) + + return rate def get_return_against_item_fields(voucher_type): return_against_item_fields = { diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index fc2cc97e0a50..4ea0e114b487 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -362,7 +362,7 @@ def update_reserved_qty(self): sales_order.update_reserved_qty(so_item_rows) def set_incoming_rate(self): - if self.doctype not in ("Delivery Note", "Sales Invoice", "Sales Order"): + if self.doctype not in ("Delivery Note", "Sales Invoice"): return items = self.get("items") + (self.get("packed_items") or []) @@ -371,18 +371,19 @@ def set_incoming_rate(self): # Get incoming rate based on original item cost based on valuation method qty = flt(d.get('stock_qty') or d.get('actual_qty')) - d.incoming_rate = get_incoming_rate({ - "item_code": d.item_code, - "warehouse": d.warehouse, - "posting_date": self.get('posting_date') or self.get('transaction_date'), - "posting_time": self.get('posting_time') or nowtime(), - "qty": qty if cint(self.get("is_return")) else (-1 * qty), - "serial_no": d.get('serial_no'), - "company": self.company, - "voucher_type": self.doctype, - "voucher_no": self.name, - "allow_zero_valuation": d.get("allow_zero_valuation") - }, raise_error_if_no_rate=False) + if not d.incoming_rate: + d.incoming_rate = get_incoming_rate({ + "item_code": d.item_code, + "warehouse": d.warehouse, + "posting_date": self.get('posting_date') or self.get('transaction_date'), + "posting_time": self.get('posting_time') or nowtime(), + "qty": qty if cint(self.get("is_return")) else (-1 * qty), + "serial_no": d.get('serial_no'), + "company": self.company, + "voucher_type": self.doctype, + "voucher_no": self.name, + "allow_zero_valuation": d.get("allow_zero_valuation") + }, raise_error_if_no_rate=False) # For internal transfers use incoming rate as the valuation rate if self.is_internal_transfer(): diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index eddd048c74e7..27feec1d15f1 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -332,6 +332,7 @@ def get_sle_against_current_voucher(self): where item_code = %(item_code)s and warehouse = %(warehouse)s + and is_cancelled = 0 and timestamp(posting_date, time_format(posting_time, %(time_format)s)) = timestamp(%(posting_date)s, time_format(%(posting_time)s, %(time_format)s)) order by