mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-13 03:45:08 +00:00
fix: resolve gl entries duplication in asset purchase workflow (#41845)
* fix: resolve gl entries duplication in asset purchase workflow
* fix: prevent duplicate entry when creating purchase receipt from purchase invoice
* chore: test case added
* fix: fixed missing asset category issue
(cherry picked from commit 55a4bd469b)
# Conflicts:
# erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
This commit is contained in:
@@ -369,6 +369,21 @@ class PurchaseInvoice(BuyingController):
|
||||
item.expense_account = stock_not_billed_account
|
||||
elif item.is_fixed_asset:
|
||||
account = None
|
||||
if not item.pr_detail and item.po_detail:
|
||||
receipt_item = frappe.get_cached_value(
|
||||
"Purchase Receipt Item",
|
||||
{
|
||||
"purchase_order": item.purchase_order,
|
||||
"purchase_order_item": item.po_detail,
|
||||
"docstatus": 1,
|
||||
},
|
||||
["name", "parent"],
|
||||
as_dict=1,
|
||||
)
|
||||
if receipt_item:
|
||||
item.pr_detail = receipt_item.name
|
||||
item.purchase_receipt = receipt_item.parent
|
||||
|
||||
if item.pr_detail:
|
||||
if not self.asset_received_but_not_billed:
|
||||
self.asset_received_but_not_billed = self.get_company_default(
|
||||
|
||||
@@ -10,7 +10,11 @@ import erpnext
|
||||
from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
|
||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||
from erpnext.buying.doctype.purchase_order.purchase_order import get_mapped_purchase_invoice
|
||||
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
|
||||
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice as make_pi_from_po
|
||||
from erpnext.buying.doctype.purchase_order.test_purchase_order import (
|
||||
create_pr_against_po,
|
||||
create_purchase_order,
|
||||
)
|
||||
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
|
||||
from erpnext.controllers.accounts_controller import get_payment_terms
|
||||
from erpnext.controllers.buying_controller import QtyMismatchError
|
||||
@@ -1957,6 +1961,176 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
|
||||
|
||||
self.assertRaises(frappe.ValidationError, dr_note.save)
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
def test_debit_note_without_item(self):
|
||||
pi = make_purchase_invoice(item_name="_Test Item", qty=10, do_not_submit=True)
|
||||
pi.items[0].item_code = ""
|
||||
pi.save()
|
||||
|
||||
self.assertFalse(pi.items[0].item_code)
|
||||
pi.submit()
|
||||
|
||||
return_pi = make_purchase_invoice(
|
||||
item_name="_Test Item",
|
||||
is_return=1,
|
||||
return_against=pi.name,
|
||||
qty=-10,
|
||||
do_not_save=True,
|
||||
)
|
||||
return_pi.items[0].item_code = ""
|
||||
return_pi.save()
|
||||
return_pi.submit()
|
||||
self.assertEqual(return_pi.docstatus, 1)
|
||||
|
||||
def test_purchase_invoice_with_use_serial_batch_field_for_rejected_qty(self):
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||
|
||||
batch_item = make_item(
|
||||
"_Test Purchase Invoice Batch Item For Rejected Qty",
|
||||
properties={"has_batch_no": 1, "create_new_batch": 1, "is_stock_item": 1},
|
||||
).name
|
||||
|
||||
serial_item = make_item(
|
||||
"_Test Purchase Invoice Serial Item for Rejected Qty",
|
||||
properties={"has_serial_no": 1, "is_stock_item": 1},
|
||||
).name
|
||||
|
||||
rej_warehouse = create_warehouse("_Test Purchase INV Warehouse For Rejected Qty")
|
||||
|
||||
batch_no = "BATCH-PI-BNU-TPRBI-0001"
|
||||
serial_nos = ["SNU-PI-TPRSI-0001", "SNU-PI-TPRSI-0002", "SNU-PI-TPRSI-0003"]
|
||||
|
||||
if not frappe.db.exists("Batch", batch_no):
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Batch",
|
||||
"batch_id": batch_no,
|
||||
"item": batch_item,
|
||||
}
|
||||
).insert()
|
||||
|
||||
for serial_no in serial_nos:
|
||||
if not frappe.db.exists("Serial No", serial_no):
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Serial No",
|
||||
"item_code": serial_item,
|
||||
"serial_no": serial_no,
|
||||
}
|
||||
).insert()
|
||||
|
||||
pi = make_purchase_invoice(
|
||||
item_code=batch_item,
|
||||
received_qty=10,
|
||||
qty=8,
|
||||
rejected_qty=2,
|
||||
update_stock=1,
|
||||
rejected_warehouse=rej_warehouse,
|
||||
use_serial_batch_fields=1,
|
||||
batch_no=batch_no,
|
||||
rate=100,
|
||||
do_not_submit=1,
|
||||
)
|
||||
|
||||
pi.append(
|
||||
"items",
|
||||
{
|
||||
"item_code": serial_item,
|
||||
"qty": 2,
|
||||
"rate": 100,
|
||||
"base_rate": 100,
|
||||
"item_name": serial_item,
|
||||
"uom": "Nos",
|
||||
"stock_uom": "Nos",
|
||||
"conversion_factor": 1,
|
||||
"rejected_qty": 1,
|
||||
"warehouse": pi.items[0].warehouse,
|
||||
"rejected_warehouse": rej_warehouse,
|
||||
"use_serial_batch_fields": 1,
|
||||
"serial_no": "\n".join(serial_nos[:2]),
|
||||
"rejected_serial_no": serial_nos[2],
|
||||
},
|
||||
)
|
||||
|
||||
pi.save()
|
||||
pi.submit()
|
||||
|
||||
pi.reload()
|
||||
|
||||
for row in pi.items:
|
||||
self.assertTrue(row.serial_and_batch_bundle)
|
||||
self.assertTrue(row.rejected_serial_and_batch_bundle)
|
||||
|
||||
if row.item_code == batch_item:
|
||||
self.assertEqual(row.batch_no, batch_no)
|
||||
else:
|
||||
self.assertEqual(row.serial_no, "\n".join(serial_nos[:2]))
|
||||
self.assertEqual(row.rejected_serial_no, serial_nos[2])
|
||||
|
||||
def test_make_pr_and_pi_from_po(self):
|
||||
from erpnext.assets.doctype.asset.test_asset import create_asset_category
|
||||
|
||||
if not frappe.db.exists("Asset Category", "Computers"):
|
||||
create_asset_category()
|
||||
|
||||
item = create_item(
|
||||
item_code="_Test_Item", is_stock_item=0, is_fixed_asset=1, asset_category="Computers"
|
||||
)
|
||||
po = create_purchase_order(item_code=item.item_code)
|
||||
pr = create_pr_against_po(po.name, 10)
|
||||
pi = make_pi_from_po(po.name)
|
||||
pi.insert()
|
||||
pi.submit()
|
||||
|
||||
pr_gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Purchase Receipt' and voucher_no=%s
|
||||
order by account asc""",
|
||||
pr.name,
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
pr_expected_values = [
|
||||
["Asset Received But Not Billed - _TC", 0, 5000],
|
||||
["CWIP Account - _TC", 5000, 0],
|
||||
]
|
||||
|
||||
for i, gle in enumerate(pr_gl_entries):
|
||||
self.assertEqual(pr_expected_values[i][0], gle.account)
|
||||
self.assertEqual(pr_expected_values[i][1], gle.debit)
|
||||
self.assertEqual(pr_expected_values[i][2], gle.credit)
|
||||
|
||||
pi_gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
pi.name,
|
||||
as_dict=1,
|
||||
)
|
||||
pi_expected_values = [
|
||||
["Asset Received But Not Billed - _TC", 5000, 0],
|
||||
["Creditors - _TC", 0, 5000],
|
||||
]
|
||||
|
||||
for i, gle in enumerate(pi_gl_entries):
|
||||
self.assertEqual(pi_expected_values[i][0], gle.account)
|
||||
self.assertEqual(pi_expected_values[i][1], gle.debit)
|
||||
self.assertEqual(pi_expected_values[i][2], gle.credit)
|
||||
|
||||
|
||||
def set_advance_flag(company, flag, default_account):
|
||||
frappe.db.set_value(
|
||||
"Company",
|
||||
company,
|
||||
{
|
||||
"book_advance_payments_in_separate_party_account": flag,
|
||||
"default_advance_paid_account": default_account,
|
||||
},
|
||||
)
|
||||
|
||||
>>>>>>> 55a4bd469b (fix: resolve gl entries duplication in asset purchase workflow (#41845))
|
||||
|
||||
def check_gl_entries(
|
||||
doc,
|
||||
|
||||
@@ -546,7 +546,7 @@ class PurchaseReceipt(BuyingController):
|
||||
|
||||
if not (
|
||||
(erpnext.is_perpetual_inventory_enabled(self.company) and d.item_code in stock_items)
|
||||
or d.is_fixed_asset
|
||||
or (d.is_fixed_asset and not d.purchase_invoice)
|
||||
):
|
||||
continue
|
||||
|
||||
|
||||
Reference in New Issue
Block a user