Skip to content

Commit

Permalink
fix: consider sales rate as incoming rate for transit warehouse in pu…
Browse files Browse the repository at this point in the history
…rchase flow

(cherry picked from commit 683a47f)
  • Loading branch information
rohitwaghchaure authored and mergify[bot] committed Oct 12, 2022
1 parent 23aca66 commit 948b231
Show file tree
Hide file tree
Showing 4 changed files with 278 additions and 25 deletions.
Expand Up @@ -705,6 +705,10 @@ def make_item_gl_entries(self, gl_entries):
)
)

credit_amount = item.base_net_amount
if self.is_internal_supplier and item.valuation_rate:
credit_amount = flt(item.valuation_rate * item.stock_qty)

# Intentionally passed negative debit amount to avoid incorrect GL Entry validation
gl_entries.append(
self.get_gl_dict(
Expand All @@ -714,7 +718,7 @@ def make_item_gl_entries(self, gl_entries):
"cost_center": item.cost_center,
"project": item.project or self.project,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"debit": -1 * flt(item.base_net_amount, item.precision("base_net_amount")),
"debit": -1 * flt(credit_amount, item.precision("base_net_amount")),
},
warehouse_account[item.from_warehouse]["account_currency"],
item=item,
Expand Down
Expand Up @@ -3306,6 +3306,7 @@ def create_sales_invoice(**args):
"item_name": args.item_name or "_Test Item",
"description": args.description or "_Test Item",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"target_warehouse": args.target_warehouse or "_Test Warehouse 1 - _TC",
"qty": args.qty or 1,
"uom": args.uom or "Nos",
"stock_uom": args.uom or "Nos",
Expand Down
234 changes: 234 additions & 0 deletions erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
Expand Up @@ -2,6 +2,9 @@
# License: GNU General Public License v3. See license.txt


from cmath import pi
from turtle import update

import frappe
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, cint, cstr, flt, today
Expand All @@ -14,6 +17,7 @@
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice
from erpnext.stock.doctype.serial_no.serial_no import SerialNoDuplicateError, get_serial_nos
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.get_item_details import update_stock
from erpnext.stock.stock_ledger import SerialNoExistsInFutureTransaction


Expand Down Expand Up @@ -1199,6 +1203,115 @@ def test_backdated_transaction_for_internal_transfer(self):
self.assertEqual(pr1.items[0].rate, 100)
pr1.submit()

self.assertEqual(pr1.is_internal_supplier, 1)

# Backdated purchase receipt entry, the valuation rate should be updated for DN1 and PR1
make_purchase_receipt(
item_code=item_doc.name,
company=company,
posting_date=add_days(today(), -2),
warehouse=from_warehouse,
qty=1,
rate=200,
)

dn_value = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": "Delivery Note", "voucher_no": dn1.name, "warehouse": target_warehouse},
"stock_value_difference",
)

self.assertEqual(abs(dn_value), 200.00)

pr_value = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": "Purchase Receipt", "voucher_no": pr1.name, "warehouse": to_warehouse},
"stock_value_difference",
)

self.assertEqual(abs(pr_value), 200.00)
pr1.load_from_db()

self.assertEqual(pr1.items[0].valuation_rate, 200)
self.assertEqual(pr1.items[0].rate, 100)

Gl = frappe.qb.DocType("GL Entry")

query = (
frappe.qb.from_(Gl)
.select(
(fn.Sum(Gl.debit) - fn.Sum(Gl.credit)).as_("value"),
)
.where((Gl.voucher_type == pr1.doctype) & (Gl.voucher_no == pr1.name))
).run(as_dict=True)

self.assertEqual(query[0].value, 0)

def test_backdated_transaction_for_internal_transfer_in_trasit_warehouse_for_purchase_receipt(
self,
):
from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note

prepare_data_for_internal_transfer()
customer = "_Test Internal Customer 2"
company = "_Test Company with perpetual inventory"

from_warehouse = create_warehouse("_Test Internal From Warehouse New", company=company)
to_warehouse = create_warehouse("_Test Internal To Warehouse New", company=company)
item_doc = create_item("Test Internal Transfer Item")

target_warehouse = create_warehouse("_Test Internal GIT Warehouse New", company=company)

make_purchase_receipt(
item_code=item_doc.name,
company=company,
posting_date=add_days(today(), -1),
warehouse=from_warehouse,
qty=1,
rate=100,
)

