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 #26359

Merged
merged 54 commits into from
Aug 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
be15e16
feat(Accounts Settings): Add 'Enable Discount Accounting' checkbox
GangaManoj Jul 5, 2021
6e0d83d
feat(Sales Invoice): Add 'Discount Account' field in Items table
GangaManoj Jul 5, 2021
cf7579e
feat: Create GL Entries for discount accounting
GangaManoj Jul 5, 2021
b08bb1f
feat: Filter list for Discount Account field in Items table
GangaManoj Jul 6, 2021
ef667a9
feat: Add Default Discount Account field
GangaManoj Jul 6, 2021
657e9b5
feat: Assign Item's Default Discount Account if present
GangaManoj Jul 6, 2021
3ea4f99
feat: Toggle display for discount accounting fields according to enab…
GangaManoj Jul 6, 2021
9910968
Merge branch 'develop' into enable-discount-accounting
nextchamp-saqib Jul 7, 2021
0d5ad3b
fix: Add description for Enable Discount Accounting checkbox
GangaManoj Jul 12, 2021
b22dba1
fix: Filter Discount Account list
GangaManoj Jul 12, 2021
4fcdc5d
fix: Copy discount account from first row to all Items
GangaManoj Jul 12, 2021
0b7d8fb
fix: Move Default Discount Account field to Item Defaults
GangaManoj Jul 12, 2021
b85d301
fix: Filter options for Default Discount Account
GangaManoj Jul 12, 2021
555852c
fix: Add Discount Account field
GangaManoj Jul 12, 2021
4b8918e
fix: Display Discount Account only if Enable Discount Accounting is c…
GangaManoj Jul 12, 2021
81375ae
fix: Copy Discount Account from first row
GangaManoj Jul 12, 2021
65e2b9f
fix: Filter options for Discount Account
GangaManoj Jul 12, 2021
8f7b0a1
fix: Create common function for discount accounting
GangaManoj Jul 12, 2021
2f4c607
fix: Add tests for discount accounting
GangaManoj Jul 13, 2021
4f2bf98
fix: Add Additional Discount Account field
GangaManoj Jul 15, 2021
8e96e2d
fix: Filter options for Additional Discount Account
GangaManoj Jul 15, 2021
40412f7
fix: Only display Additional Discount Account if Enable Discount Acco…
GangaManoj Jul 15, 2021
857501c
fix: Make additional GL Entries for discount applied on taxes
GangaManoj Jul 15, 2021
6bff653
fix: Sider issues
GangaManoj Jul 15, 2021
b0f2182
fix: Check all expected GL Entries
GangaManoj Jul 17, 2021
87d448e
fix: Add Additional Discount Account field
GangaManoj Jul 17, 2021
7bbc9a8
fix: Filter options for Additional Discount Account
GangaManoj Jul 17, 2021
fa4c03e
fix: Create ledger entries for discount applied on taxes in make_tax_…
GangaManoj Jul 17, 2021
c2ba689
fix: Only display Additional Discount Account if Enable Discount Acco…
GangaManoj Jul 17, 2021
c4d2dc0
fix: Remove unnecessary condition
GangaManoj Jul 17, 2021
99551e9
fix: Add test for additional discount applied on taxes
GangaManoj Jul 17, 2021
2284993
fix: Switch debit and credit for ledger entries for discount applied …
GangaManoj Jul 17, 2021
d6956ff
fix: Add test for additional discount applied on taxes
GangaManoj Jul 17, 2021
bfb7256
Merge branch 'develop' into enable-discount-accounting
GangaManoj Jul 17, 2021
980798c
fix: Use the item's cost centre instead of the Invoice's
GangaManoj Jul 19, 2021
63b7ecd
fix: Use the item's project instead of the invoice's
GangaManoj Jul 19, 2021
0ea2934
fix: GL Entry creation
GangaManoj Jul 19, 2021
8fc9c13
fix: Filter for additional_discount_account
GangaManoj Jul 19, 2021
1d830df
fix: Filter for additional_discount_account
GangaManoj Jul 19, 2021
4105e27
fix: Create GL Entries for Additional Discount Account
GangaManoj Jul 19, 2021
59ee695
fix: Make discount_account mandatory if discount accounting is enabled
GangaManoj Jul 19, 2021
82d147e
fix: Tests
GangaManoj Jul 19, 2021
46bed5e
fix: Add mandatory_depends_on property for Discount Account
GangaManoj Jul 20, 2021
b7267f8
fix: Syntax Error
deepeshgarg007 Jul 21, 2021
92f7a5a
fix: GL For taxes if discount applied on Grand Total
deepeshgarg007 Jul 21, 2021
c525b37
fix: Tests
deepeshgarg007 Jul 21, 2021
c677d47
fix: Test Cases
deepeshgarg007 Jul 22, 2021
ad7bb31
fix: GL Entries for discount amount with item qty greater than 1
deepeshgarg007 Jul 28, 2021
cb539b7
fix: Add discount account handling in Purchase Invoice
deepeshgarg007 Aug 5, 2021
75a8327
test: Update test cases for discount accounting
deepeshgarg007 Aug 5, 2021
5122948
Merge branch 'develop' of https://github.com/frappe/erpnext into enab…
deepeshgarg007 Aug 13, 2021
5999760
fix: Syntax error
GangaManoj Aug 13, 2021
f977c65
fix: Make enable_discount_accounting a class property
GangaManoj Aug 13, 2021
f9356ee
fix: Sider issues
GangaManoj Aug 13, 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 @@ -20,6 +20,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 @@ -260,6 +261,13 @@
"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",
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 = class PurchaseInvoice extends erpnext.buying.
items_add(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() {
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
28 changes: 19 additions & 9 deletions erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,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 @@ -521,7 +522,7 @@ def make_item_gl_entries(self, gl_entries):
and flt(d.base_tax_amount_after_discount_amount)]

exchange_rate_map, net_rate_map = get_purchase_document_details(self)

for item in self.get("items"):
if flt(item.base_net_amount):
account_currency = get_account_currency(item.expense_account)
Expand Down Expand Up @@ -612,7 +613,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, self.enable_discount_accounting)
else:
amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount"))

