Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Enable discount accounting #26579

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
e1dc698
feat(Accounts Settings): Add 'Enable Discount Accounting' checkbox
GangaManoj Jul 5, 2021
a6690a8
feat(Sales Invoice): Add 'Discount Account' field in Items table
GangaManoj Jul 5, 2021
f6a9374
feat: Create GL Entries for discount accounting
GangaManoj Jul 5, 2021
c4e5429
feat: Filter list for Discount Account field in Items table
GangaManoj Jul 6, 2021
acb9e20
feat: Add Default Discount Account field
GangaManoj Jul 6, 2021
cdfefa2
feat: Assign Item's Default Discount Account if present
GangaManoj Jul 6, 2021
f48fa2e
feat: Toggle display for discount accounting fields according to enab…
GangaManoj Jul 6, 2021
d24b5f7
fix: Add description for Enable Discount Accounting checkbox
GangaManoj Jul 12, 2021
cfb9417
fix: Filter Discount Account list
GangaManoj Jul 12, 2021
613d08f
fix: Copy discount account from first row to all Items
GangaManoj Jul 12, 2021
546c8d1
fix: Move Default Discount Account field to Item Defaults
GangaManoj Jul 12, 2021
ee025b5
fix: Filter options for Default Discount Account
GangaManoj Jul 12, 2021
bde5c61
fix: Add Discount Account field
GangaManoj Jul 12, 2021
e2c83c3
fix: Display Discount Account only if Enable Discount Accounting is c…
GangaManoj Jul 12, 2021
377775a
fix: Copy Discount Account from first row
GangaManoj Jul 12, 2021
e06eb8e
fix: Filter options for Discount Account
GangaManoj Jul 12, 2021
fd2852e
fix: Create common function for discount accounting
GangaManoj Jul 12, 2021
38e87fc
fix: Add tests for discount accounting
GangaManoj Jul 13, 2021
9e788cf
fix: Add Additional Discount Account field
GangaManoj Jul 15, 2021
c1d65cf
fix: Filter options for Additional Discount Account
GangaManoj Jul 15, 2021
b64787e
fix: Only display Additional Discount Account if Enable Discount Acco…
GangaManoj Jul 15, 2021
38327fc
fix: Make additional GL Entries for discount applied on taxes
GangaManoj Jul 15, 2021
d6f409a
fix: Sider issues
GangaManoj Jul 15, 2021
d0d9e83
fix: Check all expected GL Entries
GangaManoj Jul 17, 2021
03f2706
fix: Add Additional Discount Account field
GangaManoj Jul 17, 2021
ff25683
fix: Filter options for Additional Discount Account
GangaManoj Jul 17, 2021
9dd2a9e
fix: Create ledger entries for discount applied on taxes in make_tax_…
GangaManoj Jul 17, 2021
4da7c58
fix: Only display Additional Discount Account if Enable Discount Acco…
GangaManoj Jul 17, 2021
d62af77
fix: Remove unnecessary condition
GangaManoj Jul 17, 2021
9965287
fix: Add test for additional discount applied on taxes
GangaManoj Jul 17, 2021
99cb89f
fix: Switch debit and credit for ledger entries for discount applied …
GangaManoj Jul 17, 2021
251f229
fix: Add test for additional discount applied on taxes
GangaManoj Jul 17, 2021
b4a8bc8
fix: Use the item's cost centre instead of the Invoice's
GangaManoj Jul 19, 2021
e7e9bda
fix: Use the item's project instead of the invoice's
GangaManoj Jul 19, 2021
f421dc7
fix: GL Entry creation
GangaManoj Jul 19, 2021
821b75f
fix: Filter for additional_discount_account
GangaManoj Jul 19, 2021
ed6ebdf
fix: Filter for additional_discount_account
GangaManoj Jul 19, 2021
566e8f8
fix: Create GL Entries for Additional Discount Account
GangaManoj Jul 19, 2021
1f6c05f
fix: Make discount_account mandatory if discount accounting is enabled
GangaManoj Jul 19, 2021
45327e0
fix: Tests
GangaManoj Jul 19, 2021
4fa409e
fix: Add mandatory_depends_on property for Discount Account
GangaManoj Jul 20, 2021
55325ef
Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext…
deepeshgarg007 Jul 21, 2021
fc09d84
fix: Syntax Error
deepeshgarg007 Jul 21, 2021
5a06019
fix: GL For taxes if discount applied on Grand Total
deepeshgarg007 Jul 21, 2021
c765073
fix: Tests
deepeshgarg007 Jul 21, 2021
2ff0d3e
fix: Test Cases
deepeshgarg007 Jul 22, 2021
1c9e516
fix: GL Entries for discount amount with item qty greater than 1
deepeshgarg007 Jul 28, 2021
9b561ea
Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext…
deepeshgarg007 Aug 10, 2021
b73bb3e
fix: Add discount account handling in Purchase Invoice
deepeshgarg007 Aug 5, 2021
428cceb
test: Update test cases for discount accounting
deepeshgarg007 Aug 5, 2021
797170e
fix: Linting issues
deepeshgarg007 Aug 10, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"book_asset_depreciation_entry_automatically",
"unlink_advance_payment_on_cancelation_of_order",
"post_change_gl_entries",
"enable_discount_accounting",
"tax_settings_section",
"determine_address_tax_category_from",
"column_break_19",
Expand Down Expand Up @@ -261,14 +262,21 @@
"fieldname": "post_change_gl_entries",
"fieldtype": "Check",
"label": "Create Ledger Entries for Change Amount"
},
{
"default": "0",
"description": "If enabled, additional ledger entries will be made for discounts in a separate Discount Account",
"fieldname": "enable_discount_accounting",
"fieldtype": "Check",
"label": "Enable Discount Accounting"
}
],
"icon": "icon-cog",
"idx": 1,
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2021-06-17 20:26:03.721202",
"modified": "2021-07-12 18:54:29.084958",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
Expand Down
20 changes: 20 additions & 0 deletions erpnext/accounts/doctype/accounts_settings/accounts_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def validate(self):

