Merge branch 'develop' of https://github.com/frappe/erpnext into asset_purchase_receipt_gl
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index e8fc445..2f08b65 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -33,7 +33,7 @@
)
from erpnext.accounts.party import get_due_date, get_party_account
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
-from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_enabled
+from erpnext.assets.doctype.asset.asset import is_cwip_accounting_enabled
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
from erpnext.buying.utils import check_on_hold_or_closed_status
from erpnext.controllers.accounts_controller import validate_account_head
@@ -281,9 +281,6 @@
# in case of auto inventory accounting,
# expense account is always "Stock Received But Not Billed" for a stock item
# except opening entry, drop-ship entry and fixed asset items
- if item.item_code:
- asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category")
-
if (
auto_accounting_for_stock
and item.item_code in stock_items
@@ -350,22 +347,26 @@
frappe.msgprint(msg, title=_("Expense Head Changed"))
item.expense_account = stock_not_billed_account
-
- elif item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category):
+ elif item.is_fixed_asset and item.pr_detail:
+ if not asset_received_but_not_billed:
+ asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed")
+ item.expense_account = asset_received_but_not_billed
+ elif item.is_fixed_asset:
+ account_type = (
+ "capital_work_in_progress_account"
+ if is_cwip_accounting_enabled(item.asset_category)
+ else "fixed_asset_account"
+ )
asset_category_account = get_asset_category_account(
- "fixed_asset_account", item=item.item_code, company=self.company
+ account_type, item=item.item_code, company=self.company
)
if not asset_category_account:
- form_link = get_link_to_form("Asset Category", asset_category)
+ form_link = get_link_to_form("Asset Category", item.asset_category)
throw(
_("Please set Fixed Asset Account in {} against {}.").format(form_link, self.company),
title=_("Missing Account"),
)
item.expense_account = asset_category_account
- elif item.is_fixed_asset and item.pr_detail:
- if not asset_received_but_not_billed:
- asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed")
- item.expense_account = asset_received_but_not_billed
elif not item.expense_account and for_validate:
throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name))
@@ -587,6 +588,7 @@
if self.auto_accounting_for_stock:
self.stock_received_but_not_billed = self.get_company_default("stock_received_but_not_billed")
self.expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
+ self.asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed")
else:
self.stock_received_but_not_billed = None
self.expenses_included_in_valuation = None
@@ -598,9 +600,6 @@
self.make_item_gl_entries(gl_entries)
self.make_precision_loss_gl_entry(gl_entries)
- if self.check_asset_cwip_enabled():
- self.get_asset_gl_entry(gl_entries)
-
self.make_tax_gl_entries(gl_entries)
self.make_internal_transfer_gl_entries(gl_entries)
@@ -702,7 +701,11 @@
if item.item_code:
asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category")
- if self.update_stock and self.auto_accounting_for_stock and item.item_code in stock_items:
+ if (
+ self.update_stock
+ and self.auto_accounting_for_stock
+ and (item.item_code in stock_items or item.is_fixed_asset)
+ ):
# warehouse account
warehouse_debit_amount = self.make_stock_adjustment_entry(
gl_entries, item, voucher_wise_stock_value, account_currency
@@ -817,9 +820,7 @@
)
)
- elif not item.is_fixed_asset or (
- item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category)
- ):
+ else:
expense_account = (
item.expense_account
if (not item.enable_deferred_expense or self.is_return)
@@ -970,11 +971,16 @@
(item.purchase_receipt, valuation_tax_accounts),
)
+ stock_rbnb = (
+ self.asset_received_but_not_billed
+ if item.is_fixed_asset
+ else self.stock_received_but_not_billed
+ )
if not negative_expense_booked_in_pr:
gl_entries.append(
self.get_gl_dict(
{
- "account": self.stock_received_but_not_billed,
+ "account": stock_rbnb,
"against": self.supplier,
"debit": flt(item.item_tax_amount, item.precision("item_tax_amount")),
"remarks": self.remarks or _("Accounting Entry for Stock"),
@@ -989,156 +995,12 @@
item.item_tax_amount, item.precision("item_tax_amount")
)
- def get_asset_gl_entry(self, gl_entries):
- arbnb_account = None
- eiiav_account = None
- asset_eiiav_currency = None
-
- for item in self.get("items"):
- if item.is_fixed_asset:
- asset_amount = flt(item.net_amount) + flt(item.item_tax_amount / self.conversion_rate)
- base_asset_amount = flt(item.base_net_amount + item.item_tax_amount)
-
- item_exp_acc_type = frappe.get_cached_value("Account", item.expense_account, "account_type")
- if not item.expense_account or item_exp_acc_type not in [
- "Asset Received But Not Billed",
- "Fixed Asset",
- ]:
- if not arbnb_account:
- arbnb_account = self.get_company_default("asset_received_but_not_billed")
- item.expense_account = arbnb_account
-
- if not self.update_stock:
- arbnb_currency = get_account_currency(item.expense_account)
- gl_entries.append(
- self.get_gl_dict(
- {
- "account": item.expense_account,
- "against": self.supplier,
- "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
- "debit": base_asset_amount,
- "debit_in_account_currency": (
- base_asset_amount if arbnb_currency == self.company_currency else asset_amount
- ),
- "cost_center": item.cost_center,
- "project": item.project or self.project,
- },
- item=item,
- )
- )
-
- if item.item_tax_amount:
- if not eiiav_account or not asset_eiiav_currency:
- eiiav_account = self.get_company_default("expenses_included_in_asset_valuation")
- asset_eiiav_currency = get_account_currency(eiiav_account)
-
- gl_entries.append(
- self.get_gl_dict(
- {
- "account": eiiav_account,
- "against": self.supplier,
- "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
- "cost_center": item.cost_center,
- "project": item.project or self.project,
- "credit": item.item_tax_amount,
- "credit_in_account_currency": (
- item.item_tax_amount
- if asset_eiiav_currency == self.company_currency
- else item.item_tax_amount / self.conversion_rate
- ),
- },
- item=item,
- )
- )
- else:
- cwip_account = get_asset_account(
- "capital_work_in_progress_account", asset_category=item.asset_category, company=self.company
- )
-
- cwip_account_currency = get_account_currency(cwip_account)
- gl_entries.append(
- self.get_gl_dict(
- {
- "account": cwip_account,
- "against": self.supplier,
- "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
- "debit": base_asset_amount,
- "debit_in_account_currency": (
- base_asset_amount if cwip_account_currency == self.company_currency else asset_amount
- ),
- "cost_center": item.cost_center or self.cost_center,
- "project": item.project or self.project,
- },
- item=item,
- )
- )
-
- if item.item_tax_amount and not cint(erpnext.is_perpetual_inventory_enabled(self.company)):
- if not eiiav_account or not asset_eiiav_currency:
- eiiav_account = self.get_company_default("expenses_included_in_asset_valuation")
- asset_eiiav_currency = get_account_currency(eiiav_account)
-
- gl_entries.append(
- self.get_gl_dict(
- {
- "account": eiiav_account,
- "against": self.supplier,
- "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
- "cost_center": item.cost_center,
- "credit": item.item_tax_amount,
- "project": item.project or self.project,
- "credit_in_account_currency": (
- item.item_tax_amount
- if asset_eiiav_currency == self.company_currency
- else item.item_tax_amount / self.conversion_rate
- ),
- },
- item=item,
- )
- )
-
- # Assets are bought through this document then it will be linked to this document
- if flt(item.landed_cost_voucher_amount):
- if not eiiav_account:
- eiiav_account = self.get_company_default("expenses_included_in_asset_valuation")
-
- gl_entries.append(
- self.get_gl_dict(
- {
- "account": eiiav_account,
- "against": cwip_account,
- "cost_center": item.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": flt(item.landed_cost_voucher_amount),
- "project": item.project or self.project,
- },
- item=item,
- )
- )
-
- gl_entries.append(
- self.get_gl_dict(
- {
- "account": cwip_account,
- "against": eiiav_account,
- "cost_center": item.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "debit": flt(item.landed_cost_voucher_amount),
- "project": item.project or self.project,
- },
- item=item,
- )
- )
-
- # update gross amount of assets bought through this document
- assets = frappe.db.get_all(
- "Asset", filters={"purchase_invoice": self.name, "item_code": item.item_code}
- )
- for asset in assets:
- frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(item.valuation_rate))
- frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate))
-
- return gl_entries
+ assets = frappe.db.get_all(
+ "Asset", filters={"purchase_invoice": self.name, "item_code": item.item_code}
+ )
+ for asset in assets:
+ frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(item.valuation_rate))
+ frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate))
def make_stock_adjustment_entry(
self, gl_entries, item, voucher_wise_stock_value, account_currency
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index d496778..70a8470 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -41,7 +41,7 @@
from_repost=from_repost,
)
save_entries(gl_map, adv_adj, update_outstanding, from_repost)
- # Post GL Map proccess there may no be any GL Entries
+ # Post GL Map process there may no be any GL Entries
elif gl_map:
frappe.throw(
_(
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 9eeffd8..98d8248 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -73,11 +73,7 @@
gl_entries = self.get_gl_entries(warehouse_account)
make_gl_entries(gl_entries, from_repost=from_repost)
- elif self.doctype in ["Purchase Receipt", "Purchase Invoice"] and self.docstatus == 1:
- gl_entries = []
- gl_entries = self.get_asset_gl_entry(gl_entries)
- update_regional_gl_entries(gl_entries, self)
- make_gl_entries(gl_entries, from_repost=from_repost)
+ update_regional_gl_entries(gl_entries, self)
def validate_serialized_batch(self):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 3734892..9fe06a2 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -144,8 +144,8 @@
if item.is_fixed_asset and is_cwip_accounting_enabled(item.asset_category):
# check cwip accounts before making auto assets
# Improves UX by not giving messages of "Assets Created" before throwing error of not finding arbnb account
- arbnb_account = self.get_company_default("asset_received_but_not_billed")
- cwip_account = get_asset_account(
+ self.get_company_default("asset_received_but_not_billed")
+ get_asset_account(
"capital_work_in_progress_account", asset_category=item.asset_category, company=self.company
)
break
@@ -313,8 +313,6 @@
self.make_item_gl_entries(gl_entries, warehouse_account=warehouse_account)
self.make_tax_gl_entries(gl_entries)
- self.get_asset_gl_entry(gl_entries)
- update_regional_gl_entries(gl_entries, self)
return process_gl_map(gl_entries)
@@ -323,11 +321,19 @@
get_purchase_document_details,
)
- stock_rbnb = None
+ is_asset_pr = any(d.is_fixed_asset for d in self.get("items"))
+ stock_asset_rbnb = None
+ remarks = self.get("remarks") or _("Accounting Entry for {0}").format(
+ "Asset" if is_asset_pr else "Stock"
+ )
+
if erpnext.is_perpetual_inventory_enabled(self.company):
- stock_rbnb = self.get_company_default("stock_received_but_not_billed")
+ stock_asset_rbnb = (
+ self.get_company_default("asset_received_but_not_billed")
+ if is_asset_pr
+ else self.get_company_default("stock_received_but_not_billed")
+ )
landed_cost_entries = get_item_account_wise_additional_cost(self.name)
- expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
warehouse_with_no_account = []
stock_items = self.get_stock_items()
@@ -339,236 +345,195 @@
exchange_rate_map, net_rate_map = get_purchase_document_details(self)
- for d in self.get("items"):
- if d.item_code in stock_items and flt(d.qty) and (flt(d.valuation_rate) or self.is_return):
- if warehouse_account.get(d.warehouse):
- stock_value_diff = frappe.db.get_value(
- "Stock Ledger Entry",
- {
- "voucher_type": "Purchase Receipt",
- "voucher_no": self.name,
- "voucher_detail_no": d.name,
- "warehouse": d.warehouse,
- "is_cancelled": 0,
- },
- "stock_value_difference",
- )
+ def make_item_asset_inward_entries(item, stock_value_diff, stock_asset_account_name):
+ account_currency = get_account_currency(stock_asset_account_name)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=stock_asset_account_name,
+ cost_center=d.cost_center,
+ debit=stock_value_diff,
+ credit=0.0,
+ remarks=remarks,
+ against_account=stock_asset_rbnb,
+ account_currency=account_currency,
+ item=item,
+ )
- warehouse_account_name = warehouse_account[d.warehouse]["account"]
- warehouse_account_currency = warehouse_account[d.warehouse]["account_currency"]
- supplier_warehouse_account = warehouse_account.get(self.supplier_warehouse, {}).get("account")
- supplier_warehouse_account_currency = warehouse_account.get(self.supplier_warehouse, {}).get(
- "account_currency"
- )
- remarks = self.get("remarks") or _("Accounting Entry for Stock")
+ def make_stock_received_but_not_billed_entry(item):
+ account = (
+ warehouse_account[item.from_warehouse]["account"] if item.from_warehouse else stock_asset_rbnb
+ )
+ account_currency = get_account_currency(account)
- # If PR is sub-contracted and fg item rate is zero
- # in that case if account for source and target warehouse are same,
- # then GL entries should not be posted
+ outgoing_amount = item.base_net_amount
+ # GL Entry for from warehouse or Stock Received but not billed
+ # Intentionally passed negative debit amount to avoid incorrect GL Entry validation
+ credit_amount = (
+ flt(item.base_net_amount, item.precision("base_net_amount"))
+ if account_currency == self.company_currency
+ else flt(item.net_amount, item.precision("net_amount"))
+ )
+
+ if self.is_internal_transfer() and item.valuation_rate:
+ outgoing_amount = abs(get_stock_value_difference(self.name, item.name, item.from_warehouse))
+ credit_amount = outgoing_amount
+
+ if credit_amount:
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=account,
+ cost_center=item.cost_center,
+ debit=-1 * flt(outgoing_amount, item.precision("base_net_amount")),
+ credit=0.0,
+ remarks=remarks,
+ against_account=stock_asset_account_name,
+ debit_in_account_currency=-1 * credit_amount,
+ account_currency=account_currency,
+ item=item,
+ )
+
+ # check if the exchange rate has changed
+ if d.get("purchase_invoice"):
if (
- flt(stock_value_diff) == flt(d.rm_supp_cost)
- and warehouse_account.get(self.supplier_warehouse)
- and warehouse_account_name == supplier_warehouse_account
+ exchange_rate_map[item.purchase_invoice]
+ and self.conversion_rate != exchange_rate_map[item.purchase_invoice]
+ and item.net_rate == net_rate_map[item.purchase_invoice_item]
):
- continue
- self.add_gl_entry(
- gl_entries=gl_entries,
- account=warehouse_account_name,
- cost_center=d.cost_center,
- debit=stock_value_diff,
- credit=0.0,
- remarks=remarks,
- against_account=stock_rbnb,
- account_currency=warehouse_account_currency,
- item=d,
- )
-
- # GL Entry for from warehouse or Stock Received but not billed
- # Intentionally passed negative debit amount to avoid incorrect GL Entry validation
- credit_currency = (
- get_account_currency(warehouse_account[d.from_warehouse]["account"])
- if d.from_warehouse
- else get_account_currency(stock_rbnb)
- )
-
- credit_amount = (
- flt(d.base_net_amount, d.precision("base_net_amount"))
- if credit_currency == self.company_currency
- else flt(d.net_amount, d.precision("net_amount"))
- )
-
- outgoing_amount = d.base_net_amount
- if self.is_internal_transfer() and d.valuation_rate:
- outgoing_amount = abs(
- frappe.db.get_value(
- "Stock Ledger Entry",
- {
- "voucher_type": "Purchase Receipt",
- "voucher_no": self.name,
- "voucher_detail_no": d.name,
- "warehouse": d.from_warehouse,
- "is_cancelled": 0,
- },
- "stock_value_difference",
- )
+ discrepancy_caused_by_exchange_rate_difference = (item.qty * item.net_rate) * (
+ exchange_rate_map[item.purchase_invoice] - self.conversion_rate
)
- credit_amount = outgoing_amount
-
- if credit_amount:
- account = warehouse_account[d.from_warehouse]["account"] if d.from_warehouse else stock_rbnb
self.add_gl_entry(
gl_entries=gl_entries,
account=account,
- cost_center=d.cost_center,
- debit=-1 * flt(outgoing_amount, d.precision("base_net_amount")),
- credit=0.0,
- remarks=remarks,
- against_account=warehouse_account_name,
- debit_in_account_currency=-1 * credit_amount,
- account_currency=credit_currency,
- item=d,
- )
-
- # check if the exchange rate has changed
- if d.get("purchase_invoice"):
- if (
- exchange_rate_map[d.purchase_invoice]
- and self.conversion_rate != exchange_rate_map[d.purchase_invoice]
- and d.net_rate == net_rate_map[d.purchase_invoice_item]
- ):
-
- discrepancy_caused_by_exchange_rate_difference = (d.qty * d.net_rate) * (
- exchange_rate_map[d.purchase_invoice] - self.conversion_rate
- )
-
- self.add_gl_entry(
- gl_entries=gl_entries,
- account=account,
- cost_center=d.cost_center,
- debit=0.0,
- credit=discrepancy_caused_by_exchange_rate_difference,
- remarks=remarks,
- against_account=self.supplier,
- debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
- account_currency=credit_currency,
- item=d,
- )
-
- self.add_gl_entry(
- gl_entries=gl_entries,
- account=self.get_company_default("exchange_gain_loss_account"),
- cost_center=d.cost_center,
- debit=discrepancy_caused_by_exchange_rate_difference,
- credit=0.0,
- remarks=remarks,
- against_account=self.supplier,
- debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
- account_currency=credit_currency,
- item=d,
- )
-
- # Amount added through landed-cos-voucher
- if d.landed_cost_voucher_amount and landed_cost_entries:
- if (d.item_code, d.name) in landed_cost_entries:
- for account, amount in landed_cost_entries[(d.item_code, d.name)].items():
- account_currency = get_account_currency(account)
- credit_amount = (
- flt(amount["base_amount"])
- if (amount["base_amount"] or account_currency != self.company_currency)
- else flt(amount["amount"])
- )
-
- self.add_gl_entry(
- gl_entries=gl_entries,
- account=account,
- cost_center=d.cost_center,
- debit=0.0,
- credit=credit_amount,
- remarks=remarks,
- against_account=warehouse_account_name,
- credit_in_account_currency=flt(amount["amount"]),
- account_currency=account_currency,
- project=d.project,
- item=d,
- )
-
- if d.rate_difference_with_purchase_invoice and stock_rbnb:
- account_currency = get_account_currency(stock_rbnb)
- self.add_gl_entry(
- gl_entries=gl_entries,
- account=stock_rbnb,
- cost_center=d.cost_center,
+ cost_center=item.cost_center,
debit=0.0,
- credit=flt(d.rate_difference_with_purchase_invoice),
- remarks=_("Adjustment based on Purchase Invoice rate"),
- against_account=warehouse_account_name,
+ credit=discrepancy_caused_by_exchange_rate_difference,
+ remarks=remarks,
+ against_account=self.supplier,
+ debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
account_currency=account_currency,
- project=d.project,
- item=d,
+ item=item,
)
- # sub-contracting warehouse
- if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
self.add_gl_entry(
gl_entries=gl_entries,
- account=supplier_warehouse_account,
+ account=self.get_company_default("exchange_gain_loss_account"),
cost_center=d.cost_center,
- debit=0.0,
- credit=flt(d.rm_supp_cost),
- remarks=remarks,
- against_account=warehouse_account_name,
- account_currency=supplier_warehouse_account_currency,
- item=d,
- )
-
- # divisional loss adjustment
- valuation_amount_as_per_doc = (
- flt(outgoing_amount, d.precision("base_net_amount"))
- + flt(d.landed_cost_voucher_amount)
- + flt(d.rm_supp_cost)
- + flt(d.item_tax_amount)
- + flt(d.rate_difference_with_purchase_invoice)
- )
-
- divisional_loss = flt(
- valuation_amount_as_per_doc - flt(stock_value_diff), d.precision("base_net_amount")
- )
-
- if divisional_loss:
- if self.is_return or flt(d.item_tax_amount):
- loss_account = expenses_included_in_valuation
- else:
- loss_account = (
- self.get_company_default("default_expense_account", ignore_validation=True) or stock_rbnb
- )
-
- cost_center = d.cost_center or frappe.get_cached_value(
- "Company", self.company, "cost_center"
- )
-
- self.add_gl_entry(
- gl_entries=gl_entries,
- account=loss_account,
- cost_center=cost_center,
- debit=divisional_loss,
+ debit=discrepancy_caused_by_exchange_rate_difference,
credit=0.0,
remarks=remarks,
- against_account=warehouse_account_name,
- account_currency=credit_currency,
- project=d.project,
- item=d,
+ against_account=self.supplier,
+ debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
+ account_currency=account_currency,
+ item=item,
)
- elif (
- d.warehouse not in warehouse_with_no_account
- or d.rejected_warehouse not in warehouse_with_no_account
- ):
- warehouse_with_no_account.append(d.warehouse)
- elif (
+ def make_landed_cost_gl_entries(item):
+ # Amount added through landed-cos-voucher
+ if item.landed_cost_voucher_amount and landed_cost_entries:
+ if (item.item_code, item.name) in landed_cost_entries:
+ for account, amount in landed_cost_entries[(item.item_code, item.name)].items():
+ account_currency = get_account_currency(account)
+ credit_amount = (
+ flt(amount["base_amount"])
+ if (amount["base_amount"] or account_currency != self.company_currency)
+ else flt(amount["amount"])
+ )
+
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=account,
+ cost_center=item.cost_center,
+ debit=0.0,
+ credit=credit_amount,
+ remarks=remarks,
+ against_account=stock_asset_account_name,
+ credit_in_account_currency=flt(amount["amount"]),
+ account_currency=account_currency,
+ project=item.project,
+ item=item,
+ )
+
+ def make_rate_difference_entry(item):
+ if item.rate_difference_with_purchase_invoice and stock_asset_rbnb:
+ account_currency = get_account_currency(stock_asset_rbnb)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=stock_asset_rbnb,
+ cost_center=item.cost_center,
+ debit=0.0,
+ credit=flt(item.rate_difference_with_purchase_invoice),
+ remarks=_("Adjustment based on Purchase Invoice rate"),
+ against_account=stock_asset_account_name,
+ account_currency=account_currency,
+ project=item.project,
+ item=item,
+ )
+
+ def make_sub_contracting_gl_entries(item):
+ # sub-contracting warehouse
+ if flt(item.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=supplier_warehouse_account,
+ cost_center=item.cost_center,
+ debit=0.0,
+ credit=flt(item.rm_supp_cost),
+ remarks=remarks,
+ against_account=stock_asset_account_name,
+ account_currency=supplier_warehouse_account_currency,
+ item=item,
+ )
+
+ def make_divisional_loss_gl_entry(item):
+ if item.is_fixed_asset:
+ return
+
+ # divisional loss adjustment
+ expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
+ valuation_amount_as_per_doc = (
+ flt(item.base_net_amount, d.precision("base_net_amount"))
+ + flt(item.landed_cost_voucher_amount)
+ + flt(item.rm_supp_cost)
+ + flt(item.item_tax_amount)
+ + flt(item.rate_difference_with_purchase_invoice)
+ )
+
+ divisional_loss = flt(
+ valuation_amount_as_per_doc - flt(stock_value_diff), item.precision("base_net_amount")
+ )
+
+ if divisional_loss:
+ if self.is_return or flt(item.item_tax_amount):
+ loss_account = expenses_included_in_valuation
+ else:
+ loss_account = (
+ self.get_company_default("default_expense_account", ignore_validation=True)
+ or stock_asset_rbnb
+ )
+
+ cost_center = item.cost_center or frappe.get_cached_value(
+ "Company", self.company, "cost_center"
+ )
+ account_currency = get_account_currency(loss_account)
+ self.add_gl_entry(
+ gl_entries=gl_entries,
+ account=loss_account,
+ cost_center=cost_center,
+ debit=divisional_loss,
+ credit=0.0,
+ remarks=remarks,
+ against_account=stock_asset_account_name,
+ account_currency=account_currency,
+ project=item.project,
+ item=item,
+ )
+
+ for d in self.get("items"):
+ if (
d.item_code not in stock_items
- and not d.is_fixed_asset
and flt(d.qty)
and provisional_accounting_for_non_stock_items
and d.get("provisional_expense_account")
@@ -576,6 +541,56 @@
self.add_provisional_gl_entry(
d, gl_entries, self.posting_date, d.get("provisional_expense_account")
)
+ elif flt(d.qty) and (flt(d.valuation_rate) or self.is_return):
+ if d.is_fixed_asset:
+ account_type = (
+ "capital_work_in_progress_account"
+ if is_cwip_accounting_enabled(d.asset_category)
+ else "fixed_asset_account"
+ )
+ stock_asset_account_name = get_asset_category_account(
+ asset_category=d.asset_category,
+ fieldname=account_type,
+ company=self.company,
+ )
+
+ stock_value_diff = flt(d.net_amount) + flt(d.item_tax_amount / self.conversion_rate)
+ elif (
+ (flt(d.valuation_rate) or self.is_return)
+ and flt(d.qty)
+ and warehouse_account.get(d.warehouse)
+ ):
+ stock_value_diff = get_stock_value_difference(self.name, d.name, d.warehouse)
+ stock_asset_account_name = warehouse_account[d.warehouse]["account"]
+ supplier_warehouse_account = warehouse_account.get(self.supplier_warehouse, {}).get("account")
+ supplier_warehouse_account_currency = warehouse_account.get(self.supplier_warehouse, {}).get(
+ "account_currency"
+ )
+
+ # If PR is sub-contracted and fg item rate is zero
+ # in that case if account for source and target warehouse are same,
+ # then GL entries should not be posted
+ if (
+ flt(stock_value_diff) == flt(d.rm_supp_cost)
+ and warehouse_account.get(self.supplier_warehouse)
+ and stock_asset_account_name == supplier_warehouse_account
+ ):
+ continue
+
+ make_item_asset_inward_entries(d, stock_value_diff, stock_asset_account_name)
+ make_stock_received_but_not_billed_entry(d)
+ make_landed_cost_gl_entries(d)
+ make_rate_difference_entry(d)
+ make_sub_contracting_gl_entries(d)
+ make_divisional_loss_gl_entry(d)
+ elif (
+ d.warehouse not in warehouse_with_no_account
+ or d.rejected_warehouse not in warehouse_with_no_account
+ ):
+ warehouse_with_no_account.append(d.warehouse)
+
+ if d.is_fixed_asset:
+ self.update_assets(d, d.valuation_rate)
if warehouse_with_no_account:
frappe.msgprint(
@@ -701,103 +716,6 @@
i += 1
- def get_asset_gl_entry(self, gl_entries):
- for item in self.get("items"):
- if item.is_fixed_asset:
- if is_cwip_accounting_enabled(item.asset_category):
- self.add_asset_gl_entries(item, gl_entries)
- if flt(item.landed_cost_voucher_amount):
- self.add_lcv_gl_entries(item, gl_entries)
- # update assets gross amount by its valuation rate
- # valuation rate is total of net rate, raw mat supp cost, tax amount, lcv amount per item
- self.update_assets(item, item.valuation_rate)
- return gl_entries
-
- def add_asset_gl_entries(self, item, gl_entries):
- arbnb_account = self.get_company_default("asset_received_but_not_billed")
- # This returns category's cwip account if not then fallback to company's default cwip account
- cwip_account = get_asset_account(
- "capital_work_in_progress_account", asset_category=item.asset_category, company=self.company
- )
-
- asset_amount = flt(item.net_amount) + flt(item.item_tax_amount / self.conversion_rate)
- base_asset_amount = flt(item.base_net_amount + item.item_tax_amount)
- remarks = self.get("remarks") or _("Accounting Entry for Asset")
-
- cwip_account_currency = get_account_currency(cwip_account)
- # debit cwip account
- debit_in_account_currency = (
- base_asset_amount if cwip_account_currency == self.company_currency else asset_amount
- )
-
- self.add_gl_entry(
- gl_entries=gl_entries,
- account=cwip_account,
- cost_center=item.cost_center,
- debit=base_asset_amount,
- credit=0.0,
- remarks=remarks,
- against_account=arbnb_account,
- debit_in_account_currency=debit_in_account_currency,
- item=item,
- )
-
- asset_rbnb_currency = get_account_currency(arbnb_account)
- # credit arbnb account
- credit_in_account_currency = (
- base_asset_amount if asset_rbnb_currency == self.company_currency else asset_amount
- )
-
- self.add_gl_entry(
- gl_entries=gl_entries,
- account=arbnb_account,
- cost_center=item.cost_center,
- debit=0.0,
- credit=base_asset_amount,
- remarks=remarks,
- against_account=cwip_account,
- credit_in_account_currency=credit_in_account_currency,
- item=item,
- )
-
- def add_lcv_gl_entries(self, item, gl_entries):
- expenses_included_in_asset_valuation = self.get_company_default(
- "expenses_included_in_asset_valuation"
- )
- if not is_cwip_accounting_enabled(item.asset_category):
- asset_account = get_asset_category_account(
- asset_category=item.asset_category, fieldname="fixed_asset_account", company=self.company
- )
- else:
- # This returns company's default cwip account
- asset_account = get_asset_account("capital_work_in_progress_account", company=self.company)
-
- remarks = self.get("remarks") or _("Accounting Entry for Stock")
-
- self.add_gl_entry(
- gl_entries=gl_entries,
- account=expenses_included_in_asset_valuation,
- cost_center=item.cost_center,
- debit=0.0,
- credit=flt(item.landed_cost_voucher_amount),
- remarks=remarks,
- against_account=asset_account,
- project=item.project,
- item=item,
- )
-
- self.add_gl_entry(
- gl_entries=gl_entries,
- account=asset_account,
- cost_center=item.cost_center,
- debit=flt(item.landed_cost_voucher_amount),
- credit=0.0,
- remarks=remarks,
- against_account=expenses_included_in_asset_valuation,
- project=item.project,
- item=item,
- )
-
def update_assets(self, item, valuation_rate):
assets = frappe.db.get_all(
"Asset", filters={"purchase_receipt": self.name, "item_code": item.item_code}
@@ -822,14 +740,30 @@
po_details.append(d.purchase_order_item)
if po_details:
- updated_pr += update_billed_amount_based_on_po(po_details, update_modified, self)
+ updated_pr += update_billed_amount_based_on_po(po_details, update_modified)
for pr in set(updated_pr):
pr_doc = self if (pr == self.name) else frappe.get_doc("Purchase Receipt", pr)
update_billing_percentage(pr_doc, update_modified=update_modified)
+ self.load_from_db()
-def update_billed_amount_based_on_po(po_details, update_modified=True, pr_doc=None):
+
+def get_stock_value_difference(voucher_no, voucher_detail_no, warehouse):
+ return frappe.db.get_value(
+ "Stock Ledger Entry",
+ {
+ "voucher_type": "Purchase Receipt",
+ "voucher_no": voucher_no,
+ "voucher_detail_no": voucher_detail_no,
+ "warehouse": warehouse,
+ "is_cancelled": 0,
+ },
+ "stock_value_difference",
+ )
+
+
+def update_billed_amount_based_on_po(po_details, update_modified=True):
po_billed_amt_details = get_billed_amount_against_po(po_details)
# Get all Purchase Receipt Item rows against the Purchase Order Items
@@ -858,19 +792,13 @@
po_billed_amt_details[pr_item.purchase_order_item] = billed_against_po
if pr_item.billed_amt != billed_amt_agianst_pr:
- # update existing doc if possible
- if pr_doc and pr_item.parent == pr_doc.name:
- pr_item = next((item for item in pr_doc.items if item.name == pr_item.name), None)
- pr_item.db_set("billed_amt", billed_amt_agianst_pr, update_modified=update_modified)
-
- else:
- frappe.db.set_value(
- "Purchase Receipt Item",
- pr_item.name,
- "billed_amt",
- billed_amt_agianst_pr,
- update_modified=update_modified,
- )
+ frappe.db.set_value(
+ "Purchase Receipt Item",
+ pr_item.name,
+ "billed_amt",
+ billed_amt_agianst_pr,
+ update_modified=update_modified,
+ )
updated_pr.append(pr_item.parent)
@@ -1256,8 +1184,3 @@
def on_doctype_update():
frappe.db.add_index("Purchase Receipt", ["supplier", "is_return", "return_against"])
-
-
-@erpnext.allow_regional
-def update_regional_gl_entries(gl_list, doc):
- return
diff --git a/erpnext/templates/pages/integrations/__init__.py b/erpnext/templates/pages/integrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/templates/pages/integrations/__init__.py