Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: inventory dimension for returned inter company transfer #35289

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions erpnext/controllers/accounts_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,9 @@ def validate_party_accounts(self):
)

def validate_inter_company_reference(self):
if self.get("is_return"):
return

if self.doctype not in ("Purchase Invoice", "Purchase Receipt"):
return

Expand Down
18 changes: 16 additions & 2 deletions erpnext/controllers/stock_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,22 @@ def update_inventory_dimensions(self, row, sl_dict) -> None:
"Delivery Note",
"Stock Entry",
]:
if (sl_dict.actual_qty > 0 and self.doctype in ["Purchase Invoice", "Purchase Receipt"]) or (
sl_dict.actual_qty < 0 and self.doctype in ["Sales Invoice", "Delivery Note", "Stock Entry"]
if (
(
sl_dict.actual_qty > 0
and not self.get("is_return")
or sl_dict.actual_qty < 0
and self.get("is_return")
)
and self.doctype in ["Purchase Invoice", "Purchase Receipt"]
) or (
(
sl_dict.actual_qty < 0
and not self.get("is_return")
or sl_dict.actual_qty > 0
and self.get("is_return")
)
and self.doctype in ["Sales Invoice", "Delivery Note", "Stock Entry"]
):
sl_dict[dimension.target_fieldname] = row.get(dimension.source_fieldname)
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
from frappe.tests.utils import FrappeTestCase
from frappe.utils import nowdate, nowtime

from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import (
Expand Down Expand Up @@ -257,6 +258,8 @@ def test_check_mandatory_depends_on_dimensions(self):
)

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

create_inventory_dimension(
reference_document="Store",
type_of_transaction="Outward",
Expand Down Expand Up @@ -319,6 +322,98 @@ def test_for_purchase_sales_and_stock_transaction(self):
self.assertEqual(entries[0].store, "Store 2")
self.assertEqual(entries[0].actual_qty, -10.0)

return_dn = make_return_doc("Delivery Note", dn_doc.name)
return_dn.submit()
entries = get_voucher_sl_entries(return_dn.name, ["warehouse", "store", "actual_qty"])

self.assertEqual(entries[0].warehouse, warehouse)
self.assertEqual(entries[0].store, "Store 2")
self.assertEqual(entries[0].actual_qty, 10.0)

se_doc = make_stock_entry(
item_code=item_code, qty=10, from_warehouse=warehouse, to_warehouse=warehouse, do_not_save=True
)

se_doc.items[0].store = "Store 2"
se_doc.items[0].to_store = "Store 1"

se_doc.save()
se_doc.submit()

return_pr = make_return_doc("Purchase Receipt", pr_doc.name)
return_pr.submit()
entries = get_voucher_sl_entries(return_pr.name, ["warehouse", "store", "actual_qty"])

self.assertEqual(entries[0].warehouse, warehouse)
self.assertEqual(entries[0].store, "Store 1")
self.assertEqual(entries[0].actual_qty, -10.0)

def test_inter_transfer_return_against_inventory_dimension(self):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt

data = prepare_data_for_internal_transfer()

dn_doc = create_delivery_note(
customer=data.customer,
company=data.company,
warehouse=data.from_warehouse,
target_warehouse=data.to_warehouse,
qty=5,
cost_center=data.cost_center,
expense_account=data.expense_account,
do_not_submit=True,
)

dn_doc.items[0].store = "Inter Transfer Store 1"
dn_doc.items[0].to_store = "Inter Transfer Store 2"
dn_doc.save()
dn_doc.submit()

for d in get_voucher_sl_entries(dn_doc.name, ["store", "actual_qty"]):
if d.actual_qty > 0:
self.assertEqual(d.store, "Inter Transfer Store 2")
else:
self.assertEqual(d.store, "Inter Transfer Store 1")

pr_doc = make_inter_company_purchase_receipt(dn_doc.name)
pr_doc.items[0].warehouse = data.store_warehouse
pr_doc.items[0].from_store = "Inter Transfer Store 2"
pr_doc.items[0].store = "Inter Transfer Store 3"
pr_doc.save()
pr_doc.submit()

for d in get_voucher_sl_entries(pr_doc.name, ["store", "actual_qty"]):
if d.actual_qty > 0:
self.assertEqual(d.store, "Inter Transfer Store 3")
else:
self.assertEqual(d.store, "Inter Transfer Store 2")

return_doc = make_return_doc("Purchase Receipt", pr_doc.name)
return_doc.submit()

for d in get_voucher_sl_entries(return_doc.name, ["store", "actual_qty"]):
if d.actual_qty > 0:
self.assertEqual(d.store, "Inter Transfer Store 2")
else:
self.assertEqual(d.store, "Inter Transfer Store 3")

dn_doc.load_from_db()

return_doc1 = make_return_doc("Delivery Note", dn_doc.name)
return_doc1.posting_date = nowdate()
return_doc1.posting_time = nowtime()
return_doc1.items[0].target_warehouse = dn_doc.items[0].target_warehouse
return_doc1.items[0].warehouse = dn_doc.items[0].warehouse
return_doc1.save()
return_doc1.submit()

for d in get_voucher_sl_entries(return_doc1.name, ["store", "actual_qty"]):
if d.actual_qty > 0:
self.assertEqual(d.store, "Inter Transfer Store 1")
else:
self.assertEqual(d.store, "Inter Transfer Store 2")


def get_voucher_sl_entries(voucher_no, fields):
return frappe.get_all(
Expand Down Expand Up @@ -423,3 +518,79 @@ def create_inventory_dimension(**args):
doc.insert(ignore_permissions=True)

return doc


def prepare_data_for_internal_transfer():
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
from erpnext.selling.doctype.customer.test_customer import create_internal_customer
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse

company = "_Test Company with perpetual inventory"

customer = create_internal_customer(
"_Test Internal Customer 3",
company,
company,
)

supplier = create_internal_supplier(
"_Test Internal Supplier 3",
company,
company,
)

for store in ["Inter Transfer Store 1", "Inter Transfer Store 2", "Inter Transfer Store 3"]:
if not frappe.db.exists("Store", store):
frappe.get_doc({"doctype": "Store", "store_name": store}).insert(ignore_permissions=True)

warehouse = create_warehouse("_Test Internal Warehouse New A", company=company)

to_warehouse = create_warehouse("_Test Internal Warehouse GIT A", company=company)

pr_doc = make_purchase_receipt(
company=company, warehouse=warehouse, qty=10, rate=100, do_not_submit=True
)
pr_doc.items[0].store = "Inter Transfer Store 1"
pr_doc.submit()

if not frappe.db.get_value("Company", company, "unrealized_profit_loss_account"):
account = "Unrealized Profit and Loss - TCP1"
if not frappe.db.exists("Account", account):
frappe.get_doc(
{
"doctype": "Account",
"account_name": "Unrealized Profit and Loss",
"parent_account": "Direct Income - TCP1",
"company": company,
"is_group": 0,
"account_type": "Income Account",
}
).insert()

frappe.db.set_value("Company", company, "unrealized_profit_loss_account", account)

cost_center = frappe.db.get_value("Company", company, "cost_center") or frappe.db.get_value(
"Cost Center", {"company": company}, "name"
)

expene_account = frappe.db.get_value(
"Company", company, "stock_adjustment_account"
) or frappe.db.get_value(
"Account", {"company": company, "account_type": "Expense Account"}, "name"
)

return frappe._dict(
{
"from_warehouse": warehouse,
"to_warehouse": to_warehouse,
"customer": customer,
"supplier": supplier,
"company": company,
"cost_center": cost_center,
"expene_account": expene_account,
"store_warehouse": frappe.db.get_value(
"Warehouse", {"name": ("like", "Store%"), "company": company}, "name"
),
}
)