# Keep stock in advance and make sure that systen won't pick this stock while reposting backdated transaction
for i in range(1, 4):
make_purchase_receipt(
item_code=item_doc.name,
company=company,
posting_date=add_days(today(), -1 * i),
warehouse=target_warehouse,
qty=1,
rate=320 * i,
)

dn1 = create_delivery_note(
item_code=item_doc.name,
company=company,
customer=customer,
cost_center="Main - TCP1",
expense_account="Cost of Goods Sold - TCP1",
qty=1,
rate=500,
warehouse=from_warehouse,
target_warehouse=target_warehouse,
)

self.assertEqual(dn1.items[0].rate, 100)

pr1 = make_inter_company_purchase_receipt(dn1.name)
pr1.items[0].warehouse = to_warehouse
self.assertEqual(pr1.items[0].rate, 100)
pr1.submit()

stk_ledger = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": "Purchase Receipt", "voucher_no": pr1.name, "warehouse": target_warehouse},
["stock_value_difference", "outgoing_rate"],
as_dict=True,
)

self.assertEqual(abs(stk_ledger.stock_value_difference), 100)
self.assertEqual(stk_ledger.outgoing_rate, 100)

# Backdated purchase receipt entry, the valuation rate should be updated for DN1 and PR1
make_purchase_receipt(
item_code=item_doc.name,
Expand Down Expand Up @@ -1241,6 +1354,127 @@ def test_backdated_transaction_for_internal_transfer(self):

self.assertEqual(query[0].value, 0)

def test_backdated_transaction_for_internal_transfer_in_trasit_warehouse_for_purchase_invoice(
self,
):
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import (
make_purchase_invoice as make_purchase_invoice_for_si,
)
from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
make_inter_company_purchase_invoice,
)
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice

prepare_data_for_internal_transfer()
customer = "_Test Internal Customer 2"
company = "_Test Company with perpetual inventory"

from_warehouse = create_warehouse("_Test Internal From Warehouse New", company=company)
to_warehouse = create_warehouse("_Test Internal To Warehouse New", company=company)
item_doc = create_item("Test Internal Transfer Item")

target_warehouse = create_warehouse("_Test Internal GIT Warehouse New", company=company)

make_purchase_invoice_for_si(
item_code=item_doc.name,
company=company,
posting_date=add_days(today(), -1),
warehouse=from_warehouse,
qty=1,
update_stock=1,
expense_account="Cost of Goods Sold - TCP1",
cost_center="Main - TCP1",
rate=100,
)

# Keep stock in advance and make sure that systen won't pick this stock while reposting backdated transaction
for i in range(1, 4):
make_purchase_invoice_for_si(
item_code=item_doc.name,
company=company,
posting_date=add_days(today(), -1 * i),
warehouse=target_warehouse,
update_stock=1,
qty=1,
expense_account="Cost of Goods Sold - TCP1",
cost_center="Main - TCP1",
rate=320 * i,
)

si1 = create_sales_invoice(
item_code=item_doc.name,
company=company,
customer=customer,
cost_center="Main - TCP1",
income_account="Sales - TCP1",
qty=1,
rate=500,
update_stock=1,
warehouse=from_warehouse,
target_warehouse=target_warehouse,
)

self.assertEqual(si1.items[0].rate, 100)

pi1 = make_inter_company_purchase_invoice(si1.name)
pi1.items[0].warehouse = to_warehouse
self.assertEqual(pi1.items[0].rate, 100)
pi1.update_stock = 1
pi1.save()
pi1.submit()

stk_ledger = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": pi1.doctype, "voucher_no": pi1.name, "warehouse": target_warehouse},
["stock_value_difference", "outgoing_rate"],
as_dict=True,
)

self.assertEqual(abs(stk_ledger.stock_value_difference), 100)
self.assertEqual(stk_ledger.outgoing_rate, 100)

# Backdated purchase receipt entry, the valuation rate should be updated for si1 and pi1
make_purchase_receipt(
item_code=item_doc.name,
company=company,
posting_date=add_days(today(), -2),
warehouse=from_warehouse,
qty=1,
rate=200,
)

si_value = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": si1.doctype, "voucher_no": si1.name, "warehouse": target_warehouse},
"stock_value_difference",
)

self.assertEqual(abs(si_value), 200.00)

