Merge pull request #30675 from deepeshgarg007/item_wise_provisional_accounting

feat: Item-wise provisional accounting for service items
This commit is contained in:
Deepesh Garg 2022-04-14 12:30:50 +05:30 committed by GitHub
commit 7536da0b41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 72 additions and 33 deletions

View File

@ -811,7 +811,9 @@ class PurchaseInvoice(BuyingController):
if provisional_accounting_for_non_stock_items: if provisional_accounting_for_non_stock_items:
if item.purchase_receipt: if item.purchase_receipt:
provisional_account = self.get_company_default("default_provisional_account") provisional_account = frappe.db.get_value(
"Purchase Receipt Item", item.pr_detail, "provisional_expense_account"
) or self.get_company_default("default_provisional_account")
purchase_receipt_doc = purchase_receipt_doc_map.get(item.purchase_receipt) purchase_receipt_doc = purchase_receipt_doc_map.get(item.purchase_receipt)
if not purchase_receipt_doc: if not purchase_receipt_doc:
@ -834,7 +836,7 @@ class PurchaseInvoice(BuyingController):
if expense_booked_in_pr: if expense_booked_in_pr:
# Intentionally passing purchase invoice item to handle partial billing # Intentionally passing purchase invoice item to handle partial billing
purchase_receipt_doc.add_provisional_gl_entry( purchase_receipt_doc.add_provisional_gl_entry(
item, gl_entries, self.posting_date, reverse=1 item, gl_entries, self.posting_date, provisional_account, reverse=1
) )
if not self.is_internal_transfer(): if not self.is_internal_transfer():

View File

@ -1482,7 +1482,8 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEqual(payment_entry.taxes[0].allocated_amount, 0) self.assertEqual(payment_entry.taxes[0].allocated_amount, 0)
def test_provisional_accounting_entry(self): def test_provisional_accounting_entry(self):
item = create_item("_Test Non Stock Item", is_stock_item=0) create_item("_Test Non Stock Item", is_stock_item=0)
provisional_account = create_account( provisional_account = create_account(
account_name="Provision Account", account_name="Provision Account",
parent_account="Current Liabilities - _TC", parent_account="Current Liabilities - _TC",
@ -1505,6 +1506,8 @@ class TestPurchaseInvoice(unittest.TestCase):
pi.save() pi.save()
pi.submit() pi.submit()
self.assertEquals(pr.items[0].provisional_expense_account, "Provision Account - _TC")
# Check GLE for Purchase Invoice # Check GLE for Purchase Invoice
expected_gle = [ expected_gle = [
["Cost of Goods Sold - _TC", 250, 0, add_days(pr.posting_date, -1)], ["Cost of Goods Sold - _TC", 250, 0, add_days(pr.posting_date, -1)],

View File

@ -233,7 +233,8 @@ erpnext.company.setup_queries = function(frm) {
["expenses_included_in_asset_valuation", {"account_type": "Expenses Included In Asset Valuation"}], ["expenses_included_in_asset_valuation", {"account_type": "Expenses Included In Asset Valuation"}],
["capital_work_in_progress_account", {"account_type": "Capital Work in Progress"}], ["capital_work_in_progress_account", {"account_type": "Capital Work in Progress"}],
["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}], ["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}],
["unrealized_profit_loss_account", {"root_type": ["in", ["Liability", "Asset"]]}] ["unrealized_profit_loss_account", {"root_type": ["in", ["Liability", "Asset"]]}],
["default_provisional_account", {"root_type": ["in", ["Liability", "Asset"]]}]
], function(i, v) { ], function(i, v) {
erpnext.company.set_custom_query(frm, v); erpnext.company.set_custom_query(frm, v);
}); });

View File

@ -377,6 +377,17 @@ $.extend(erpnext.item, {
} }
} }
frm.set_query('default_provisional_account', 'item_defaults', (doc, cdt, cdn) => {
let row = locals[cdt][cdn];
return {
filters: {
"company": row.company,
"root_type": ["in", ["Liability", "Asset"]],
"is_group": 0
}
};
});
}, },
make_dashboard: function(frm) { make_dashboard: function(frm) {

View File

@ -15,6 +15,7 @@
"default_supplier", "default_supplier",
"column_break_8", "column_break_8",
"expense_account", "expense_account",
"default_provisional_account",
"selling_defaults", "selling_defaults",
"selling_cost_center", "selling_cost_center",
"column_break_12", "column_break_12",
@ -101,11 +102,17 @@
"fieldtype": "Link", "fieldtype": "Link",
"label": "Default Discount Account", "label": "Default Discount Account",
"options": "Account" "options": "Account"
},
{
"fieldname": "default_provisional_account",
"fieldtype": "Link",
"label": "Default Provisional Account",
"options": "Account"
} }
], ],
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2021-07-13 01:26:03.860065", "modified": "2022-04-10 20:18:54.148195",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Item Default", "name": "Item Default",
@ -114,5 +121,6 @@
"quick_entry": 1, "quick_entry": 1,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"states": [],
"track_changes": 1 "track_changes": 1
} }

View File

@ -106,8 +106,6 @@
"terms", "terms",
"bill_no", "bill_no",
"bill_date", "bill_date",
"accounting_details_section",
"provisional_expense_account",
"more_info", "more_info",
"project", "project",
"status", "status",
@ -1145,26 +1143,13 @@
"label": "Represents Company", "label": "Represents Company",
"options": "Company", "options": "Company",
"read_only": 1 "read_only": 1
},
{
"collapsible": 1,
"fieldname": "accounting_details_section",
"fieldtype": "Section Break",
"label": "Accounting Details"
},
{
"fieldname": "provisional_expense_account",
"fieldtype": "Link",
"hidden": 1,
"label": "Provisional Expense Account",
"options": "Account"
} }
], ],
"icon": "fa fa-truck", "icon": "fa fa-truck",
"idx": 261, "idx": 261,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2022-03-10 11:40:52.690984", "modified": "2022-04-10 22:50:37.761362",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Purchase Receipt", "name": "Purchase Receipt",