Expand Down Expand Up @@ -854,8 +855,10 @@ 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 = {}

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, self.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 @@ -864,21 +867,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 Expand Up @@ -919,6 +922,13 @@ def make_tax_gl_entries(self, gl_entries):
"remarks": self.remarks or "Accounting Entry for Stock"
}, item=tax))

@property
def enable_discount_accounting(self):
if not hasattr(self, "_enable_discount_accounting"):
self._enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))

return self._enable_discount_accounting

def make_internal_transfer_gl_entries(self, gl_entries):
if self.is_internal_transfer() and flt(self.base_total_taxes_and_charges):
account_currency = get_account_currency(self.unrealized_profit_loss_account)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,50 @@ def test_purchase_invoice_with_exchange_rate_difference(self):

self.assertEqual(discrepancy_caused_by_exchange_rate_diff, amount)

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 @@ -1161,6 +1205,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 @@ -1191,6 +1247,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 @@ -1213,6 +1274,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 @@ -1221,7 +1283,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 @@ -850,6 +851,12 @@
"options": "Company:company:default_currency",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "discount_account",
"fieldtype": "Link",
"label": "Discount Account",
"options": "Account"
}
],
"idx": 1,
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 = class SalesInvoiceController extends e

items_add(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() {
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
7 changes: 7 additions & 0 deletions erpnext/accounts/doctype/sales_invoice/sales_invoice.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
"section_break_49",
"apply_discount_on",
"base_discount_amount",
"additional_discount_account",
"column_break_51",
"additional_discount_percentage",
"discount_amount",
Expand Down Expand Up @@ -2332,6 +2333,12 @@
"fieldtype": "Check",
"label": "Disable Rounded Total"
},
{
"fieldname": "additional_discount_account",
"fieldtype": "Link",
"label": "Additional Discount Account",
"options": "Account"
},
{
"allow_on_submit": 1,
"fieldname": "dispatch_address_name",
Expand Down
Loading