pi_value = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": pi1.doctype, "voucher_no": pi1.name, "warehouse": to_warehouse},
"stock_value_difference",
)

self.assertEqual(abs(pi_value), 200.00)
pi1.load_from_db()

self.assertEqual(pi1.items[0].valuation_rate, 200)
self.assertEqual(pi1.items[0].rate, 100)

Gl = frappe.qb.DocType("GL Entry")

query = (
frappe.qb.from_(Gl)
.select(
(fn.Sum(Gl.debit) - fn.Sum(Gl.credit)).as_("value"),
)
.where((Gl.voucher_type == pi1.doctype) & (Gl.voucher_no == pi1.name))
).run(as_dict=True)

self.assertEqual(query[0].value, 0)

def test_batch_expiry_for_purchase_receipt(self):
from erpnext.controllers.sales_and_purchase_return import make_return_doc

Expand Down
62 changes: 38 additions & 24 deletions erpnext/stock/stock_ledger.py
Expand Up @@ -589,6 +589,15 @@ def process_sle(self, sle):
sle.stock_queue = json.dumps(self.wh_data.stock_queue)
sle.stock_value_difference = stock_value_difference
sle.doctype = "Stock Ledger Entry"

if (
sle.voucher_type in ["Purchase Receipt", "Purchase Invoice"]
and sle.voucher_detail_no
and sle.actual_qty < 0
and frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_internal_supplier")
):
sle.outgoing_rate = get_incoming_rate_for_inter_company_transfer(sle)

frappe.get_doc(sle).db_update()

if not self.args.get("sle_id"):
Expand Down Expand Up @@ -652,22 +661,7 @@ def get_incoming_outgoing_rate_from_transaction(self, sle):
and sle.voucher_detail_no
and frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_internal_supplier")
):
field = (
"delivery_note_item" if sle.voucher_type == "Purchase Receipt" else "sales_invoice_item"
)
doctype = (
"Delivery Note Item" if sle.voucher_type == "Purchase Receipt" else "Sales Invoice Item"
)
refernce_name = frappe.get_cached_value(
sle.voucher_type + " Item", sle.voucher_detail_no, field
)

if refernce_name:
rate = frappe.get_cached_value(
doctype,
refernce_name,
"incoming_rate",
)
rate = get_incoming_rate_for_inter_company_transfer(sle)
else:
if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"):
rate_field = "valuation_rate"
Expand Down Expand Up @@ -748,14 +742,12 @@ def update_rate_on_delivery_and_sales_return(self, sle, outgoing_rate):

def update_rate_on_purchase_receipt(self, sle, outgoing_rate):
if frappe.db.exists(sle.voucher_type + " Item", sle.voucher_detail_no):
frappe.db.set_value(
sle.voucher_type + " Item",
sle.voucher_detail_no,
{
"base_net_rate": outgoing_rate,
"valuation_rate": outgoing_rate,
},
)
if sle.voucher_type in ["Purchase Receipt", "Purchase Invoice"] and frappe.get_cached_value(
sle.voucher_type, sle.voucher_no, "is_internal_supplier"
):
frappe.db.set_value(
f"{sle.voucher_type} Item", sle.voucher_detail_no, "valuation_rate", sle.outgoing_rate
)
else:
frappe.db.set_value(
"Purchase Receipt Item Supplied", sle.voucher_detail_no, "rate", outgoing_rate
Expand Down Expand Up @@ -1546,3 +1538,25 @@ def is_negative_stock_allowed(*, item_code: Optional[str] = None) -> bool:
if item_code and cint(frappe.db.get_value("Item", item_code, "allow_negative_stock", cache=True)):
return True
return False


def get_incoming_rate_for_inter_company_transfer(sle) -> float:
"""
For inter company transfer, incoming rate is the average of the outgoing rate
"""
rate = 0.0

field = "delivery_note_item" if sle.voucher_type == "Purchase Receipt" else "sales_invoice_item"

doctype = "Delivery Note Item" if sle.voucher_type == "Purchase Receipt" else "Sales Invoice Item"

reference_name = frappe.get_cached_value(sle.voucher_type + " Item", sle.voucher_detail_no, field)

if reference_name:
rate = frappe.get_cached_value(
doctype,
reference_name,
"incoming_rate",
)

return rate

0 comments on commit 948b231

Please sign in to comment.