mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-03 04:09:11 +00:00
Merge pull request #49834 from rohitwaghchaure/feat-track-purchases
feat: track purchases in accounting and configure item / item group / brand wise COGS
This commit is contained in:
@@ -884,6 +884,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
self.make_write_off_gl_entry(gl_entries)
|
self.make_write_off_gl_entry(gl_entries)
|
||||||
self.make_gle_for_rounding_adjustment(gl_entries)
|
self.make_gle_for_rounding_adjustment(gl_entries)
|
||||||
self.set_transaction_currency_and_rate_in_gl_map(gl_entries)
|
self.set_transaction_currency_and_rate_in_gl_map(gl_entries)
|
||||||
|
self.set_gl_entry_for_purchase_expense(gl_entries)
|
||||||
return gl_entries
|
return gl_entries
|
||||||
|
|
||||||
def check_asset_cwip_enabled(self):
|
def check_asset_cwip_enabled(self):
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from erpnext.accounts.party import get_party_details
|
|||||||
from erpnext.buying.utils import update_last_purchase_rate, validate_for_items
|
from erpnext.buying.utils import update_last_purchase_rate, validate_for_items
|
||||||
from erpnext.controllers.sales_and_purchase_return import get_rate_for_return
|
from erpnext.controllers.sales_and_purchase_return import get_rate_for_return
|
||||||
from erpnext.controllers.subcontracting_controller import SubcontractingController
|
from erpnext.controllers.subcontracting_controller import SubcontractingController
|
||||||
from erpnext.stock.get_item_details import get_conversion_factor
|
from erpnext.stock.get_item_details import get_conversion_factor, get_item_defaults
|
||||||
from erpnext.stock.utils import get_incoming_rate
|
from erpnext.stock.utils import get_incoming_rate
|
||||||
|
|
||||||
|
|
||||||
@@ -307,6 +307,60 @@ class BuyingController(SubcontractingController):
|
|||||||
address_display_field, render_address(self.get(address_field), check_permissions=False)
|
address_display_field, render_address(self.get(address_field), check_permissions=False)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def set_gl_entry_for_purchase_expense(self, gl_entries):
|
||||||
|
if self.doctype == "Purchase Invoice" and not self.update_stock:
|
||||||
|
return
|
||||||
|
|
||||||
|
for row in self.items:
|
||||||
|
details = get_purchase_expense_account(row.item_code, self.company)
|
||||||
|
|
||||||
|
if not details.purchase_expense_account:
|
||||||
|
details.purchase_expense_account = frappe.get_cached_value(
|
||||||
|
"Company", self.company, "purchase_expense_account"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not details.purchase_expense_account:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not details.purchase_expense_contra_account:
|
||||||
|
details.purchase_expense_contra_account = frappe.get_cached_value(
|
||||||
|
"Company", self.company, "purchase_expense_contra_account"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not details.purchase_expense_contra_account:
|
||||||
|
frappe.throw(
|
||||||
|
_("Please set Purchase Expense Contra Account in Company {0}").format(self.company)
|
||||||
|
)
|
||||||
|
|
||||||
|
amount = flt(row.valuation_rate * row.stock_qty, row.precision("base_amount"))
|
||||||
|
self.add_gl_entry(
|
||||||
|
gl_entries=gl_entries,
|
||||||
|
account=details.purchase_expense_account,
|
||||||
|
cost_center=row.cost_center,
|
||||||
|
debit=amount,
|
||||||
|
credit=0.0,
|
||||||
|
remarks=_("Purchase Expense for Item {0}").format(row.item_code),
|
||||||
|
against_account=details.purchase_expense_contra_account,
|
||||||
|
account_currency=frappe.get_cached_value(
|
||||||
|
"Account", details.purchase_expense_account, "account_currency"
|
||||||
|
),
|
||||||
|
item=row,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.add_gl_entry(
|
||||||
|
gl_entries=gl_entries,
|
||||||
|
account=details.purchase_expense_contra_account,
|
||||||
|
cost_center=row.cost_center,
|
||||||
|
debit=0.0,
|
||||||
|
credit=amount,
|
||||||
|
remarks=_("Purchase Expense for Item {0}").format(row.item_code),
|
||||||
|
against_account=details.purchase_expense_account,
|
||||||
|
account_currency=frappe.get_cached_value(
|
||||||
|
"Account", details.purchase_expense_contra_account, "account_currency"
|
||||||
|
),
|
||||||
|
item=row,
|
||||||
|
)
|
||||||
|
|
||||||
def set_total_in_words(self):
|
def set_total_in_words(self):
|
||||||
from frappe.utils import money_in_words
|
from frappe.utils import money_in_words
|
||||||
|
|
||||||
@@ -1171,3 +1225,33 @@ def validate_item_type(doc, fieldname, message):
|
|||||||
@erpnext.allow_regional
|
@erpnext.allow_regional
|
||||||
def update_regional_item_valuation_rate(doc):
|
def update_regional_item_valuation_rate(doc):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.request_cache
|
||||||
|
def get_purchase_expense_account(item_code, company):
|
||||||
|
defaults = get_item_defaults(item_code, company)
|
||||||
|
|
||||||
|
details = frappe._dict(
|
||||||
|
{
|
||||||
|
"purchase_expense_account": defaults.get("purchase_expense_account"),
|
||||||
|
"purchase_expense_contra_account": defaults.get("purchase_expense_contra_account"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not details.purchase_expense_account:
|
||||||
|
details = frappe.db.get_value(
|
||||||
|
"Item Default",
|
||||||
|
{"parent": defaults.item_group, "company": company},
|
||||||
|
["purchase_expense_account", "purchase_expense_contra_account"],
|
||||||
|
as_dict=1,
|
||||||
|
) or frappe._dict({})
|
||||||
|
|
||||||
|
if not details.purchase_expense_account:
|
||||||
|
details = frappe.db.get_value(
|
||||||
|
"Item Default",
|
||||||
|
{"parent": defaults.brand, "company": company},
|
||||||
|
["purchase_expense_account", "purchase_expense_contra_account"],
|
||||||
|
as_dict=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
return details or frappe._dict({})
|
||||||
|
|||||||
@@ -278,6 +278,8 @@ erpnext.company.setup_queries = function (frm) {
|
|||||||
["depreciation_expense_account", { root_type: "Expense", account_type: "Depreciation" }],
|
["depreciation_expense_account", { root_type: "Expense", account_type: "Depreciation" }],
|
||||||
["disposal_account", { report_type: "Profit and Loss" }],
|
["disposal_account", { report_type: "Profit and Loss" }],
|
||||||
["default_inventory_account", { account_type: "Stock" }],
|
["default_inventory_account", { account_type: "Stock" }],
|
||||||
|
["purchase_expense_account", { root_type: "Expense" }],
|
||||||
|
["purchase_expense_contra_account", { root_type: "Expense" }],
|
||||||
["cost_center", {}],
|
["cost_center", {}],
|
||||||
["round_off_cost_center", {}],
|
["round_off_cost_center", {}],
|
||||||
["depreciation_cost_center", {}],
|
["depreciation_cost_center", {}],
|
||||||
|
|||||||
@@ -106,6 +106,10 @@
|
|||||||
"default_warehouse_for_sales_return",
|
"default_warehouse_for_sales_return",
|
||||||
"credit_limit",
|
"credit_limit",
|
||||||
"transactions_annual_history",
|
"transactions_annual_history",
|
||||||
|
"purchase_expense_section",
|
||||||
|
"purchase_expense_account",
|
||||||
|
"column_break_ereg",
|
||||||
|
"purchase_expense_contra_account",
|
||||||
"stock_tab",
|
"stock_tab",
|
||||||
"auto_accounting_for_stock_settings",
|
"auto_accounting_for_stock_settings",
|
||||||
"enable_perpetual_inventory",
|
"enable_perpetual_inventory",
|
||||||
@@ -844,6 +848,27 @@
|
|||||||
"options": "Currency",
|
"options": "Currency",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "purchase_expense_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Purchase Expense"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_ereg",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "purchase_expense_account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Purchase Expense Account",
|
||||||
|
"options": "Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "purchase_expense_contra_account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Purchase Expense Contra Account",
|
||||||
|
"options": "Account"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-building",
|
"icon": "fa fa-building",
|
||||||
@@ -851,7 +876,7 @@
|
|||||||
"image_field": "company_logo",
|
"image_field": "company_logo",
|
||||||
"is_tree": 1,
|
"is_tree": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-08-25 18:34:03.602046",
|
"modified": "2025-10-01 17:34:10.971627",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
"name": "Company",
|
"name": "Company",
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ class Company(NestedSet):
|
|||||||
parent_company: DF.Link | None
|
parent_company: DF.Link | None
|
||||||
payment_terms: DF.Link | None
|
payment_terms: DF.Link | None
|
||||||
phone_no: DF.Data | None
|
phone_no: DF.Data | None
|
||||||
|
purchase_expense_account: DF.Link | None
|
||||||
|
purchase_expense_contra_account: DF.Link | None
|
||||||
reconcile_on_advance_payment_date: DF.Check
|
reconcile_on_advance_payment_date: DF.Check
|
||||||
reconciliation_takes_effect_on: DF.Literal[
|
reconciliation_takes_effect_on: DF.Literal[
|
||||||
"Advance Payment Date", "Oldest Of Invoice Or Advance", "Reconciliation Date"
|
"Advance Payment Date", "Oldest Of Invoice Or Advance", "Reconciliation Date"
|
||||||
|
|||||||
@@ -488,6 +488,21 @@ $.extend(erpnext.item, {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let fields = ["purchase_expense_account", "purchase_expense_contra_account", "default_cogs_account"];
|
||||||
|
|
||||||
|
fields.forEach((field) => {
|
||||||
|
frm.set_query(field, "item_defaults", (doc, cdt, cdn) => {
|
||||||
|
let row = locals[cdt][cdn];
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
company: row.company,
|
||||||
|
root_type: "Expense",
|
||||||
|
is_group: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
make_dashboard: function (frm) {
|
make_dashboard: function (frm) {
|
||||||
|
|||||||
@@ -16,20 +16,22 @@
|
|||||||
"item_name",
|
"item_name",
|
||||||
"item_group",
|
"item_group",
|
||||||
"stock_uom",
|
"stock_uom",
|
||||||
|
"opening_stock",
|
||||||
|
"valuation_rate",
|
||||||
|
"standard_rate",
|
||||||
"column_break0",
|
"column_break0",
|
||||||
"disabled",
|
"disabled",
|
||||||
"allow_alternative_item",
|
"allow_alternative_item",
|
||||||
"is_stock_item",
|
"is_stock_item",
|
||||||
"has_variants",
|
"has_variants",
|
||||||
"opening_stock",
|
|
||||||
"valuation_rate",
|
|
||||||
"standard_rate",
|
|
||||||
"is_fixed_asset",
|
"is_fixed_asset",
|
||||||
"auto_create_assets",
|
"auto_create_assets",
|
||||||
"is_grouped_asset",
|
"is_grouped_asset",
|
||||||
"asset_category",
|
"asset_category",
|
||||||
"asset_naming_series",
|
"asset_naming_series",
|
||||||
|
"section_break_znra",
|
||||||
"over_delivery_receipt_allowance",
|
"over_delivery_receipt_allowance",
|
||||||
|
"column_break_wugd",
|
||||||
"over_billing_allowance",
|
"over_billing_allowance",
|
||||||
"image",
|
"image",
|
||||||
"section_break_11",
|
"section_break_11",
|
||||||
@@ -63,6 +65,8 @@
|
|||||||
"column_break_37",
|
"column_break_37",
|
||||||
"has_serial_no",
|
"has_serial_no",
|
||||||
"serial_no_series",
|
"serial_no_series",
|
||||||
|
"defaults_tab",
|
||||||
|
"item_defaults",
|
||||||
"variants_section",
|
"variants_section",
|
||||||
"variant_of",
|
"variant_of",
|
||||||
"variant_based_on",
|
"variant_based_on",
|
||||||
@@ -74,8 +78,6 @@
|
|||||||
"column_break_9s9o",
|
"column_break_9s9o",
|
||||||
"enable_deferred_revenue",
|
"enable_deferred_revenue",
|
||||||
"no_of_months",
|
"no_of_months",
|
||||||
"section_break_avcp",
|
|
||||||
"item_defaults",
|
|
||||||
"purchasing_tab",
|
"purchasing_tab",
|
||||||
"purchase_uom",
|
"purchase_uom",
|
||||||
"min_order_qty",
|
"min_order_qty",
|
||||||
@@ -887,10 +889,6 @@
|
|||||||
"fieldname": "column_break_9s9o",
|
"fieldname": "column_break_9s9o",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "section_break_avcp",
|
|
||||||
"fieldtype": "Section Break"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "deferred_accounting_section",
|
"fieldname": "deferred_accounting_section",
|
||||||
@@ -936,6 +934,19 @@
|
|||||||
"fieldname": "production_capacity",
|
"fieldname": "production_capacity",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"label": "Production Capacity"
|
"label": "Production Capacity"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "defaults_tab",
|
||||||
|
"fieldtype": "Tab Break",
|
||||||
|
"label": "Defaults"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_znra",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_wugd",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-tag",
|
"icon": "fa fa-tag",
|
||||||
@@ -943,7 +954,7 @@
|
|||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"links": [],
|
"links": [],
|
||||||
"make_attachments_public": 1,
|
"make_attachments_public": 1,
|
||||||
"modified": "2025-08-14 23:35:56.293048",
|
"modified": "2025-10-01 16:58:40.946604",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Item",
|
"name": "Item",
|
||||||
|
|||||||
@@ -305,6 +305,7 @@ class TestItem(IntegrationTestCase):
|
|||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"default_warehouse": "_Test Warehouse 2 - _TC", # no override
|
"default_warehouse": "_Test Warehouse 2 - _TC", # no override
|
||||||
"expense_account": "_Test Account Stock Expenses - _TC", # override brand default
|
"expense_account": "_Test Account Stock Expenses - _TC", # override brand default
|
||||||
|
"default_cogs_account": "_Test Account Cost for Goods Sold - _TC", # override brand default
|
||||||
"buying_cost_center": "_Test Write Off Cost Center - _TC", # override item group default
|
"buying_cost_center": "_Test Write Off Cost Center - _TC", # override item group default
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -315,7 +316,7 @@ class TestItem(IntegrationTestCase):
|
|||||||
"item_code": "Test Item With Defaults",
|
"item_code": "Test Item With Defaults",
|
||||||
"warehouse": "_Test Warehouse 2 - _TC", # from item
|
"warehouse": "_Test Warehouse 2 - _TC", # from item
|
||||||
"income_account": "_Test Account Sales - _TC", # from brand
|
"income_account": "_Test Account Sales - _TC", # from brand
|
||||||
"expense_account": "_Test Account Stock Expenses - _TC", # from item
|
"expense_account": "_Test Account Cost for Goods Sold - _TC", # from item
|
||||||
"cost_center": "_Test Cost Center 2 - _TC", # from item group
|
"cost_center": "_Test Cost Center 2 - _TC", # from item group
|
||||||
}
|
}
|
||||||
sales_item_details = get_item_details(
|
sales_item_details = get_item_details(
|
||||||
|
|||||||
@@ -16,10 +16,15 @@
|
|||||||
"column_break_8",
|
"column_break_8",
|
||||||
"expense_account",
|
"expense_account",
|
||||||
"default_provisional_account",
|
"default_provisional_account",
|
||||||
|
"column_break_cpif",
|
||||||
|
"purchase_expense_account",
|
||||||
|
"purchase_expense_contra_account",
|
||||||
"selling_defaults",
|
"selling_defaults",
|
||||||
"selling_cost_center",
|
"selling_cost_center",
|
||||||
"column_break_12",
|
"column_break_12",
|
||||||
"income_account",
|
"income_account",
|
||||||
|
"cost_of_good_sold_section",
|
||||||
|
"default_cogs_account",
|
||||||
"deferred_accounting_defaults_section",
|
"deferred_accounting_defaults_section",
|
||||||
"deferred_expense_account",
|
"deferred_expense_account",
|
||||||
"column_break_kwad",
|
"column_break_kwad",
|
||||||
@@ -111,7 +116,7 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "default_provisional_account",
|
"fieldname": "default_provisional_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Default Provisional Account",
|
"label": "Default Provisional Account (Service)",
|
||||||
"options": "Account"
|
"options": "Account"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -136,19 +141,47 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "column_break_kwad",
|
"fieldname": "column_break_kwad",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_cpif",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "cost_of_good_sold_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Cost of Goods Sold"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "default_cogs_account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Default COGS Account",
|
||||||
|
"options": "Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "purchase_expense_account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Purchase Expense Account",
|
||||||
|
"options": "Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "purchase_expense_contra_account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Purchase Expense Contra Account",
|
||||||
|
"options": "Account"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-03-17 13:46:09.719105",
|
"modified": "2025-10-01 19:17:33.687836",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Item Default",
|
"name": "Item Default",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
|
"row_format": "Dynamic",
|
||||||
"sort_field": "creation",
|
"sort_field": "creation",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"states": [],
|
"states": [],
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class ItemDefault(Document):
|
|||||||
|
|
||||||
buying_cost_center: DF.Link | None
|
buying_cost_center: DF.Link | None
|
||||||
company: DF.Link
|
company: DF.Link
|
||||||
|
default_cogs_account: DF.Link | None
|
||||||
default_discount_account: DF.Link | None
|
default_discount_account: DF.Link | None
|
||||||
default_price_list: DF.Link | None
|
default_price_list: DF.Link | None
|
||||||
default_provisional_account: DF.Link | None
|
default_provisional_account: DF.Link | None
|
||||||
@@ -28,6 +29,8 @@ class ItemDefault(Document):
|
|||||||
parent: DF.Data
|
parent: DF.Data
|
||||||
parentfield: DF.Data
|
parentfield: DF.Data
|
||||||
parenttype: DF.Data
|
parenttype: DF.Data
|
||||||
|
purchase_expense_account: DF.Link | None
|
||||||
|
purchase_expense_contra_account: DF.Link | None
|
||||||
selling_cost_center: DF.Link | None
|
selling_cost_center: DF.Link | None
|
||||||
# end: auto-generated types
|
# end: auto-generated types
|
||||||
|
|
||||||
|
|||||||
@@ -479,6 +479,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
|
|
||||||
self.make_item_gl_entries(gl_entries, warehouse_account=warehouse_account)
|
self.make_item_gl_entries(gl_entries, warehouse_account=warehouse_account)
|
||||||
self.make_tax_gl_entries(gl_entries, via_landed_cost_voucher)
|
self.make_tax_gl_entries(gl_entries, via_landed_cost_voucher)
|
||||||
|
self.set_gl_entry_for_purchase_expense(gl_entries)
|
||||||
update_regional_gl_entries(gl_entries, self)
|
update_regional_gl_entries(gl_entries, self)
|
||||||
|
|
||||||
return process_gl_map(gl_entries, from_repost=frappe.flags.through_repost_item_valuation)
|
return process_gl_map(gl_entries, from_repost=frappe.flags.through_repost_item_valuation)
|
||||||
|
|||||||
@@ -4415,6 +4415,69 @@ class TestPurchaseReceipt(IntegrationTestCase):
|
|||||||
|
|
||||||
self.assertEqual(srbnb_cost, 1000)
|
self.assertEqual(srbnb_cost, 1000)
|
||||||
|
|
||||||
|
def test_purchase_expense_account(self):
|
||||||
|
item = "Test Item with Purchase Expense Account"
|
||||||
|
make_item(item, {"is_stock_item": 1})
|
||||||
|
company = "_Test Company with perpetual inventory"
|
||||||
|
|
||||||
|
expense_account = "_Test Account Purchase Expense - TCP1"
|
||||||
|
expense_contra_account = "_Test Account Purchase Contra Expense - TCP1"
|
||||||
|
if not frappe.db.exists("Account", expense_account):
|
||||||
|
frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Account",
|
||||||
|
"account_name": "_Test Account Purchase Expense",
|
||||||
|
"parent_account": "Stock Expenses - TCP1",
|
||||||
|
"company": company,
|
||||||
|
"is_group": 0,
|
||||||
|
"root_type": "Expense",
|
||||||
|
}
|
||||||
|
).insert()
|
||||||
|
|
||||||
|
if not frappe.db.exists("Account", expense_contra_account):
|
||||||
|
frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Account",
|
||||||
|
"account_name": "_Test Account Purchase Contra Expense",
|
||||||
|
"parent_account": "Stock Expenses - TCP1",
|
||||||
|
"company": company,
|
||||||
|
"is_group": 0,
|
||||||
|
"root_type": "Expense",
|
||||||
|
}
|
||||||
|
).insert()
|
||||||
|
|
||||||
|
item_doc = frappe.get_doc("Item", item)
|
||||||
|
item_doc.append(
|
||||||
|
"item_defaults",
|
||||||
|
{
|
||||||
|
"company": company,
|
||||||
|
"default_warehouse": "Stores - TCP1",
|
||||||
|
"purchase_expense_account": expense_account,
|
||||||
|
"purchase_expense_contra_account": expense_contra_account,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
item_doc.save()
|
||||||
|
|
||||||
|
pr = make_purchase_receipt(
|
||||||
|
item_code=item,
|
||||||
|
qty=10,
|
||||||
|
rate=100,
|
||||||
|
company=company,
|
||||||
|
warehouse="Stores - TCP1",
|
||||||
|
)
|
||||||
|
|
||||||
|
gl_entries = get_gl_entries(pr.doctype, pr.name)
|
||||||
|
accounts = [d.account for d in gl_entries]
|
||||||
|
self.assertTrue(expense_account in accounts)
|
||||||
|
self.assertTrue(expense_contra_account in accounts)
|
||||||
|
|
||||||
|
for row in gl_entries:
|
||||||
|
if row.account == expense_account:
|
||||||
|
self.assertEqual(row.debit, 1000)
|
||||||
|
if row.account == expense_contra_account:
|
||||||
|
self.assertEqual(row.credit, 1000)
|
||||||
|
|
||||||
|
|
||||||
def prepare_data_for_internal_transfer():
|
def prepare_data_for_internal_transfer():
|
||||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
|
||||||
|
|||||||
@@ -868,6 +868,19 @@ def get_default_income_account(ctx: ItemDetailsCtx, item, item_group, brand):
|
|||||||
|
|
||||||
|
|
||||||
def get_default_expense_account(ctx: ItemDetailsCtx, item, item_group, brand):
|
def get_default_expense_account(ctx: ItemDetailsCtx, item, item_group, brand):
|
||||||
|
if ctx.get("doctype") in ["Sales Invoice", "Delivery Note"]:
|
||||||
|
expense_account = (
|
||||||
|
item.get("default_cogs_account")
|
||||||
|
or item_group.get("default_cogs_account")
|
||||||
|
or brand.get("default_cogs_account")
|
||||||
|
)
|
||||||
|
|
||||||
|
if not expense_account:
|
||||||
|
expense_account = frappe.get_cached_value("Company", ctx.company, "default_expense_account")
|
||||||
|
|
||||||
|
if expense_account:
|
||||||
|
return expense_account
|
||||||
|
|
||||||
return (
|
return (
|
||||||
item.get("expense_account")
|
item.get("expense_account")
|
||||||
or item_group.get("expense_account")
|
or item_group.get("expense_account")
|
||||||
|
|||||||
Reference in New Issue
Block a user