fix: Item valuation for internal stocktransfers
This commit is contained in:
@@ -508,7 +508,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
grand_total = self.rounded_total if (self.rounding_adjustment and self.rounded_total) else self.grand_total
|
grand_total = self.rounded_total if (self.rounding_adjustment and self.rounded_total) else self.grand_total
|
||||||
|
|
||||||
if grand_total and not self.is_internal_transfer():
|
if grand_total and not self.is_internal_transfer():
|
||||||
# Didnot use base_grand_total to book rounding loss gle
|
# Did not use base_grand_total to book rounding loss gle
|
||||||
grand_total_in_company_currency = flt(grand_total * self.conversion_rate,
|
grand_total_in_company_currency = flt(grand_total * self.conversion_rate,
|
||||||
self.precision("grand_total"))
|
self.precision("grand_total"))
|
||||||
gl_entries.append(
|
gl_entries.append(
|
||||||
@@ -539,8 +539,8 @@ class PurchaseInvoice(BuyingController):
|
|||||||
voucher_wise_stock_value = {}
|
voucher_wise_stock_value = {}
|
||||||
if self.update_stock:
|
if self.update_stock:
|
||||||
for d in frappe.get_all('Stock Ledger Entry',
|
for d in frappe.get_all('Stock Ledger Entry',
|
||||||
fields = ["voucher_detail_no", "stock_value_difference"], filters={'voucher_no': self.name}):
|
fields = ["voucher_detail_no", "stock_value_difference", "warehouse"], filters={'voucher_no': self.name}):
|
||||||
voucher_wise_stock_value.setdefault(d.voucher_detail_no, d.stock_value_difference)
|
voucher_wise_stock_value.setdefault((d.voucher_detail_no, d.warehouse), d.stock_value_difference)
|
||||||
|
|
||||||
valuation_tax_accounts = [d.account_head for d in self.get("taxes")
|
valuation_tax_accounts = [d.account_head for d in self.get("taxes")
|
||||||
if d.category in ('Valuation', 'Total and Valuation')
|
if d.category in ('Valuation', 'Total and Valuation')
|
||||||
@@ -823,10 +823,10 @@ class PurchaseInvoice(BuyingController):
|
|||||||
|
|
||||||
# Stock ledger value is not matching with the warehouse amount
|
# Stock ledger value is not matching with the warehouse amount
|
||||||
if (self.update_stock and voucher_wise_stock_value.get(item.name) and
|
if (self.update_stock and voucher_wise_stock_value.get(item.name) and
|
||||||
warehouse_debit_amount != flt(voucher_wise_stock_value.get(item.name), net_amt_precision)):
|
warehouse_debit_amount != flt(voucher_wise_stock_value.get((item.name, item.warehouse)), net_amt_precision)):
|
||||||
|
|
||||||
cost_of_goods_sold_account = self.get_company_default("default_expense_account")
|
cost_of_goods_sold_account = self.get_company_default("default_expense_account")
|
||||||
stock_amount = flt(voucher_wise_stock_value.get(item.name), net_amt_precision)
|
stock_amount = flt(voucher_wise_stock_value.get((item.name, item.warehouse)), net_amt_precision)
|
||||||
stock_adjustment_amt = warehouse_debit_amount - stock_amount
|
stock_adjustment_amt = warehouse_debit_amount - stock_amount
|
||||||
|
|
||||||
gl_entries.append(
|
gl_entries.append(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"autoname": "hash",
|
"autoname": "hash",
|
||||||
"creation": "2013-05-22 12:43:10",
|
"creation": "2013-05-22 12:43:10",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
@@ -46,6 +47,7 @@
|
|||||||
"column_break_25",
|
"column_break_25",
|
||||||
"base_net_rate",
|
"base_net_rate",
|
||||||
"base_net_amount",
|
"base_net_amount",
|
||||||
|
"outgoing_rate",
|
||||||
"valuation_rate",
|
"valuation_rate",
|
||||||
"item_tax_amount",
|
"item_tax_amount",
|
||||||
"landed_cost_voucher_amount",
|
"landed_cost_voucher_amount",
|
||||||
@@ -553,8 +555,8 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"label": "Brand",
|
"label": "Brand",
|
||||||
"print_hide": 1,
|
"options": "Brand",
|
||||||
"options": "Brand"
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fetch_from": "item_code.item_group",
|
"fetch_from": "item_code.item_group",
|
||||||
@@ -562,9 +564,9 @@
|
|||||||
"fieldname": "item_group",
|
"fieldname": "item_group",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Item Group",
|
"label": "Item Group",
|
||||||
|
"options": "Item Group",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1,
|
"read_only": 1
|
||||||
"options": "Item Group"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Tax detail table fetched from item master as a string and stored in this field.\nUsed for Taxes and Charges",
|
"description": "Tax detail table fetched from item master as a string and stored in this field.\nUsed for Taxes and Charges",
|
||||||
@@ -779,11 +781,18 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "outgoing_rate",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Outgoing Rate",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2020-08-20 11:48:01.398356",
|
"links": [],
|
||||||
|
"modified": "2020-12-23 17:30:57.458876",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice Item",
|
"name": "Purchase Invoice Item",
|
||||||
|
|||||||
@@ -1770,59 +1770,59 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
self.assertEqual(target_doc.company, "_Test Company 1")
|
self.assertEqual(target_doc.company, "_Test Company 1")
|
||||||
self.assertEqual(target_doc.supplier, "_Test Internal Supplier")
|
self.assertEqual(target_doc.supplier, "_Test Internal Supplier")
|
||||||
|
|
||||||
# def test_internal_transfer_gl_entry(self):
|
def test_internal_transfer_gl_entry(self):
|
||||||
# ## Create internal transfer account
|
## Create internal transfer account
|
||||||
# account = create_account(account_name="Unrealized Profit",
|
account = create_account(account_name="Unrealized Profit",
|
||||||
# parent_account="Current Liabilities - TCP1", company="_Test Company with perpetual inventory")
|
parent_account="Current Liabilities - TCP1", company="_Test Company with perpetual inventory")
|
||||||
|
|
||||||
# frappe.db.set_value('Company', '_Test Company with perpetual inventory',
|
frappe.db.set_value('Company', '_Test Company with perpetual inventory',
|
||||||
# 'unrealized_profit_loss_account', account)
|
'unrealized_profit_loss_account', account)
|
||||||
|
|
||||||
# customer = create_internal_customer("_Test Internal Customer 2", "_Test Company with perpetual inventory",
|
customer = create_internal_customer("_Test Internal Customer 2", "_Test Company with perpetual inventory",
|
||||||
# "_Test Company with perpetual inventory")
|
"_Test Company with perpetual inventory")
|
||||||
|
|
||||||
# create_internal_supplier("_Test Internal Supplier 2", "_Test Company with perpetual inventory",
|
create_internal_supplier("_Test Internal Supplier 2", "_Test Company with perpetual inventory",
|
||||||
# "_Test Company with perpetual inventory")
|
"_Test Company with perpetual inventory")
|
||||||
|
|
||||||
# si = create_sales_invoice(
|
si = create_sales_invoice(
|
||||||
# company = "_Test Company with perpetual inventory",
|
company = "_Test Company with perpetual inventory",
|
||||||
# customer = customer,
|
customer = customer,
|
||||||
# debit_to = "Debtors - TCP1",
|
debit_to = "Debtors - TCP1",
|
||||||
# warehouse = "Stores - TCP1",
|
warehouse = "Stores - TCP1",
|
||||||
# income_account = "Sales - TCP1",
|
income_account = "Sales - TCP1",
|
||||||
# expense_account = "Cost of Goods Sold - TCP1",
|
expense_account = "Cost of Goods Sold - TCP1",
|
||||||
# cost_center = "Main - TCP1",
|
cost_center = "Main - TCP1",
|
||||||
# currency = "INR",
|
currency = "INR",
|
||||||
# do_not_save = 1
|
do_not_save = 1
|
||||||
# )
|
)
|
||||||
|
|
||||||
# si.selling_price_list = "_Test Price List Rest of the World"
|
si.selling_price_list = "_Test Price List Rest of the World"
|
||||||
# si.update_stock = 1
|
si.update_stock = 1
|
||||||
# si.items[0].target_warehouse = 'Work In Progress - TCP1'
|
si.items[0].target_warehouse = 'Work In Progress - TCP1'
|
||||||
# add_taxes(si)
|
add_taxes(si)
|
||||||
# si.save()
|
si.save()
|
||||||
# si.submit()
|
si.submit()
|
||||||
|
|
||||||
# target_doc = make_inter_company_transaction("Sales Invoice", si.name)
|
target_doc = make_inter_company_transaction("Sales Invoice", si.name)
|
||||||
# target_doc.company = '_Test Company with perpetual inventory'
|
target_doc.company = '_Test Company with perpetual inventory'
|
||||||
# target_doc.items[0].warehouse = 'Finished Goods - TCP1'
|
target_doc.items[0].warehouse = 'Finished Goods - TCP1'
|
||||||
# add_taxes(target_doc)
|
add_taxes(target_doc)
|
||||||
# target_doc.save()
|
target_doc.save()
|
||||||
# target_doc.submit()
|
target_doc.submit()
|
||||||
|
|
||||||
# si_gl_entries = [
|
si_gl_entries = [
|
||||||
# ["_Test Account Excise Duty - TCP1", 0.0, 12.0, nowdate()],
|
["_Test Account Excise Duty - TCP1", 0.0, 12.0, nowdate()],
|
||||||
# ["Unrealized Profit - TCP1", 12.0, 0.0, nowdate()]
|
["Unrealized Profit - TCP1", 12.0, 0.0, nowdate()]
|
||||||
# ]
|
]
|
||||||
|
|
||||||
# check_gl_entries(self, si.name, si_gl_entries, add_days(nowdate(), -1))
|
check_gl_entries(self, si.name, si_gl_entries, add_days(nowdate(), -1))
|
||||||
|
|
||||||
# pi_gl_entries = [
|
pi_gl_entries = [
|
||||||
# ["_Test Account Excise Duty - TCP1", 12.0 , 0.0, nowdate()],
|
["_Test Account Excise Duty - TCP1", 12.0 , 0.0, nowdate()],
|
||||||
# ["Unrealized Profit - TCP1", 0.0, 12.0, nowdate()]
|
["Unrealized Profit - TCP1", 0.0, 12.0, nowdate()]
|
||||||
# ]
|
]
|
||||||
|
|
||||||
# check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1))
|
check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1))
|
||||||
|
|
||||||
def test_eway_bill_json(self):
|
def test_eway_bill_json(self):
|
||||||
si = make_sales_invoice_for_ewaybill()
|
si = make_sales_invoice_for_ewaybill()
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ class BuyingController(StockController):
|
|||||||
self.validate_items()
|
self.validate_items()
|
||||||
self.set_qty_as_per_stock_uom()
|
self.set_qty_as_per_stock_uom()
|
||||||
self.validate_stock_or_nonstock_items()
|
self.validate_stock_or_nonstock_items()
|
||||||
self.update_tax_category_for_internal_transfer()
|
|
||||||
self.validate_warehouse()
|
self.validate_warehouse()
|
||||||
self.validate_from_warehouse()
|
self.validate_from_warehouse()
|
||||||
self.set_supplier_address()
|
self.set_supplier_address()
|
||||||
@@ -67,6 +66,8 @@ class BuyingController(StockController):
|
|||||||
if self.doctype in ("Purchase Receipt", "Purchase Invoice"):
|
if self.doctype in ("Purchase Receipt", "Purchase Invoice"):
|
||||||
self.update_valuation_rate()
|
self.update_valuation_rate()
|
||||||
|
|
||||||
|
self.set_out_going_rate()
|
||||||
|
|
||||||
def set_missing_values(self, for_validate=False):
|
def set_missing_values(self, for_validate=False):
|
||||||
super(BuyingController, self).set_missing_values(for_validate)
|
super(BuyingController, self).set_missing_values(for_validate)
|
||||||
|
|
||||||
@@ -100,11 +101,6 @@ class BuyingController(StockController):
|
|||||||
msg = _('Tax Category has been changed to "Total" because all the Items are non-stock items')
|
msg = _('Tax Category has been changed to "Total" because all the Items are non-stock items')
|
||||||
self.update_tax_category(msg)
|
self.update_tax_category(msg)
|
||||||
|
|
||||||
def update_tax_category_for_internal_transfer(self):
|
|
||||||
if self.doctype == 'Purchase Invoice' and self.is_internal_transfer():
|
|
||||||
msg = _('Tax Category has been changed to "Total" as its an internal purchase.')
|
|
||||||
self.update_tax_category(msg)
|
|
||||||
|
|
||||||
def update_tax_category(self, msg):
|
def update_tax_category(self, msg):
|
||||||
tax_for_valuation = [d for d in self.get("taxes")
|
tax_for_valuation = [d for d in self.get("taxes")
|
||||||
if d.category in ["Valuation", "Valuation and Total"]]
|
if d.category in ["Valuation", "Valuation and Total"]]
|
||||||
@@ -224,6 +220,32 @@ class BuyingController(StockController):
|
|||||||
else:
|
else:
|
||||||
item.valuation_rate = 0.0
|
item.valuation_rate = 0.0
|
||||||
|
|
||||||
|
def set_out_going_rate(self):
|
||||||
|
if self.doctype not in ("Purchase Receipt", "Purchase Invoice"):
|
||||||
|
return
|
||||||
|
|
||||||
|
items = self.get("items")
|
||||||
|
for d in items:
|
||||||
|
if not cint(self.get("is_return")) and d.get("target_warehouse"):
|
||||||
|
# Get outgoing rate based on original item cost based on valuation method
|
||||||
|
d.outgoing_rate = get_incoming_rate({
|
||||||
|
"item_code": d.item_code,
|
||||||
|
"warehouse": d.target_warehouse,
|
||||||
|
"posting_date": self.posting_date,
|
||||||
|
"posting_time": self.posting_time,
|
||||||
|
"qty": -1 * flt(d.qty),
|
||||||
|
"serial_no": d.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)
|
||||||
|
|
||||||
|
elif self.get("return_against"):
|
||||||
|
# Get incoming rate of return entry from reference document
|
||||||
|
# based on original item cost as per valuation method
|
||||||
|
d.outgoing_rate = get_rate_for_return(self.doctype, self.name, d.item_code, self.return_against, item_row=d)
|
||||||
|
|
||||||
def get_supplied_items_cost(self, item_row_id, reset_outgoing_rate=True):
|
def get_supplied_items_cost(self, item_row_id, reset_outgoing_rate=True):
|
||||||
supplied_items_cost = 0.0
|
supplied_items_cost = 0.0
|
||||||
for d in self.get("supplied_items"):
|
for d in self.get("supplied_items"):
|
||||||
@@ -559,6 +581,7 @@ class BuyingController(StockController):
|
|||||||
from_warehouse_sle = self.get_sl_entries(d, {
|
from_warehouse_sle = self.get_sl_entries(d, {
|
||||||
"actual_qty": -1 * pr_qty,
|
"actual_qty": -1 * pr_qty,
|
||||||
"warehouse": d.from_warehouse,
|
"warehouse": d.from_warehouse,
|
||||||
|
"outgoing_rate": d.outgoing_rate,
|
||||||
"dependant_sle_voucher_detail_no": d.name
|
"dependant_sle_voucher_detail_no": d.name
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -569,10 +592,8 @@ class BuyingController(StockController):
|
|||||||
"serial_no": cstr(d.serial_no).strip()
|
"serial_no": cstr(d.serial_no).strip()
|
||||||
})
|
})
|
||||||
if self.is_return:
|
if self.is_return:
|
||||||
outgoing_rate = get_rate_for_return(self.doctype, self.name, d.item_code, self.return_against, item_row=d)
|
|
||||||
|
|
||||||
sle.update({
|
sle.update({
|
||||||
"outgoing_rate": outgoing_rate,
|
"outgoing_rate": d.outgoing_rate,
|
||||||
"recalculate_rate": 1
|
"recalculate_rate": 1
|
||||||
})
|
})
|
||||||
if d.from_warehouse:
|
if d.from_warehouse:
|
||||||
|
|||||||
@@ -331,6 +331,12 @@ class SellingController(StockController):
|
|||||||
"voucher_no": self.name,
|
"voucher_no": self.name,
|
||||||
"allow_zero_valuation": d.get("allow_zero_valuation")
|
"allow_zero_valuation": d.get("allow_zero_valuation")
|
||||||
}, raise_error_if_no_rate=False)
|
}, raise_error_if_no_rate=False)
|
||||||
|
|
||||||
|
# For internal transfers use incoming rate as the valuation rate
|
||||||
|
if self.get('is_internal_customer') and d.get('target_warehouse'):
|
||||||
|
d.rate = d.incoming_rate
|
||||||
|
frappe.msgprint(_("Row {0}: Item rate updated as the valuation rate since its an internal transfer").format(d.idx))
|
||||||
|
|
||||||
elif self.get("return_against"):
|
elif self.get("return_against"):
|
||||||
# Get incoming rate of return entry from reference document
|
# Get incoming rate of return entry from reference document
|
||||||
# based on original item cost as per valuation method
|
# based on original item cost as per valuation method
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class StockController(AccountsController):
|
|||||||
warehouse_with_no_account = []
|
warehouse_with_no_account = []
|
||||||
precision = frappe.get_precision("GL Entry", "debit_in_account_currency")
|
precision = frappe.get_precision("GL Entry", "debit_in_account_currency")
|
||||||
for item_row in voucher_details:
|
for item_row in voucher_details:
|
||||||
sle_list = sle_map.get(item_row.name)
|
sle_list = sle_map.get((item_row.name, item_row.warehouse))
|
||||||
if sle_list:
|
if sle_list:
|
||||||
for sle in sle_list:
|
for sle in sle_list:
|
||||||
if warehouse_account.get(sle.warehouse):
|
if warehouse_account.get(sle.warehouse):
|
||||||
@@ -216,7 +216,7 @@ class StockController(AccountsController):
|
|||||||
""", (self.doctype, self.name), as_dict=True)
|
""", (self.doctype, self.name), as_dict=True)
|
||||||
|
|
||||||
for sle in stock_ledger_entries:
|
for sle in stock_ledger_entries:
|
||||||
stock_ledger.setdefault(sle.voucher_detail_no, []).append(sle)
|
stock_ledger.setdefault((sle.voucher_detail_no, sle.warehouse), []).append(sle)
|
||||||
return stock_ledger
|
return stock_ledger
|
||||||
|
|
||||||
def make_batches(self, warehouse_field):
|
def make_batches(self, warehouse_field):
|
||||||
|
|||||||
@@ -56,6 +56,7 @@
|
|||||||
"column_break_32",
|
"column_break_32",
|
||||||
"base_net_rate",
|
"base_net_rate",
|
||||||
"base_net_amount",
|
"base_net_amount",
|
||||||
|
"outgoing_rate",
|
||||||
"valuation_rate",
|
"valuation_rate",
|
||||||
"item_tax_amount",
|
"item_tax_amount",
|
||||||
"rm_supp_cost",
|
"rm_supp_cost",
|
||||||
@@ -861,12 +862,18 @@
|
|||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "Received Qty in Stock UOM",
|
"label": "Received Qty in Stock UOM",
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "outgoing_rate",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Outgoing Rate",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-12-07 10:00:38.204294",
|
"modified": "2020-12-23 17:33:19.479325",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Purchase Receipt Item",
|
"name": "Purchase Receipt Item",
|
||||||
|
|||||||
Reference in New Issue
Block a user