self.validate_stale_days()
self.enable_payment_schedule_in_print()
self.toggle_discount_accounting_fields()

def validate_stale_days(self):
if not self.allow_stale and cint(self.stale_days) <= 0:
Expand All @@ -33,3 +34,22 @@ def enable_payment_schedule_in_print(self):
for doctype in ("Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"):
make_property_setter(doctype, "due_date", "print_hide", show_in_print, "Check", validate_fields_for_doctype=False)
make_property_setter(doctype, "payment_schedule", "print_hide", 0 if show_in_print else 1, "Check", validate_fields_for_doctype=False)

def toggle_discount_accounting_fields(self):
enable_discount_accounting = cint(self.enable_discount_accounting)

for doctype in ["Sales Invoice Item", "Purchase Invoice Item"]:
make_property_setter(doctype, "discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
if enable_discount_accounting:
make_property_setter(doctype, "discount_account", "mandatory_depends_on", "eval: doc.discount_amount", "Code", validate_fields_for_doctype=False)
else:
make_property_setter(doctype, "discount_account", "mandatory_depends_on", "", "Code", validate_fields_for_doctype=False)

for doctype in ["Sales Invoice", "Purchase Invoice"]:
make_property_setter(doctype, "additional_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
if enable_discount_accounting:
make_property_setter(doctype, "additional_discount_account", "mandatory_depends_on", "eval: doc.discount_amount", "Code", validate_fields_for_doctype=False)
else:
make_property_setter(doctype, "additional_discount_account", "mandatory_depends_on", "", "Code", validate_fields_for_doctype=False)

make_property_setter("Item", "default_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
22 changes: 21 additions & 1 deletion erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
items_add: function(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
this.frm.script_manager.copy_from_first_row("items", row,
["expense_account", "cost_center", "project"]);
["expense_account", "discount_account", "cost_center", "project"]);
},

on_submit: function() {
Expand Down Expand Up @@ -500,6 +500,16 @@ frappe.ui.form.on("Purchase Invoice", {
'Payment Entry': 'Payment'
}

frm.set_query("additional_discount_account", function() {
return {
filters: {
company: frm.doc.company,
is_group: 0,
report_type: "Profit and Loss",
}
};
});

frm.fields_dict['items'].grid.get_field('deferred_expense_account').get_query = function(doc) {
return {
filters: {
Expand All @@ -509,6 +519,16 @@ frappe.ui.form.on("Purchase Invoice", {
}
}
}

frm.fields_dict['items'].grid.get_field('discount_account').get_query = function(doc) {
return {
filters: {
'report_type': 'Profit and Loss',
'company': doc.company,
"is_group": 0
}
}
}
},

refresh: function(frm) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
"section_break_44",
"apply_discount_on",
"base_discount_amount",
"additional_discount_account",
"column_break_46",
"additional_discount_percentage",
"discount_amount",
Expand Down Expand Up @@ -1691,9 +1692,13 @@
"label": "Per Received",
"no_copy": 1,
"print_hide": 1,
"read_only": 1,
"show_days": 1,
"show_seconds": 1
"read_only": 1
},
{
"fieldname": "additional_discount_account",
"fieldtype": "Link",
"label": "Additional Discount Account",
"options": "Account"
},
{
"default": "0",
Expand Down
22 changes: 14 additions & 8 deletions erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ def get_gl_entries(self, warehouse_account=None):

self.make_supplier_gl_entry(gl_entries)
self.make_item_gl_entries(gl_entries)
self.make_discount_gl_entries(gl_entries)

if self.check_asset_cwip_enabled():
self.get_asset_gl_entry(gl_entries)
Expand Down Expand Up @@ -518,6 +519,8 @@ def make_item_gl_entries(self, gl_entries):
if d.category in ('Valuation', 'Total and Valuation')
and flt(d.base_tax_amount_after_discount_amount)]

enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))

for item in self.get("items"):
if flt(item.base_net_amount):
account_currency = get_account_currency(item.expense_account)
Expand Down Expand Up @@ -608,7 +611,7 @@ def make_item_gl_entries(self, gl_entries):
if (not item.enable_deferred_expense or self.is_return) else item.deferred_expense_account)

if not item.is_fixed_asset:
amount = flt(item.base_net_amount, item.precision("base_net_amount"))
dummy, amount = self.get_amount_and_base_amount(item, enable_discount_accounting)
else:
amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount"))

Expand Down Expand Up @@ -822,8 +825,11 @@ def make_stock_adjustment_entry(self, gl_entries, item, voucher_wise_stock_value
def make_tax_gl_entries(self, gl_entries):
# tax table gl entries
valuation_tax = {}
enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))