View File

@ -145,10 +145,13 @@ class PurchaseReceipt(BuyingController):
) )
) )
if provisional_accounting_for_non_stock_items: if not provisional_accounting_for_non_stock_items:
return
default_provisional_account = self.get_company_default("default_provisional_account") default_provisional_account = self.get_company_default("default_provisional_account")
if not self.provisional_expense_account: for item in self.get("items"):
self.provisional_expense_account = default_provisional_account if not item.get("provisional_expense_account"):
item.provisional_expense_account = default_provisional_account
def validate_with_previous_doc(self): def validate_with_previous_doc(self):
super(PurchaseReceipt, self).validate_with_previous_doc( super(PurchaseReceipt, self).validate_with_previous_doc(
@ -509,7 +512,9 @@ class PurchaseReceipt(BuyingController):
and flt(d.qty) and flt(d.qty)
and provisional_accounting_for_non_stock_items and provisional_accounting_for_non_stock_items
): ):
self.add_provisional_gl_entry(d, gl_entries, self.posting_date) self.add_provisional_gl_entry(
d, gl_entries, self.posting_date, d.get("provisional_expense_account")
)
if warehouse_with_no_account: if warehouse_with_no_account:
frappe.msgprint( frappe.msgprint(
@ -518,9 +523,10 @@ class PurchaseReceipt(BuyingController):
+ "\n".join(warehouse_with_no_account) + "\n".join(warehouse_with_no_account)
) )
def add_provisional_gl_entry(self, item, gl_entries, posting_date, reverse=0): def add_provisional_gl_entry(
provisional_expense_account = self.get("provisional_expense_account") self, item, gl_entries, posting_date, provisional_account, reverse=0
credit_currency = get_account_currency(provisional_expense_account) ):
credit_currency = get_account_currency(provisional_account)
debit_currency = get_account_currency(item.expense_account) debit_currency = get_account_currency(item.expense_account)
expense_account = item.expense_account expense_account = item.expense_account
remarks = self.get("remarks") or _("Accounting Entry for Service") remarks = self.get("remarks") or _("Accounting Entry for Service")
@ -534,7 +540,7 @@ class PurchaseReceipt(BuyingController):
self.add_gl_entry( self.add_gl_entry(
gl_entries=gl_entries, gl_entries=gl_entries,
account=provisional_expense_account, account=provisional_account,
cost_center=item.cost_center, cost_center=item.cost_center,
debit=0.0, debit=0.0,
credit=multiplication_factor * item.amount, credit=multiplication_factor * item.amount,
@ -554,7 +560,7 @@ class PurchaseReceipt(BuyingController):
debit=multiplication_factor * item.amount, debit=multiplication_factor * item.amount,
credit=0.0, credit=0.0,
remarks=remarks, remarks=remarks,
against_account=provisional_expense_account, against_account=provisional_account,
account_currency=debit_currency, account_currency=debit_currency,
project=item.project, project=item.project,
voucher_detail_no=item.name, voucher_detail_no=item.name,

View File

@ -96,7 +96,6 @@
"include_exploded_items", "include_exploded_items",
"batch_no", "batch_no",
"rejected_serial_no", "rejected_serial_no",
"expense_account",
"item_tax_rate", "item_tax_rate",
"item_weight_details", "item_weight_details",
"weight_per_unit", "weight_per_unit",
@ -107,6 +106,10 @@
"manufacturer", "manufacturer",
"column_break_16", "column_break_16",
"manufacturer_part_no", "manufacturer_part_no",
"accounting_details_section",
"expense_account",
"column_break_102",
"provisional_expense_account",
"accounting_dimensions_section", "accounting_dimensions_section",
"project", "project",
"dimension_col_break", "dimension_col_break",
@ -971,12 +974,27 @@
"label": "Product Bundle", "label": "Product Bundle",
"options": "Product Bundle", "options": "Product Bundle",
"read_only": 1 "read_only": 1
},
{
"fieldname": "provisional_expense_account",
"fieldtype": "Link",
"label": "Provisional Expense Account",
"options": "Account"
},
{
"fieldname": "accounting_details_section",
"fieldtype": "Section Break",
"label": "Accounting Details"
},
{
"fieldname": "column_break_102",
"fieldtype": "Column Break"
} }
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2022-02-01 11:32:27.980524", "modified": "2022-04-11 13:07:32.061402",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Purchase Receipt Item", "name": "Purchase Receipt Item",

View File

@ -345,6 +345,7 @@ def get_basic_details(args, item, overwrite_warehouse=True):
"expense_account": expense_account "expense_account": expense_account
or get_default_expense_account(args, item_defaults, item_group_defaults, brand_defaults), or get_default_expense_account(args, item_defaults, item_group_defaults, brand_defaults),
"discount_account": get_default_discount_account(args, item_defaults), "discount_account": get_default_discount_account(args, item_defaults),
"provisional_expense_account": get_provisional_account(args, item_defaults),
"cost_center": get_default_cost_center( "cost_center": get_default_cost_center(
args, item_defaults, item_group_defaults, brand_defaults args, item_defaults, item_group_defaults, brand_defaults
), ),
@ -699,6 +700,10 @@ def get_default_expense_account(args, item, item_group, brand):
) )
def get_provisional_account(args, item):
return item.get("default_provisional_account") or args.default_provisional_account
def get_default_discount_account(args, item): def get_default_discount_account(args, item):
return item.get("default_discount_account") or args.discount_account return item.get("default_discount_account") or args.discount_account