for tax in self.get("taxes"):
if tax.category in ("Total", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount):
amount, base_amount = self.get_tax_amounts(tax, enable_discount_accounting)
if tax.category in ("Total", "Valuation and Total") and flt(base_amount):
account_currency = get_account_currency(tax.account_head)

dr_or_cr = "debit" if tax.add_deduct_tax == "Add" else "credit"
Expand All @@ -832,21 +838,21 @@ def make_tax_gl_entries(self, gl_entries):
self.get_gl_dict({
"account": tax.account_head,
"against": self.supplier,
dr_or_cr: tax.base_tax_amount_after_discount_amount,
dr_or_cr + "_in_account_currency": tax.base_tax_amount_after_discount_amount \
if account_currency==self.company_currency \
else tax.tax_amount_after_discount_amount,
dr_or_cr: base_amount,
dr_or_cr + "_in_account_currency": base_amount
if account_currency==self.company_currency
else amount,
"cost_center": tax.cost_center
}, account_currency, item=tax)
)
# accumulate valuation tax
if self.is_opening == "No" and tax.category in ("Valuation", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount) \
if self.is_opening == "No" and tax.category in ("Valuation", "Valuation and Total") and flt(base_amount) \
and not self.is_internal_transfer():
if self.auto_accounting_for_stock and not tax.cost_center:
frappe.throw(_("Cost Center is required in row {0} in Taxes table for type {1}").format(tax.idx, _(tax.category)))
valuation_tax.setdefault(tax.name, 0)
valuation_tax[tax.name] += \
(tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.base_tax_amount_after_discount_amount)
(tax.add_deduct_tax == "Add" and 1 or -1) * flt(base_amount)

if self.is_opening == "No" and self.negative_expense_to_be_booked and valuation_tax:
# credit valuation tax amount in "Expenses Included In Valuation"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,50 @@ def check_gle_for_pi(self, pi):
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)

def test_purchase_invoice_with_discount_accounting_enabled(self):
enable_discount_accounting()

discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
pi = make_purchase_invoice(discount_account=discount_account, rate=45)

expected_gle = [
["_Test Account Cost for Goods Sold - _TC", 250.0, 0.0, nowdate()],
["Creditors - _TC", 0.0, 225.0, nowdate()],
["Discount Account - _TC", 0.0, 25.0, nowdate()]
]

check_gl_entries(self, pi.name, expected_gle, nowdate())
enable_discount_accounting(enable=0)

def test_additional_discount_for_purchase_invoice_with_discount_accounting_enabled(self):
enable_discount_accounting()
additional_discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")

pi = make_purchase_invoice(do_not_save=1, parent_cost_center="Main - _TC")
pi.apply_discount_on = "Grand Total"
pi.additional_discount_account = additional_discount_account
pi.additional_discount_percentage = 10
pi.disable_rounded_total = 1
pi.append("taxes", {
"charge_type": "On Net Total",
"account_head": "_Test Account VAT - _TC",
"cost_center": "Main - _TC",
"description": "Test",
"rate": 10
})
pi.submit()

expected_gle = [
["_Test Account Cost for Goods Sold - _TC", 250.0, 0.0, nowdate()],
["_Test Account VAT - _TC", 25.0, 0.0, nowdate()],
["Creditors - _TC", 0.0, 247.5, nowdate()],
["Discount Account - _TC", 0.0, 27.5, nowdate()]
]

check_gl_entries(self, pi.name, expected_gle, nowdate())

def test_purchase_invoice_change_naming_series(self):
pi = frappe.copy_doc(test_records[1])
pi.insert()
Expand Down Expand Up @@ -1140,6 +1184,18 @@ def test_purchase_invoice_advance_taxes(self):
self.assertEqual(expected_gle[i][0], gle.account)
self.assertEqual(expected_gle[i][1], gle.amount)

def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
gl_entries = frappe.db.sql("""select account, debit, credit, posting_date
from `tabGL Entry`
where voucher_type='Purchase Invoice' and voucher_no=%s and posting_date >= %s
order by posting_date asc, account asc""", (voucher_no, posting_date), as_dict=1)

for i, gle in enumerate(gl_entries):
doc.assertEqual(expected_gle[i][0], gle.account)
doc.assertEqual(expected_gle[i][1], gle.debit)
doc.assertEqual(expected_gle[i][2], gle.credit)
doc.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)

def update_tax_witholding_category(company, account, date):
from erpnext.accounts.utils import get_fiscal_year

Expand Down Expand Up @@ -1170,6 +1226,11 @@ def unlink_payment_on_cancel_of_invoice(enable=1):
accounts_settings.unlink_payment_on_cancellation_of_invoice = enable
accounts_settings.save()

def enable_discount_accounting(enable=1):
accounts_settings = frappe.get_doc("Accounts Settings")
accounts_settings.enable_discount_accounting = enable
accounts_settings.save()

def make_purchase_invoice(**args):
pi = frappe.new_doc("Purchase Invoice")
args = frappe._dict(args)
Expand All @@ -1192,6 +1253,7 @@ def make_purchase_invoice(**args):
pi.return_against = args.return_against
pi.is_subcontracted = args.is_subcontracted or "No"
pi.supplier_warehouse = args.supplier_warehouse or "_Test Warehouse 1 - _TC"
pi.cost_center = args.parent_cost_center

pi.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
Expand All @@ -1200,7 +1262,10 @@ def make_purchase_invoice(**args):
"received_qty": args.received_qty or 0,
"rejected_qty": args.rejected_qty or 0,
"rate": args.rate or 50,
'expense_account': args.expense_account or '_Test Account Cost for Goods Sold - _TC',
"price_list_rate": args.price_list_rate or 50,
"expense_account": args.expense_account or '_Test Account Cost for Goods Sold - _TC',
"discount_account": args.discount_account or None,
"discount_amount": args.discount_amount or 0,
"conversion_factor": 1.0,
"serial_no": args.serial_no,
"stock_uom": args.uom or "_Test UOM",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"manufacturer_part_no",
"accounting",
"expense_account",
"discount_account",
"col_break5",
"is_fixed_asset",
"asset_location",
Expand Down Expand Up @@ -849,12 +850,18 @@
"options": "Company:company:default_currency",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "discount_account",
"fieldtype": "Link",
"label": "Discount Account",
"options": "Account"
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2021-06-16 19:57:03.101571",
"modified": "2021-07-13 02:04:37.787882",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",
Expand Down
24 changes: 22 additions & 2 deletions erpnext/accounts/doctype/sales_invoice/sales_invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte

items_add: function(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
this.frm.script_manager.copy_from_first_row("items", row, ["income_account", "cost_center"]);
this.frm.script_manager.copy_from_first_row("items", row, ["income_account", "discount_account", "cost_center"]);
},

set_dynamic_labels: function() {
Expand Down Expand Up @@ -510,7 +510,6 @@ cur_frm.set_query("income_account", "items", function(doc) {
}
});


// Cost Center in Details Table
// -----------------------------
cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(doc) {
Expand Down Expand Up @@ -592,6 +591,16 @@ frappe.ui.form.on('Sales Invoice', {
};
});

frm.set_query("additional_discount_account", function() {
return {
filters: {
company: frm.doc.company,
is_group: 0,
report_type: "Profit and Loss",
}
};
});

frm.custom_make_buttons = {
'Delivery Note': 'Delivery',
'Sales Invoice': 'Return / Credit Note',
Expand All @@ -618,6 +627,17 @@ frappe.ui.form.on('Sales Invoice', {
}
}

// discount account
frm.fields_dict['items'].grid.get_field('discount_account').get_query = function(doc) {
return {
filters: {
'report_type': 'Profit and Loss',
'company': doc.company,
"is_group": 0
}
}
}

frm.fields_dict['items'].grid.get_field('deferred_revenue_account').get_query = function(doc) {
return {
filters: {
Expand Down
Loading