mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-31 10:49:09 +00:00
Merge pull request #46941 from frappe/version-14-hotfix
chore: release v14
This commit is contained in:
@@ -46,9 +46,6 @@ class BankClearance(Document):
|
|||||||
as_dict=1,
|
as_dict=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.bank_account:
|
|
||||||
condition += "and bank_account = %(bank_account)s"
|
|
||||||
|
|
||||||
payment_entries = frappe.db.sql(
|
payment_entries = frappe.db.sql(
|
||||||
f"""
|
f"""
|
||||||
select
|
select
|
||||||
@@ -70,7 +67,6 @@ class BankClearance(Document):
|
|||||||
"account": self.account,
|
"account": self.account,
|
||||||
"from": self.from_date,
|
"from": self.from_date,
|
||||||
"to": self.to_date,
|
"to": self.to_date,
|
||||||
"bank_account": self.bank_account,
|
|
||||||
},
|
},
|
||||||
as_dict=1,
|
as_dict=1,
|
||||||
)
|
)
|
||||||
@@ -93,7 +89,7 @@ class BankClearance(Document):
|
|||||||
.where(loan_disbursement.docstatus == 1)
|
.where(loan_disbursement.docstatus == 1)
|
||||||
.where(loan_disbursement.disbursement_date >= self.from_date)
|
.where(loan_disbursement.disbursement_date >= self.from_date)
|
||||||
.where(loan_disbursement.disbursement_date <= self.to_date)
|
.where(loan_disbursement.disbursement_date <= self.to_date)
|
||||||
.where(loan_disbursement.disbursement_account.isin([self.bank_account, self.account]))
|
.where(loan_disbursement.disbursement_account == self.account)
|
||||||
.orderby(loan_disbursement.disbursement_date)
|
.orderby(loan_disbursement.disbursement_date)
|
||||||
.orderby(loan_disbursement.name, order=frappe.qb.desc)
|
.orderby(loan_disbursement.name, order=frappe.qb.desc)
|
||||||
)
|
)
|
||||||
@@ -121,7 +117,7 @@ class BankClearance(Document):
|
|||||||
.where(loan_repayment.docstatus == 1)
|
.where(loan_repayment.docstatus == 1)
|
||||||
.where(loan_repayment.posting_date >= self.from_date)
|
.where(loan_repayment.posting_date >= self.from_date)
|
||||||
.where(loan_repayment.posting_date <= self.to_date)
|
.where(loan_repayment.posting_date <= self.to_date)
|
||||||
.where(loan_repayment.payment_account.isin([self.bank_account, self.account]))
|
.where(loan_repayment.payment_account == self.account)
|
||||||
)
|
)
|
||||||
|
|
||||||
if not self.include_reconciled_entries:
|
if not self.include_reconciled_entries:
|
||||||
|
|||||||
@@ -1852,7 +1852,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
|
|||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
pi = make_pi_from_pr(pr.name)
|
pi = make_pi_from_pr(pr.name)
|
||||||
self.assertEqual(pi.payment_schedule[0].payment_amount, 2500)
|
self.assertEqual(pi.payment_schedule[0].payment_amount, 1000)
|
||||||
|
|
||||||
automatically_fetch_payment_terms(enable=0)
|
automatically_fetch_payment_terms(enable=0)
|
||||||
frappe.db.set_value(
|
frappe.db.set_value(
|
||||||
@@ -1984,6 +1984,78 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
|
|||||||
|
|
||||||
self.assertRaises(frappe.ValidationError, dr_note.save)
|
self.assertRaises(frappe.ValidationError, dr_note.save)
|
||||||
|
|
||||||
|
def test_apply_discount_on_grand_total(self):
|
||||||
|
"""
|
||||||
|
To test if after applying discount on grand total,
|
||||||
|
the grand total is calculated correctly without any rounding errors
|
||||||
|
"""
|
||||||
|
invoice = make_purchase_invoice(qty=2, rate=100, do_not_save=True, do_not_submit=True)
|
||||||
|
invoice.append(
|
||||||
|
"items",
|
||||||
|
{
|
||||||
|
"item_code": "_Test Item",
|
||||||
|
"qty": 1,
|
||||||
|
"rate": 21.39,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
invoice.append(
|
||||||
|
"taxes",
|
||||||
|
{
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"account_head": "_Test Account VAT - _TC",
|
||||||
|
"description": "VAT",
|
||||||
|
"rate": 15.5,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# the grand total here will be 255.71
|
||||||
|
invoice.disable_rounded_total = 1
|
||||||
|
# apply discount on grand total to adjust the grand total to 255
|
||||||
|
invoice.discount_amount = 0.71
|
||||||
|
invoice.save()
|
||||||
|
|
||||||
|
# check if grand total is 496 and not something like 254.99 due to rounding errors
|
||||||
|
self.assertEqual(invoice.grand_total, 255)
|
||||||
|
|
||||||
|
def test_apply_discount_on_grand_total_with_previous_row_total_tax(self):
|
||||||
|
"""
|
||||||
|
To test if after applying discount on grand total,
|
||||||
|
where the tax is calculated on previous row total, the grand total is calculated correctly
|
||||||
|
"""
|
||||||
|
|
||||||
|
invoice = make_purchase_invoice(qty=2, rate=100, do_not_save=True, do_not_submit=True)
|
||||||
|
invoice.extend(
|
||||||
|
"taxes",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"charge_type": "Actual",
|
||||||
|
"account_head": "_Test Account VAT - _TC",
|
||||||
|
"description": "VAT",
|
||||||
|
"tax_amount": 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"charge_type": "On Previous Row Amount",
|
||||||
|
"account_head": "_Test Account VAT - _TC",
|
||||||
|
"description": "VAT",
|
||||||
|
"row_id": 1,
|
||||||
|
"rate": 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"charge_type": "On Previous Row Total",
|
||||||
|
"account_head": "_Test Account VAT - _TC",
|
||||||
|
"description": "VAT",
|
||||||
|
"row_id": 1,
|
||||||
|
"rate": 10,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# the total here will be 340, so applying 40 discount
|
||||||
|
invoice.discount_amount = 40
|
||||||
|
invoice.save()
|
||||||
|
|
||||||
|
self.assertEqual(invoice.grand_total, 300)
|
||||||
|
|
||||||
|
|
||||||
def check_gl_entries(
|
def check_gl_entries(
|
||||||
doc,
|
doc,
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ class SalesInvoice(SellingController):
|
|||||||
self.indicator_title = _("Paid")
|
self.indicator_title = _("Paid")
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
super().validate()
|
|
||||||
self.validate_auto_set_posting_time()
|
self.validate_auto_set_posting_time()
|
||||||
|
super().validate()
|
||||||
|
|
||||||
if not (self.is_pos or self.is_debit_note):
|
if not (self.is_pos or self.is_debit_note):
|
||||||
self.so_dn_required()
|
self.so_dn_required()
|
||||||
|
|||||||
@@ -416,9 +416,9 @@ class TestSalesInvoice(FrappeTestCase):
|
|||||||
for i, k in enumerate(expected_values["keys"]):
|
for i, k in enumerate(expected_values["keys"]):
|
||||||
self.assertEqual(d.get(k), expected_values[d.account_head][i])
|
self.assertEqual(d.get(k), expected_values[d.account_head][i])
|
||||||
|
|
||||||
self.assertEqual(si.base_grand_total, 1500.01)
|
self.assertEqual(si.base_grand_total, 1500)
|
||||||
self.assertEqual(si.grand_total, 1500.01)
|
self.assertEqual(si.grand_total, 1500)
|
||||||
self.assertEqual(si.rounding_adjustment, -0.01)
|
self.assertEqual(si.rounding_adjustment, 0)
|
||||||
|
|
||||||
def test_discount_amount_gl_entry(self):
|
def test_discount_amount_gl_entry(self):
|
||||||
frappe.db.set_value("Company", "_Test Company", "round_off_account", "Round Off - _TC")
|
frappe.db.set_value("Company", "_Test Company", "round_off_account", "Round Off - _TC")
|
||||||
@@ -3860,6 +3860,35 @@ class TestSalesInvoice(FrappeTestCase):
|
|||||||
doc = frappe.get_doc("Project", project.name)
|
doc = frappe.get_doc("Project", project.name)
|
||||||
self.assertEqual(doc.total_billed_amount, si.grand_total)
|
self.assertEqual(doc.total_billed_amount, si.grand_total)
|
||||||
|
|
||||||
|
def test_create_return_invoice_for_self_update(self):
|
||||||
|
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||||
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
|
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||||
|
|
||||||
|
invoice = create_sales_invoice()
|
||||||
|
|
||||||
|
payment_entry = get_payment_entry(dt=invoice.doctype, dn=invoice.name)
|
||||||
|
payment_entry.reference_no = "test001"
|
||||||
|
payment_entry.reference_date = getdate()
|
||||||
|
|
||||||
|
payment_entry.save()
|
||||||
|
payment_entry.submit()
|
||||||
|
|
||||||
|
r_invoice = make_return_doc(invoice.doctype, invoice.name)
|
||||||
|
|
||||||
|
r_invoice.update_outstanding_for_self = 0
|
||||||
|
r_invoice.save()
|
||||||
|
|
||||||
|
self.assertEqual(r_invoice.update_outstanding_for_self, 1)
|
||||||
|
|
||||||
|
r_invoice.submit()
|
||||||
|
|
||||||
|
self.assertNotEqual(r_invoice.outstanding_amount, 0)
|
||||||
|
|
||||||
|
invoice.reload()
|
||||||
|
|
||||||
|
self.assertEqual(invoice.outstanding_amount, 0)
|
||||||
|
|
||||||
|
|
||||||
def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
|
def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
|
||||||
gl_entries = frappe.db.sql(
|
gl_entries = frappe.db.sql(
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
frappe.db.rollback()
|
frappe.db.rollback()
|
||||||
|
|
||||||
def create_sales_invoice(self, no_payment_schedule=False, do_not_submit=False):
|
def create_sales_invoice(self, no_payment_schedule=False, do_not_submit=False, **args):
|
||||||
frappe.set_user("Administrator")
|
frappe.set_user("Administrator")
|
||||||
si = create_sales_invoice(
|
si = create_sales_invoice(
|
||||||
item=self.item,
|
item=self.item,
|
||||||
@@ -34,6 +34,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
|
|||||||
rate=100,
|
rate=100,
|
||||||
price_list_rate=100,
|
price_list_rate=100,
|
||||||
do_not_save=1,
|
do_not_save=1,
|
||||||
|
**args,
|
||||||
)
|
)
|
||||||
if not no_payment_schedule:
|
if not no_payment_schedule:
|
||||||
si.append(
|
si.append(
|
||||||
@@ -111,7 +112,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
|
|||||||
self.assertEqual(expected_data[0], [row.invoiced, row.paid, row.credit_note])
|
self.assertEqual(expected_data[0], [row.invoiced, row.paid, row.credit_note])
|
||||||
pos_inv.cancel()
|
pos_inv.cancel()
|
||||||
|
|
||||||
def test_accounts_receivable(self):
|
def test_accounts_receivable_with_payment(self):
|
||||||
filters = {
|
filters = {
|
||||||
"company": self.company,
|
"company": self.company,
|
||||||
"based_on_payment_terms": 1,
|
"based_on_payment_terms": 1,
|
||||||
@@ -151,11 +152,15 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
|
|||||||
cr_note = self.create_credit_note(si.name, do_not_submit=True)
|
cr_note = self.create_credit_note(si.name, do_not_submit=True)
|
||||||
cr_note.update_outstanding_for_self = False
|
cr_note.update_outstanding_for_self = False
|
||||||
cr_note.save().submit()
|
cr_note.save().submit()
|
||||||
|
|
||||||
|
# as the invoice partially paid and returning the full amount so the outstanding amount should be True
|
||||||
|
self.assertEqual(cr_note.update_outstanding_for_self, True)
|
||||||
|
|
||||||
report = execute(filters)
|
report = execute(filters)
|
||||||
|
|
||||||
expected_data_after_credit_note = [100, 0, 0, 40, -40, self.debit_to]
|
expected_data_after_credit_note = [0, 0, 100, 0, -100, self.debit_to]
|
||||||
|
|
||||||
row = report[1][0]
|
row = report[1][-1]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected_data_after_credit_note,
|
expected_data_after_credit_note,
|
||||||
[
|
[
|
||||||
@@ -168,6 +173,105 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_accounts_receivable_without_payment(self):
|
||||||
|
filters = {
|
||||||
|
"company": self.company,
|
||||||
|
"based_on_payment_terms": 1,
|
||||||
|
"report_date": today(),
|
||||||
|
"range1": 30,
|
||||||
|
"range2": 60,
|
||||||
|
"range3": 90,
|
||||||
|
"range4": 120,
|
||||||
|
"show_remarks": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
# check invoice grand total and invoiced column's value for 3 payment terms
|
||||||
|
si = self.create_sales_invoice()
|
||||||
|
|
||||||
|
report = execute(filters)
|
||||||
|
|
||||||
|
expected_data = [[100, 30, "No Remarks"], [100, 50, "No Remarks"], [100, 20, "No Remarks"]]
|
||||||
|
|
||||||
|
for i in range(3):
|
||||||
|
row = report[1][i - 1]
|
||||||
|
self.assertEqual(expected_data[i - 1], [row.invoice_grand_total, row.invoiced, row.remarks])
|
||||||
|
|
||||||
|
# check invoice grand total, invoiced, paid and outstanding column's value after credit note
|
||||||
|
cr_note = self.create_credit_note(si.name, do_not_submit=True)
|
||||||
|
cr_note.update_outstanding_for_self = False
|
||||||
|
cr_note.save().submit()
|
||||||
|
|
||||||
|
self.assertEqual(cr_note.update_outstanding_for_self, False)
|
||||||
|
|
||||||
|
report = execute(filters)
|
||||||
|
|
||||||
|
row = report[1]
|
||||||
|
self.assertTrue(len(row) == 0)
|
||||||
|
|
||||||
|
def test_accounts_receivable_with_partial_payment(self):
|
||||||
|
filters = {
|
||||||
|
"company": self.company,
|
||||||
|
"based_on_payment_terms": 1,
|
||||||
|
"report_date": today(),
|
||||||
|
"range1": 30,
|
||||||
|
"range2": 60,
|
||||||
|
"range3": 90,
|
||||||
|
"range4": 120,
|
||||||
|
"show_remarks": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
# check invoice grand total and invoiced column's value for 3 payment terms
|
||||||
|
si = self.create_sales_invoice(qty=2)
|
||||||
|
|
||||||
|
report = execute(filters)
|
||||||
|
|
||||||
|
expected_data = [[200, 60, "No Remarks"], [200, 100, "No Remarks"], [200, 40, "No Remarks"]]
|
||||||
|
|
||||||
|
for i in range(3):
|
||||||
|
row = report[1][i - 1]
|
||||||
|
self.assertEqual(expected_data[i - 1], [row.invoice_grand_total, row.invoiced, row.remarks])
|
||||||
|
|
||||||
|
# check invoice grand total, invoiced, paid and outstanding column's value after payment
|
||||||
|
self.create_payment_entry(si.name)
|
||||||
|
report = execute(filters)
|
||||||
|
|
||||||
|
expected_data_after_payment = [[200, 60, 40, 20], [200, 100, 0, 100], [200, 40, 0, 40]]
|
||||||
|
|
||||||
|
for i in range(3):
|
||||||
|
row = report[1][i - 1]
|
||||||
|
self.assertEqual(
|
||||||
|
expected_data_after_payment[i - 1],
|
||||||
|
[row.invoice_grand_total, row.invoiced, row.paid, row.outstanding],
|
||||||
|
)
|
||||||
|
|
||||||
|
# check invoice grand total, invoiced, paid and outstanding column's value after credit note
|
||||||
|
cr_note = self.create_credit_note(si.name, do_not_submit=True)
|
||||||
|
cr_note.update_outstanding_for_self = False
|
||||||
|
cr_note.save().submit()
|
||||||
|
|
||||||
|
self.assertFalse(cr_note.update_outstanding_for_self)
|
||||||
|
|
||||||
|
report = execute(filters)
|
||||||
|
|
||||||
|
expected_data_after_credit_note = [
|
||||||
|
[200, 100, 0, 80, 20, self.debit_to],
|
||||||
|
[200, 40, 0, 0, 40, self.debit_to],
|
||||||
|
]
|
||||||
|
|
||||||
|
for i in range(2):
|
||||||
|
row = report[1][i - 1]
|
||||||
|
self.assertEqual(
|
||||||
|
expected_data_after_credit_note[i - 1],
|
||||||
|
[
|
||||||
|
row.invoice_grand_total,
|
||||||
|
row.invoiced,
|
||||||
|
row.paid,
|
||||||
|
row.credit_note,
|
||||||
|
row.outstanding,
|
||||||
|
row.party_account,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def test_cr_note_flag_to_update_self(self):
|
def test_cr_note_flag_to_update_self(self):
|
||||||
filters = {
|
filters = {
|
||||||
"company": self.company,
|
"company": self.company,
|
||||||
|
|||||||
@@ -25,11 +25,26 @@ frappe.query_reports["Asset Depreciations and Balances"] = {
|
|||||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
|
||||||
reqd: 1,
|
reqd: 1,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldname: "group_by",
|
||||||
|
label: __("Group By"),
|
||||||
|
fieldtype: "Select",
|
||||||
|
options: ["Asset Category", "Asset"],
|
||||||
|
default: "Asset Category",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldname: "asset_category",
|
fieldname: "asset_category",
|
||||||
label: __("Asset Category"),
|
label: __("Asset Category"),
|
||||||
fieldtype: "Link",
|
fieldtype: "Link",
|
||||||
options: "Asset Category",
|
options: "Asset Category",
|
||||||
|
depends_on: "eval: doc.group_by == 'Asset Category'",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: "asset",
|
||||||
|
label: __("Asset"),
|
||||||
|
fieldtype: "Link",
|
||||||
|
options: "Asset",
|
||||||
|
depends_on: "eval: doc.group_by == 'Asset'",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,21 +14,28 @@ def execute(filters=None):
|
|||||||
|
|
||||||
|
|
||||||
def get_data(filters):
|
def get_data(filters):
|
||||||
|
if filters.get("group_by") == "Asset Category":
|
||||||
|
return get_group_by_asset_category_data(filters)
|
||||||
|
elif filters.get("group_by") == "Asset":
|
||||||
|
return get_group_by_asset_data(filters)
|
||||||
|
|
||||||
|
|
||||||
|
def get_group_by_asset_category_data(filters):
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
asset_categories = get_asset_categories(filters)
|
asset_categories = get_asset_categories_for_grouped_by_category(filters)
|
||||||
assets = get_assets(filters)
|
assets = get_assets_for_grouped_by_category(filters)
|
||||||
|
|
||||||
for asset_category in asset_categories:
|
for asset_category in asset_categories:
|
||||||
row = frappe._dict()
|
row = frappe._dict()
|
||||||
# row.asset_category = asset_category
|
|
||||||
row.update(asset_category)
|
row.update(asset_category)
|
||||||
|
|
||||||
row.cost_as_on_to_date = (
|
row.value_as_on_to_date = (
|
||||||
flt(row.cost_as_on_from_date)
|
flt(row.value_as_on_from_date)
|
||||||
+ flt(row.cost_of_new_purchase)
|
+ flt(row.value_of_new_purchase)
|
||||||
- flt(row.cost_of_sold_asset)
|
- flt(row.value_of_sold_asset)
|
||||||
- flt(row.cost_of_scrapped_asset)
|
- flt(row.value_of_scrapped_asset)
|
||||||
|
- flt(row.value_of_capitalized_asset)
|
||||||
)
|
)
|
||||||
|
|
||||||
row.update(
|
row.update(
|
||||||
@@ -38,17 +45,19 @@ def get_data(filters):
|
|||||||
if asset["asset_category"] == asset_category.get("asset_category", "")
|
if asset["asset_category"] == asset_category.get("asset_category", "")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
row.accumulated_depreciation_as_on_to_date = (
|
row.accumulated_depreciation_as_on_to_date = (
|
||||||
flt(row.accumulated_depreciation_as_on_from_date)
|
flt(row.accumulated_depreciation_as_on_from_date)
|
||||||
+ flt(row.depreciation_amount_during_the_period)
|
+ flt(row.depreciation_amount_during_the_period)
|
||||||
- flt(row.depreciation_eliminated_during_the_period)
|
- flt(row.depreciation_eliminated_during_the_period)
|
||||||
|
- flt(row.depreciation_eliminated_via_reversal)
|
||||||
)
|
)
|
||||||
|
|
||||||
row.net_asset_value_as_on_from_date = flt(row.cost_as_on_from_date) - flt(
|
row.net_asset_value_as_on_from_date = flt(row.value_as_on_from_date) - flt(
|
||||||
row.accumulated_depreciation_as_on_from_date
|
row.accumulated_depreciation_as_on_from_date
|
||||||
)
|
)
|
||||||
|
|
||||||
row.net_asset_value_as_on_to_date = flt(row.cost_as_on_to_date) - flt(
|
row.net_asset_value_as_on_to_date = flt(row.value_as_on_to_date) - flt(
|
||||||
row.accumulated_depreciation_as_on_to_date
|
row.accumulated_depreciation_as_on_to_date
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -57,52 +66,71 @@ def get_data(filters):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def get_asset_categories(filters):
|
def get_asset_categories_for_grouped_by_category(filters):
|
||||||
condition = ""
|
condition = ""
|
||||||
if filters.get("asset_category"):
|
if filters.get("asset_category"):
|
||||||
condition += " and asset_category = %(asset_category)s"
|
condition += " and a.asset_category = %(asset_category)s"
|
||||||
|
|
||||||
|
# nosemgrep
|
||||||
return frappe.db.sql(
|
return frappe.db.sql(
|
||||||
f"""
|
f"""
|
||||||
SELECT asset_category,
|
SELECT a.asset_category,
|
||||||
ifnull(sum(case when purchase_date < %(from_date)s then
|
ifnull(sum(case when a.purchase_date < %(from_date)s then
|
||||||
case when ifnull(disposal_date, 0) = 0 or disposal_date >= %(from_date)s then
|
case when ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s then
|
||||||
gross_purchase_amount
|
a.gross_purchase_amount
|
||||||
else
|
else
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
0
|
0
|
||||||
end), 0) as cost_as_on_from_date,
|
end), 0) as value_as_on_from_date,
|
||||||
ifnull(sum(case when purchase_date >= %(from_date)s then
|
ifnull(sum(case when a.purchase_date >= %(from_date)s then
|
||||||
gross_purchase_amount
|
a.gross_purchase_amount
|
||||||
else
|
else
|
||||||
0
|
0
|
||||||
end), 0) as cost_of_new_purchase,
|
end), 0) as value_of_new_purchase,
|
||||||
ifnull(sum(case when ifnull(disposal_date, 0) != 0
|
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
|
||||||
and disposal_date >= %(from_date)s
|
and a.disposal_date >= %(from_date)s
|
||||||
and disposal_date <= %(to_date)s then
|
and a.disposal_date <= %(to_date)s then
|
||||||
case when status = "Sold" then
|
case when a.status = "Sold" then
|
||||||
gross_purchase_amount
|
a.gross_purchase_amount
|
||||||
else
|
else
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
0
|
0
|
||||||
end), 0) as cost_of_sold_asset,
|
end), 0) as value_of_sold_asset,
|
||||||
ifnull(sum(case when ifnull(disposal_date, 0) != 0
|
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
|
||||||
and disposal_date >= %(from_date)s
|
and a.disposal_date >= %(from_date)s
|
||||||
and disposal_date <= %(to_date)s then
|
and a.disposal_date <= %(to_date)s then
|
||||||
case when status = "Scrapped" then
|
case when a.status = "Scrapped" then
|
||||||
gross_purchase_amount
|
a.gross_purchase_amount
|
||||||
else
|
else
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
0
|
0
|
||||||
end), 0) as cost_of_scrapped_asset
|
end), 0) as value_of_scrapped_asset,
|
||||||
from `tabAsset`
|
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
|
||||||
where docstatus=1 and company=%(company)s and purchase_date <= %(to_date)s {condition}
|
and a.disposal_date >= %(from_date)s
|
||||||
group by asset_category
|
and a.disposal_date <= %(to_date)s then
|
||||||
|
case when a.status = "Capitalized" then
|
||||||
|
a.gross_purchase_amount
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end), 0) as value_of_capitalized_asset
|
||||||
|
from `tabAsset` a
|
||||||
|
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s {condition}
|
||||||
|
and not exists(
|
||||||
|
select 1 from `tabAsset Capitalization Asset Item` acai join `tabAsset Capitalization` ac on acai.parent=ac.name
|
||||||
|
where acai.asset = a.name
|
||||||
|
and ac.posting_date < %(from_date)s
|
||||||
|
and ac.docstatus=1
|
||||||
|
)
|
||||||
|
group by a.asset_category
|
||||||
""",
|
""",
|
||||||
{
|
{
|
||||||
"to_date": filters.to_date,
|
"to_date": filters.to_date,
|
||||||
@@ -114,14 +142,17 @@ def get_asset_categories(filters):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_assets(filters):
|
def get_assets_for_grouped_by_category(filters):
|
||||||
condition = ""
|
condition = ""
|
||||||
if filters.get("asset_category"):
|
if filters.get("asset_category"):
|
||||||
condition = " and a.asset_category = '{}'".format(filters.get("asset_category"))
|
condition = f" and a.asset_category = '{filters.get('asset_category')}'"
|
||||||
|
|
||||||
|
# nosemgrep
|
||||||
return frappe.db.sql(
|
return frappe.db.sql(
|
||||||
"""
|
f"""
|
||||||
SELECT results.asset_category,
|
SELECT results.asset_category,
|
||||||
sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
|
sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
|
||||||
|
sum(results.depreciation_eliminated_via_reversal) as depreciation_eliminated_via_reversal,
|
||||||
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
|
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
|
||||||
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
|
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
|
||||||
from (SELECT a.asset_category,
|
from (SELECT a.asset_category,
|
||||||
@@ -130,6 +161,11 @@ def get_assets(filters):
|
|||||||
else
|
else
|
||||||
0
|
0
|
||||||
end), 0) as accumulated_depreciation_as_on_from_date,
|
end), 0) as accumulated_depreciation_as_on_from_date,
|
||||||
|
ifnull(sum(case when gle.posting_date <= %(to_date)s and ifnull(a.disposal_date, 0) = 0 then
|
||||||
|
gle.credit
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end), 0) as depreciation_eliminated_via_reversal,
|
||||||
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s
|
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s
|
||||||
and a.disposal_date <= %(to_date)s and gle.posting_date <= a.disposal_date then
|
and a.disposal_date <= %(to_date)s and gle.posting_date <= a.disposal_date then
|
||||||
gle.debit
|
gle.debit
|
||||||
@@ -149,15 +185,22 @@ def get_assets(filters):
|
|||||||
aca.parent = a.asset_category and aca.company_name = %(company)s
|
aca.parent = a.asset_category and aca.company_name = %(company)s
|
||||||
join `tabCompany` company on
|
join `tabCompany` company on
|
||||||
company.name = %(company)s
|
company.name = %(company)s
|
||||||
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and gle.debit != 0 and gle.is_cancelled = 0 and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account) {0}
|
where
|
||||||
|
a.docstatus=1
|
||||||
|
and a.company=%(company)s
|
||||||
|
and a.purchase_date <= %(to_date)s
|
||||||
|
and gle.is_cancelled = 0
|
||||||
|
and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account)
|
||||||
|
{condition}
|
||||||
group by a.asset_category
|
group by a.asset_category
|
||||||
union
|
union
|
||||||
SELECT a.asset_category,
|
SELECT a.asset_category,
|
||||||
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and (a.disposal_date < %(from_date)s or a.disposal_date > %(to_date)s) then
|
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date < %(from_date)s then
|
||||||
0
|
0
|
||||||
else
|
else
|
||||||
a.opening_accumulated_depreciation
|
a.opening_accumulated_depreciation
|
||||||
end), 0) as accumulated_depreciation_as_on_from_date,
|
end), 0) as accumulated_depreciation_as_on_from_date,
|
||||||
|
0 as depreciation_eliminated_via_reversal,
|
||||||
ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then
|
ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then
|
||||||
a.opening_accumulated_depreciation
|
a.opening_accumulated_depreciation
|
||||||
else
|
else
|
||||||
@@ -165,51 +208,272 @@ def get_assets(filters):
|
|||||||
end), 0) as depreciation_eliminated_during_the_period,
|
end), 0) as depreciation_eliminated_during_the_period,
|
||||||
0 as depreciation_amount_during_the_period
|
0 as depreciation_amount_during_the_period
|
||||||
from `tabAsset` a
|
from `tabAsset` a
|
||||||
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s {0}
|
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s {condition}
|
||||||
group by a.asset_category) as results
|
group by a.asset_category) as results
|
||||||
group by results.asset_category
|
group by results.asset_category
|
||||||
""".format(condition),
|
""",
|
||||||
{"to_date": filters.to_date, "from_date": filters.from_date, "company": filters.company},
|
{
|
||||||
|
"to_date": filters.to_date,
|
||||||
|
"from_date": filters.from_date,
|
||||||
|
"company": filters.company,
|
||||||
|
},
|
||||||
|
as_dict=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_group_by_asset_data(filters):
|
||||||
|
data = []
|
||||||
|
|
||||||
|
asset_details = get_asset_details_for_grouped_by_category(filters)
|
||||||
|
assets = get_assets_for_grouped_by_asset(filters)
|
||||||
|
|
||||||
|
for asset_detail in asset_details:
|
||||||
|
row = frappe._dict()
|
||||||
|
row.update(asset_detail)
|
||||||
|
|
||||||
|
row.value_as_on_to_date = (
|
||||||
|
flt(row.value_as_on_from_date)
|
||||||
|
+ flt(row.value_of_new_purchase)
|
||||||
|
- flt(row.value_of_sold_asset)
|
||||||
|
- flt(row.value_of_scrapped_asset)
|
||||||
|
- flt(row.value_of_capitalized_asset)
|
||||||
|
)
|
||||||
|
|
||||||
|
row.update(next(asset for asset in assets if asset["asset"] == asset_detail.get("name", "")))
|
||||||
|
|
||||||
|
row.accumulated_depreciation_as_on_to_date = (
|
||||||
|
flt(row.accumulated_depreciation_as_on_from_date)
|
||||||
|
+ flt(row.depreciation_amount_during_the_period)
|
||||||
|
- flt(row.depreciation_eliminated_during_the_period)
|
||||||
|
- flt(row.depreciation_eliminated_via_reversal)
|
||||||
|
)
|
||||||
|
|
||||||
|
row.net_asset_value_as_on_from_date = flt(row.value_as_on_from_date) - flt(
|
||||||
|
row.accumulated_depreciation_as_on_from_date
|
||||||
|
)
|
||||||
|
|
||||||
|
row.net_asset_value_as_on_to_date = flt(row.value_as_on_to_date) - flt(
|
||||||
|
row.accumulated_depreciation_as_on_to_date
|
||||||
|
)
|
||||||
|
|
||||||
|
data.append(row)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def get_asset_details_for_grouped_by_category(filters):
|
||||||
|
condition = ""
|
||||||
|
if filters.get("asset"):
|
||||||
|
condition += " and a.name = %(asset)s"
|
||||||
|
|
||||||
|
# nosemgrep
|
||||||
|
return frappe.db.sql(
|
||||||
|
f"""
|
||||||
|
SELECT a.name,
|
||||||
|
ifnull(sum(case when a.purchase_date < %(from_date)s then
|
||||||
|
case when ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s then
|
||||||
|
a.gross_purchase_amount
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end), 0) as value_as_on_from_date,
|
||||||
|
ifnull(sum(case when a.purchase_date >= %(from_date)s then
|
||||||
|
a.gross_purchase_amount
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end), 0) as value_of_new_purchase,
|
||||||
|
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
|
||||||
|
and a.disposal_date >= %(from_date)s
|
||||||
|
and a.disposal_date <= %(to_date)s then
|
||||||
|
case when a.status = "Sold" then
|
||||||
|
a.gross_purchase_amount
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end), 0) as value_of_sold_asset,
|
||||||
|
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
|
||||||
|
and a.disposal_date >= %(from_date)s
|
||||||
|
and a.disposal_date <= %(to_date)s then
|
||||||
|
case when a.status = "Scrapped" then
|
||||||
|
a.gross_purchase_amount
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end), 0) as value_of_scrapped_asset,
|
||||||
|
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
|
||||||
|
and a.disposal_date >= %(from_date)s
|
||||||
|
and a.disposal_date <= %(to_date)s then
|
||||||
|
case when a.status = "Capitalized" then
|
||||||
|
a.gross_purchase_amount
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end), 0) as value_of_capitalized_asset
|
||||||
|
from `tabAsset` a
|
||||||
|
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s {condition}
|
||||||
|
and not exists(
|
||||||
|
select 1 from `tabAsset Capitalization Asset Item` acai join `tabAsset Capitalization` ac on acai.parent=ac.name
|
||||||
|
where acai.asset = a.name
|
||||||
|
and ac.posting_date < %(from_date)s
|
||||||
|
and ac.docstatus=1
|
||||||
|
)
|
||||||
|
group by a.name
|
||||||
|
""",
|
||||||
|
{
|
||||||
|
"to_date": filters.to_date,
|
||||||
|
"from_date": filters.from_date,
|
||||||
|
"company": filters.company,
|
||||||
|
"asset": filters.get("asset"),
|
||||||
|
},
|
||||||
|
as_dict=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_assets_for_grouped_by_asset(filters):
|
||||||
|
condition = ""
|
||||||
|
if filters.get("asset"):
|
||||||
|
condition = f" and a.name = '{filters.get('asset')}'"
|
||||||
|
|
||||||
|
# nosemgrep
|
||||||
|
return frappe.db.sql(
|
||||||
|
f"""
|
||||||
|
SELECT results.name as asset,
|
||||||
|
sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
|
||||||
|
sum(results.depreciation_eliminated_via_reversal) as depreciation_eliminated_via_reversal,
|
||||||
|
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
|
||||||
|
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
|
||||||
|
from (SELECT a.name as name,
|
||||||
|
ifnull(sum(case when gle.posting_date < %(from_date)s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
|
||||||
|
gle.debit
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end), 0) as accumulated_depreciation_as_on_from_date,
|
||||||
|
ifnull(sum(case when gle.posting_date <= %(to_date)s and ifnull(a.disposal_date, 0) = 0 then
|
||||||
|
gle.credit
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end), 0) as depreciation_eliminated_via_reversal,
|
||||||
|
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s
|
||||||
|
and a.disposal_date <= %(to_date)s and gle.posting_date <= a.disposal_date then
|
||||||
|
gle.debit
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end), 0) as depreciation_eliminated_during_the_period,
|
||||||
|
ifnull(sum(case when gle.posting_date >= %(from_date)s and gle.posting_date <= %(to_date)s
|
||||||
|
and (ifnull(a.disposal_date, 0) = 0 or gle.posting_date <= a.disposal_date) then
|
||||||
|
gle.debit
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end), 0) as depreciation_amount_during_the_period
|
||||||
|
from `tabGL Entry` gle
|
||||||
|
join `tabAsset` a on
|
||||||
|
gle.against_voucher = a.name
|
||||||
|
join `tabAsset Category Account` aca on
|
||||||
|
aca.parent = a.asset_category and aca.company_name = %(company)s
|
||||||
|
join `tabCompany` company on
|
||||||
|
company.name = %(company)s
|
||||||
|
where
|
||||||
|
a.docstatus=1
|
||||||
|
and a.company=%(company)s
|
||||||
|
and a.purchase_date <= %(to_date)s
|
||||||
|
and gle.is_cancelled = 0
|
||||||
|
and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account)
|
||||||
|
{condition}
|
||||||
|
group by a.name
|
||||||
|
union
|
||||||
|
SELECT a.name as name,
|
||||||
|
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date < %(from_date)s then
|
||||||
|
0
|
||||||
|
else
|
||||||
|
a.opening_accumulated_depreciation
|
||||||
|
end), 0) as accumulated_depreciation_as_on_from_date,
|
||||||
|
0 as depreciation_as_on_from_date_credit,
|
||||||
|
ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then
|
||||||
|
a.opening_accumulated_depreciation
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end), 0) as depreciation_eliminated_during_the_period,
|
||||||
|
0 as depreciation_amount_during_the_period
|
||||||
|
from `tabAsset` a
|
||||||
|
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s {condition}
|
||||||
|
group by a.name) as results
|
||||||
|
group by results.name
|
||||||
|
""",
|
||||||
|
{
|
||||||
|
"to_date": filters.to_date,
|
||||||
|
"from_date": filters.from_date,
|
||||||
|
"company": filters.company,
|
||||||
|
},
|
||||||
as_dict=1,
|
as_dict=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_columns(filters):
|
def get_columns(filters):
|
||||||
return [
|
columns = []
|
||||||
|
|
||||||
|
if filters.get("group_by") == "Asset Category":
|
||||||
|
columns.append(
|
||||||
|
{
|
||||||
|
"label": _("Asset Category"),
|
||||||
|
"fieldname": "asset_category",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Asset Category",
|
||||||
|
"width": 120,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
elif filters.get("group_by") == "Asset":
|
||||||
|
columns.append(
|
||||||
|
{
|
||||||
|
"label": _("Asset"),
|
||||||
|
"fieldname": "asset",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Asset",
|
||||||
|
"width": 120,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
columns += [
|
||||||
{
|
{
|
||||||
"label": _("Asset Category"),
|
"label": _("Value as on") + " " + formatdate(filters.day_before_from_date),
|
||||||
"fieldname": "asset_category",
|
"fieldname": "value_as_on_from_date",
|
||||||
"fieldtype": "Link",
|
|
||||||
"options": "Asset Category",
|
|
||||||
"width": 120,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": _("Cost as on") + " " + formatdate(filters.day_before_from_date),
|
|
||||||
"fieldname": "cost_as_on_from_date",
|
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"width": 140,
|
"width": 140,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Cost of New Purchase"),
|
"label": _("Value of New Purchase"),
|
||||||
"fieldname": "cost_of_new_purchase",
|
"fieldname": "value_of_new_purchase",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"width": 140,
|
"width": 140,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Cost of Sold Asset"),
|
"label": _("Value of Sold Asset"),
|
||||||
"fieldname": "cost_of_sold_asset",
|
"fieldname": "value_of_sold_asset",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"width": 140,
|
"width": 140,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Cost of Scrapped Asset"),
|
"label": _("Value of Scrapped Asset"),
|
||||||
"fieldname": "cost_of_scrapped_asset",
|
"fieldname": "value_of_scrapped_asset",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"width": 140,
|
"width": 140,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Cost as on") + " " + formatdate(filters.to_date),
|
"label": _("Value of New Capitalized Asset"),
|
||||||
"fieldname": "cost_as_on_to_date",
|
"fieldname": "value_of_capitalized_asset",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Value as on") + " " + formatdate(filters.to_date),
|
||||||
|
"fieldname": "value_as_on_to_date",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"width": 140,
|
"width": 140,
|
||||||
},
|
},
|
||||||
@@ -237,6 +501,12 @@ def get_columns(filters):
|
|||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"width": 270,
|
"width": 270,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": _("Depreciation eliminated via reversal"),
|
||||||
|
"fieldname": "depreciation_eliminated_via_reversal",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 270,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": _("Net Asset value as on") + " " + formatdate(filters.day_before_from_date),
|
"label": _("Net Asset value as on") + " " + formatdate(filters.day_before_from_date),
|
||||||
"fieldname": "net_asset_value_as_on_from_date",
|
"fieldname": "net_asset_value_as_on_from_date",
|
||||||
@@ -250,3 +520,5 @@ def get_columns(filters):
|
|||||||
"width": 200,
|
"width": 200,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
return columns
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ frappe.query_reports["General Ledger"] = {
|
|||||||
fieldtype: "Autocomplete",
|
fieldtype: "Autocomplete",
|
||||||
options: Object.keys(frappe.boot.party_account_types),
|
options: Object.keys(frappe.boot.party_account_types),
|
||||||
on_change: function () {
|
on_change: function () {
|
||||||
frappe.query_report.set_filter_value("party", "");
|
frappe.query_report.set_filter_value("party", []);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -468,9 +468,6 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map):
|
|||||||
data[key][rev_dr_or_cr] = 0
|
data[key][rev_dr_or_cr] = 0
|
||||||
data[key][rev_dr_or_cr + "_in_account_currency"] = 0
|
data[key][rev_dr_or_cr + "_in_account_currency"] = 0
|
||||||
|
|
||||||
if data[key].against_voucher and gle.against_voucher:
|
|
||||||
data[key].against_voucher += ", " + gle.against_voucher
|
|
||||||
|
|
||||||
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
|
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
|
||||||
show_opening_entries = filters.get("show_opening_entries")
|
show_opening_entries = filters.get("show_opening_entries")
|
||||||
|
|
||||||
@@ -633,14 +630,6 @@ def get_columns(filters):
|
|||||||
|
|
||||||
columns.extend(
|
columns.extend(
|
||||||
[
|
[
|
||||||
{"label": _("Against Voucher Type"), "fieldname": "against_voucher_type", "width": 100},
|
|
||||||
{
|
|
||||||
"label": _("Against Voucher"),
|
|
||||||
"fieldname": "against_voucher",
|
|
||||||
"fieldtype": "Dynamic Link",
|
|
||||||
"options": "against_voucher_type",
|
|
||||||
"width": 100,
|
|
||||||
},
|
|
||||||
{"label": _("Supplier Invoice No"), "fieldname": "bill_no", "fieldtype": "Data", "width": 100},
|
{"label": _("Supplier Invoice No"), "fieldname": "bill_no", "fieldtype": "Data", "width": 100},
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import erpnext
|
|||||||
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import (
|
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import (
|
||||||
add_sub_total_row,
|
add_sub_total_row,
|
||||||
add_total_row,
|
add_total_row,
|
||||||
apply_group_by_conditions,
|
apply_order_by_conditions,
|
||||||
get_grand_total,
|
get_grand_total,
|
||||||
get_group_by_and_display_fields,
|
get_group_by_and_display_fields,
|
||||||
get_tax_accounts,
|
get_tax_accounts,
|
||||||
@@ -305,12 +305,6 @@ def apply_conditions(query, pi, pii, filters):
|
|||||||
if filters.get("item_group"):
|
if filters.get("item_group"):
|
||||||
query = query.where(pii.item_group == filters.get("item_group"))
|
query = query.where(pii.item_group == filters.get("item_group"))
|
||||||
|
|
||||||
if not filters.get("group_by"):
|
|
||||||
query = query.orderby(pi.posting_date, order=Order.desc)
|
|
||||||
query = query.orderby(pii.item_group, order=Order.desc)
|
|
||||||
else:
|
|
||||||
query = apply_group_by_conditions(query, pi, pii, filters)
|
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
|
||||||
@@ -372,7 +366,17 @@ def get_items(filters, additional_table_columns):
|
|||||||
|
|
||||||
query = apply_conditions(query, pi, pii, filters)
|
query = apply_conditions(query, pi, pii, filters)
|
||||||
|
|
||||||
return query.run(as_dict=True)
|
from frappe.desk.reportview import build_match_conditions
|
||||||
|
|
||||||
|
query, params = query.walk()
|
||||||
|
match_conditions = build_match_conditions("Sales Invoice")
|
||||||
|
|
||||||
|
if match_conditions:
|
||||||
|
query += " and " + match_conditions
|
||||||
|
|
||||||
|
query = apply_order_by_conditions(query, pi, pii, filters)
|
||||||
|
|
||||||
|
return frappe.db.sql(query, params, as_dict=True)
|
||||||
|
|
||||||
|
|
||||||
def get_aii_accounts():
|
def get_aii_accounts():
|
||||||
|
|||||||
@@ -384,27 +384,24 @@ def apply_conditions(query, si, sii, filters, additional_conditions=None):
|
|||||||
| (si.unrealized_profit_loss_account == filters.get("income_account"))
|
| (si.unrealized_profit_loss_account == filters.get("income_account"))
|
||||||
)
|
)
|
||||||
|
|
||||||
if not filters.get("group_by"):
|
|
||||||
query = query.orderby(si.posting_date, order=Order.desc)
|
|
||||||
query = query.orderby(sii.item_group, order=Order.desc)
|
|
||||||
else:
|
|
||||||
query = apply_group_by_conditions(query, si, sii, filters)
|
|
||||||
|
|
||||||
for key, value in (additional_conditions or {}).items():
|
for key, value in (additional_conditions or {}).items():
|
||||||
query = query.where(si[key] == value)
|
query = query.where(si[key] == value)
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
|
||||||
def apply_group_by_conditions(query, si, ii, filters):
|
def apply_order_by_conditions(query, si, ii, filters):
|
||||||
if filters.get("group_by") == "Invoice":
|
if not filters.get("group_by"):
|
||||||
query = query.orderby(ii.parent, order=Order.desc)
|
query += f" order by {si.posting_date} desc, {ii.item_group} desc"
|
||||||
|
elif filters.get("group_by") == "Invoice":
|
||||||
|
query += f" order by {ii.parent} desc"
|
||||||
elif filters.get("group_by") == "Item":
|
elif filters.get("group_by") == "Item":
|
||||||
query = query.orderby(ii.item_code)
|
query += f" order by {ii.item_code}"
|
||||||
elif filters.get("group_by") == "Item Group":
|
elif filters.get("group_by") == "Item Group":
|
||||||
query = query.orderby(ii.item_group)
|
query += f" order by {ii.item_group}"
|
||||||
elif filters.get("group_by") in ("Customer", "Customer Group", "Territory", "Supplier"):
|
elif filters.get("group_by") in ("Customer", "Customer Group", "Territory", "Supplier"):
|
||||||
query = query.orderby(si[frappe.scrub(filters.get("group_by"))])
|
filter_field = frappe.scrub(filters.get("group_by"))
|
||||||
|
query += f" order by {filter_field} desc"
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@@ -479,7 +476,17 @@ def get_items(filters, additional_query_columns, additional_conditions=None):
|
|||||||
|
|
||||||
query = apply_conditions(query, si, sii, filters, additional_conditions)
|
query = apply_conditions(query, si, sii, filters, additional_conditions)
|
||||||
|
|
||||||
return query.run(as_dict=True)
|
from frappe.desk.reportview import build_match_conditions
|
||||||
|
|
||||||
|
query, params = query.walk()
|
||||||
|
match_conditions = build_match_conditions("Sales Invoice")
|
||||||
|
|
||||||
|
if match_conditions:
|
||||||
|
query += " and " + match_conditions
|
||||||
|
|
||||||
|
query = apply_order_by_conditions(query, si, sii, filters)
|
||||||
|
|
||||||
|
return frappe.db.sql(query, params, as_dict=True)
|
||||||
|
|
||||||
|
|
||||||
def get_delivery_notes_against_sales_order(item_list):
|
def get_delivery_notes_against_sales_order(item_list):
|
||||||
|
|||||||
@@ -397,7 +397,6 @@ def get_invoices(filters, additional_query_columns):
|
|||||||
pi.mode_of_payment,
|
pi.mode_of_payment,
|
||||||
)
|
)
|
||||||
.where(pi.docstatus == 1)
|
.where(pi.docstatus == 1)
|
||||||
.orderby(pi.posting_date, pi.name, order=Order.desc)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if additional_query_columns:
|
if additional_query_columns:
|
||||||
@@ -413,8 +412,17 @@ def get_invoices(filters, additional_query_columns):
|
|||||||
filters, query, doctype="Purchase Invoice", child_doctype="Purchase Invoice Item"
|
filters, query, doctype="Purchase Invoice", child_doctype="Purchase Invoice Item"
|
||||||
)
|
)
|
||||||
|
|
||||||
invoices = query.run(as_dict=True)
|
from frappe.desk.reportview import build_match_conditions
|
||||||
return invoices
|
|
||||||
|
query, params = query.walk()
|
||||||
|
match_conditions = build_match_conditions("Purchase Invoice")
|
||||||
|
|
||||||
|
if match_conditions:
|
||||||
|
query += " and " + match_conditions
|
||||||
|
|
||||||
|
query += " order by posting_date desc, name desc"
|
||||||
|
|
||||||
|
return frappe.db.sql(query, params, as_dict=True)
|
||||||
|
|
||||||
|
|
||||||
def get_conditions(filters, query, doctype):
|
def get_conditions(filters, query, doctype):
|
||||||
|
|||||||
@@ -438,7 +438,6 @@ def get_invoices(filters, additional_query_columns):
|
|||||||
si.company,
|
si.company,
|
||||||
)
|
)
|
||||||
.where(si.docstatus == 1)
|
.where(si.docstatus == 1)
|
||||||
.orderby(si.posting_date, si.name, order=Order.desc)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if additional_query_columns:
|
if additional_query_columns:
|
||||||
@@ -453,8 +452,17 @@ def get_invoices(filters, additional_query_columns):
|
|||||||
filters, query, doctype="Sales Invoice", child_doctype="Sales Invoice Item"
|
filters, query, doctype="Sales Invoice", child_doctype="Sales Invoice Item"
|
||||||
)
|
)
|
||||||
|
|
||||||
invoices = query.run(as_dict=True)
|
from frappe.desk.reportview import build_match_conditions
|
||||||
return invoices
|
|
||||||
|
query, params = query.walk()
|
||||||
|
match_conditions = build_match_conditions("Sales Invoice")
|
||||||
|
|
||||||
|
if match_conditions:
|
||||||
|
query += " and " + match_conditions
|
||||||
|
|
||||||
|
query += " order by posting_date desc, name desc"
|
||||||
|
|
||||||
|
return frappe.db.sql(query, params, as_dict=True)
|
||||||
|
|
||||||
|
|
||||||
def get_conditions(filters, query, doctype):
|
def get_conditions(filters, query, doctype):
|
||||||
|
|||||||
@@ -1788,14 +1788,17 @@ def update_voucher_outstanding(voucher_type, voucher_no, account, party_type, pa
|
|||||||
):
|
):
|
||||||
outstanding = voucher_outstanding[0]
|
outstanding = voucher_outstanding[0]
|
||||||
ref_doc = frappe.get_doc(voucher_type, voucher_no)
|
ref_doc = frappe.get_doc(voucher_type, voucher_no)
|
||||||
|
outstanding_amount = flt(
|
||||||
|
outstanding["outstanding_in_account_currency"], ref_doc.precision("outstanding_amount")
|
||||||
|
)
|
||||||
|
|
||||||
# Didn't use db_set for optimisation purpose
|
# Didn't use db_set for optimisation purpose
|
||||||
ref_doc.outstanding_amount = outstanding["outstanding_in_account_currency"] or 0.0
|
ref_doc.outstanding_amount = outstanding_amount
|
||||||
frappe.db.set_value(
|
frappe.db.set_value(
|
||||||
voucher_type,
|
voucher_type,
|
||||||
voucher_no,
|
voucher_no,
|
||||||
"outstanding_amount",
|
"outstanding_amount",
|
||||||
outstanding["outstanding_in_account_currency"] or 0.0,
|
outstanding_amount,
|
||||||
)
|
)
|
||||||
|
|
||||||
ref_doc.set_status(update=True)
|
ref_doc.set_status(update=True)
|
||||||
|
|||||||
@@ -153,6 +153,48 @@ class AccountsController(TransactionBase):
|
|||||||
raise_exception=1,
|
raise_exception=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def validate_against_voucher_outstanding(self):
|
||||||
|
from frappe.model.meta import get_meta
|
||||||
|
|
||||||
|
if not get_meta(self.doctype).has_field("outstanding_amount"):
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.get("is_return") and self.return_against and not self.get("is_pos"):
|
||||||
|
against_voucher_outstanding = frappe.get_value(
|
||||||
|
self.doctype, self.return_against, "outstanding_amount"
|
||||||
|
)
|
||||||
|
document_type = "Credit Note" if self.doctype == "Sales Invoice" else "Debit Note"
|
||||||
|
|
||||||
|
msg = ""
|
||||||
|
if self.get("update_outstanding_for_self"):
|
||||||
|
msg = (
|
||||||
|
"We can see {0} is made against {1}. If you want {1}'s outstanding to be updated, "
|
||||||
|
"uncheck '{2}' checkbox. <br><br>Or"
|
||||||
|
).format(
|
||||||
|
frappe.bold(document_type),
|
||||||
|
get_link_to_form(self.doctype, self.get("return_against")),
|
||||||
|
frappe.bold(_("Update Outstanding for Self")),
|
||||||
|
)
|
||||||
|
|
||||||
|
elif not self.update_outstanding_for_self and (
|
||||||
|
abs(flt(self.rounded_total) or flt(self.grand_total)) > flt(against_voucher_outstanding)
|
||||||
|
):
|
||||||
|
self.update_outstanding_for_self = 1
|
||||||
|
msg = (
|
||||||
|
"The outstanding amount {} in {} is lesser than {}. Updating the outstanding to this invoice. <br><br>And"
|
||||||
|
).format(
|
||||||
|
against_voucher_outstanding,
|
||||||
|
get_link_to_form(self.doctype, self.get("return_against")),
|
||||||
|
flt(abs(self.outstanding_amount)),
|
||||||
|
)
|
||||||
|
|
||||||
|
if msg:
|
||||||
|
msg += " you can use {} tool to reconcile against {} later.".format(
|
||||||
|
get_link_to_form("Payment Reconciliation", "Payment Reconciliation"),
|
||||||
|
get_link_to_form(self.doctype, self.get("return_against")),
|
||||||
|
)
|
||||||
|
frappe.msgprint(_(msg))
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if not self.get("is_return") and not self.get("is_debit_note"):
|
if not self.get("is_return") and not self.get("is_debit_note"):
|
||||||
self.validate_qty_is_not_zero()
|
self.validate_qty_is_not_zero()
|
||||||
@@ -178,6 +220,7 @@ class AccountsController(TransactionBase):
|
|||||||
self.disable_tax_included_prices_for_internal_transfer()
|
self.disable_tax_included_prices_for_internal_transfer()
|
||||||
self.set_incoming_rate()
|
self.set_incoming_rate()
|
||||||
self.init_internal_values()
|
self.init_internal_values()
|
||||||
|
self.validate_against_voucher_outstanding()
|
||||||
|
|
||||||
if self.meta.get_field("currency"):
|
if self.meta.get_field("currency"):
|
||||||
self.calculate_taxes_and_totals()
|
self.calculate_taxes_and_totals()
|
||||||
@@ -209,20 +252,6 @@ class AccountsController(TransactionBase):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.get("is_return") and self.get("return_against") and not self.get("is_pos"):
|
|
||||||
if self.get("update_outstanding_for_self"):
|
|
||||||
document_type = "Credit Note" if self.doctype == "Sales Invoice" else "Debit Note"
|
|
||||||
frappe.msgprint(
|
|
||||||
_(
|
|
||||||
"We can see {0} is made against {1}. If you want {1}'s outstanding to be updated, uncheck '{2}' checkbox. <br><br> Or you can use {3} tool to reconcile against {1} later."
|
|
||||||
).format(
|
|
||||||
frappe.bold(document_type),
|
|
||||||
get_link_to_form(self.doctype, self.get("return_against")),
|
|
||||||
frappe.bold("Update Outstanding for Self"),
|
|
||||||
get_link_to_form("Payment Reconciliation", "Payment Reconciliation"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
pos_check_field = "is_pos" if self.doctype == "Sales Invoice" else "is_paid"
|
pos_check_field = "is_pos" if self.doctype == "Sales Invoice" else "is_paid"
|
||||||
if cint(self.allocate_advances_automatically) and not cint(self.get(pos_check_field)):
|
if cint(self.allocate_advances_automatically) and not cint(self.get(pos_check_field)):
|
||||||
self.set_advances()
|
self.set_advances()
|
||||||
@@ -2100,7 +2129,9 @@ class AccountsController(TransactionBase):
|
|||||||
and automatically_fetch_payment_terms
|
and automatically_fetch_payment_terms
|
||||||
and self.linked_order_has_payment_terms(po_or_so, fieldname, doctype)
|
and self.linked_order_has_payment_terms(po_or_so, fieldname, doctype)
|
||||||
):
|
):
|
||||||
self.fetch_payment_terms_from_order(po_or_so, doctype)
|
self.fetch_payment_terms_from_order(
|
||||||
|
po_or_so, doctype, grand_total, base_grand_total, automatically_fetch_payment_terms
|
||||||
|
)
|
||||||
if self.get("payment_terms_template"):
|
if self.get("payment_terms_template"):
|
||||||
self.ignore_default_payment_terms_template = 1
|
self.ignore_default_payment_terms_template = 1
|
||||||
elif self.get("payment_terms_template"):
|
elif self.get("payment_terms_template"):
|
||||||
@@ -2141,7 +2172,9 @@ class AccountsController(TransactionBase):
|
|||||||
d.payment_amount * self.get("conversion_rate"), d.precision("base_payment_amount")
|
d.payment_amount * self.get("conversion_rate"), d.precision("base_payment_amount")
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.fetch_payment_terms_from_order(po_or_so, doctype)
|
self.fetch_payment_terms_from_order(
|
||||||
|
po_or_so, doctype, grand_total, base_grand_total, automatically_fetch_payment_terms
|
||||||
|
)
|
||||||
self.ignore_default_payment_terms_template = 1
|
self.ignore_default_payment_terms_template = 1
|
||||||
|
|
||||||
def get_order_details(self):
|
def get_order_details(self):
|
||||||
@@ -2179,7 +2212,9 @@ class AccountsController(TransactionBase):
|
|||||||
def linked_order_has_payment_schedule(self, po_or_so):
|
def linked_order_has_payment_schedule(self, po_or_so):
|
||||||
return frappe.get_all("Payment Schedule", filters={"parent": po_or_so})
|
return frappe.get_all("Payment Schedule", filters={"parent": po_or_so})
|
||||||
|
|
||||||
def fetch_payment_terms_from_order(self, po_or_so, po_or_so_doctype):
|
def fetch_payment_terms_from_order(
|
||||||
|
self, po_or_so, po_or_so_doctype, grand_total, base_grand_total, automatically_fetch_payment_terms
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Fetch Payment Terms from Purchase/Sales Order on creating a new Purchase/Sales Invoice.
|
Fetch Payment Terms from Purchase/Sales Order on creating a new Purchase/Sales Invoice.
|
||||||
"""
|
"""
|
||||||
@@ -2195,12 +2230,25 @@ class AccountsController(TransactionBase):
|
|||||||
"invoice_portion": schedule.invoice_portion,
|
"invoice_portion": schedule.invoice_portion,
|
||||||
"mode_of_payment": schedule.mode_of_payment,
|
"mode_of_payment": schedule.mode_of_payment,
|
||||||
"description": schedule.description,
|
"description": schedule.description,
|
||||||
"payment_amount": schedule.payment_amount,
|
|
||||||
"base_payment_amount": schedule.base_payment_amount,
|
|
||||||
"outstanding": schedule.outstanding,
|
|
||||||
"paid_amount": schedule.paid_amount,
|
"paid_amount": schedule.paid_amount,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if automatically_fetch_payment_terms:
|
||||||
|
payment_schedule["payment_amount"] = flt(
|
||||||
|
grand_total * flt(payment_schedule["invoice_portion"]) / 100,
|
||||||
|
schedule.precision("payment_amount"),
|
||||||
|
)
|
||||||
|
payment_schedule["base_payment_amount"] = flt(
|
||||||
|
base_grand_total * flt(payment_schedule["invoice_portion"]) / 100,
|
||||||
|
schedule.precision("base_payment_amount"),
|
||||||
|
)
|
||||||
|
payment_schedule["outstanding"] = payment_schedule["payment_amount"]
|
||||||
|
else:
|
||||||
|
payment_schedule["base_payment_amount"] = flt(
|
||||||
|
schedule.base_payment_amount * self.get("conversion_rate"),
|
||||||
|
schedule.precision("base_payment_amount"),
|
||||||
|
)
|
||||||
|
|
||||||
if schedule.discount_type == "Percentage":
|
if schedule.discount_type == "Percentage":
|
||||||
payment_schedule["discount_type"] = schedule.discount_type
|
payment_schedule["discount_type"] = schedule.discount_type
|
||||||
payment_schedule["discount"] = schedule.discount
|
payment_schedule["discount"] = schedule.discount
|
||||||
|
|||||||
@@ -373,9 +373,7 @@ class calculate_taxes_and_totals:
|
|||||||
self._calculate()
|
self._calculate()
|
||||||
|
|
||||||
def calculate_taxes(self):
|
def calculate_taxes(self):
|
||||||
rounding_adjustment_computed = self.doc.get("is_consolidated") and self.doc.get("rounding_adjustment")
|
self.grand_total_diff = 0
|
||||||
if not rounding_adjustment_computed:
|
|
||||||
self.doc.rounding_adjustment = 0
|
|
||||||
|
|
||||||
# maintain actual tax rate based on idx
|
# maintain actual tax rate based on idx
|
||||||
actual_tax_dict = dict(
|
actual_tax_dict = dict(
|
||||||
@@ -440,9 +438,8 @@ class calculate_taxes_and_totals:
|
|||||||
and self.discount_amount_applied
|
and self.discount_amount_applied
|
||||||
and self.doc.discount_amount
|
and self.doc.discount_amount
|
||||||
and self.doc.apply_discount_on == "Grand Total"
|
and self.doc.apply_discount_on == "Grand Total"
|
||||||
and not rounding_adjustment_computed
|
|
||||||
):
|
):
|
||||||
self.doc.rounding_adjustment = flt(
|
self.grand_total_diff = flt(
|
||||||
self.doc.grand_total - flt(self.doc.discount_amount) - tax.total,
|
self.doc.grand_total - flt(self.doc.discount_amount) - tax.total,
|
||||||
self.doc.precision("rounding_adjustment"),
|
self.doc.precision("rounding_adjustment"),
|
||||||
)
|
)
|
||||||
@@ -528,11 +525,11 @@ class calculate_taxes_and_totals:
|
|||||||
return self.adjust_grand_total_for_inclusive_tax()
|
return self.adjust_grand_total_for_inclusive_tax()
|
||||||
|
|
||||||
def adjust_grand_total_for_inclusive_tax(self):
|
def adjust_grand_total_for_inclusive_tax(self):
|
||||||
# if fully inclusive taxes and diff
|
# if any inclusive taxes and diff
|
||||||
if self.doc.get("taxes") and any(cint(t.included_in_print_rate) for t in self.doc.get("taxes")):
|
if self.doc.get("taxes") and any(cint(t.included_in_print_rate) for t in self.doc.get("taxes")):
|
||||||
last_tax = self.doc.get("taxes")[-1]
|
last_tax = self.doc.get("taxes")[-1]
|
||||||
non_inclusive_tax_amount = sum(
|
non_inclusive_tax_amount = sum(
|
||||||
flt(d.tax_amount_after_discount_amount)
|
self.get_tax_amount_if_for_valuation_or_deduction(d.tax_amount_after_discount_amount, d)
|
||||||
for d in self.doc.get("taxes")
|
for d in self.doc.get("taxes")
|
||||||
if not d.included_in_print_rate
|
if not d.included_in_print_rate
|
||||||
)
|
)
|
||||||
@@ -549,27 +546,23 @@ class calculate_taxes_and_totals:
|
|||||||
diff = flt(diff, self.doc.precision("rounding_adjustment"))
|
diff = flt(diff, self.doc.precision("rounding_adjustment"))
|
||||||
|
|
||||||
if diff and abs(diff) <= (5.0 / 10 ** last_tax.precision("tax_amount")):
|
if diff and abs(diff) <= (5.0 / 10 ** last_tax.precision("tax_amount")):
|
||||||
self.doc.grand_total_diff = diff
|
self.grand_total_diff = diff
|
||||||
else:
|
|
||||||
self.doc.grand_total_diff = 0
|
|
||||||
|
|
||||||
def calculate_totals(self):
|
def calculate_totals(self):
|
||||||
if self.doc.get("taxes"):
|
if self.doc.get("taxes"):
|
||||||
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(
|
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + self.grand_total_diff
|
||||||
self.doc.get("grand_total_diff")
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
self.doc.grand_total = flt(self.doc.net_total)
|
self.doc.grand_total = flt(self.doc.net_total)
|
||||||
|
|
||||||
if self.doc.get("taxes"):
|
if self.doc.get("taxes"):
|
||||||
self.doc.total_taxes_and_charges = flt(
|
self.doc.total_taxes_and_charges = flt(
|
||||||
self.doc.grand_total - self.doc.net_total - flt(self.doc.get("grand_total_diff")),
|
self.doc.grand_total - self.doc.net_total - self.grand_total_diff,
|
||||||
self.doc.precision("total_taxes_and_charges"),
|
self.doc.precision("total_taxes_and_charges"),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.doc.total_taxes_and_charges = 0.0
|
self.doc.total_taxes_and_charges = 0.0
|
||||||
|
|
||||||
self._set_in_company_currency(self.doc, ["total_taxes_and_charges", "rounding_adjustment"])
|
self._set_in_company_currency(self.doc, ["total_taxes_and_charges"])
|
||||||
|
|
||||||
if self.doc.doctype in [
|
if self.doc.doctype in [
|
||||||
"Quotation",
|
"Quotation",
|
||||||
@@ -619,7 +612,9 @@ class calculate_taxes_and_totals:
|
|||||||
|
|
||||||
if self.doc.meta.get_field("rounded_total"):
|
if self.doc.meta.get_field("rounded_total"):
|
||||||
if self.doc.is_rounded_total_disabled():
|
if self.doc.is_rounded_total_disabled():
|
||||||
self.doc.rounded_total = self.doc.base_rounded_total = 0
|
self.doc.rounded_total = 0
|
||||||
|
self.doc.base_rounded_total = 0
|
||||||
|
self.doc.rounding_adjustment = 0
|
||||||
return
|
return
|
||||||
|
|
||||||
self.doc.rounded_total = round_based_on_smallest_currency_fraction(
|
self.doc.rounded_total = round_based_on_smallest_currency_fraction(
|
||||||
@@ -663,33 +658,29 @@ class calculate_taxes_and_totals:
|
|||||||
return
|
return
|
||||||
|
|
||||||
total_for_discount_amount = self.get_total_for_discount_amount()
|
total_for_discount_amount = self.get_total_for_discount_amount()
|
||||||
taxes = self.doc.get("taxes")
|
|
||||||
net_total = 0
|
net_total = 0
|
||||||
|
expected_net_total = 0
|
||||||
|
|
||||||
if total_for_discount_amount:
|
if total_for_discount_amount:
|
||||||
# calculate item amount after Discount Amount
|
# calculate item amount after Discount Amount
|
||||||
for i, item in enumerate(self._items):
|
for item in self._items:
|
||||||
distributed_amount = (
|
distributed_amount = (
|
||||||
flt(self.doc.discount_amount) * item.net_amount / total_for_discount_amount
|
flt(self.doc.discount_amount) * item.net_amount / total_for_discount_amount
|
||||||
)
|
)
|
||||||
|
|
||||||
item.net_amount = flt(item.net_amount - distributed_amount, item.precision("net_amount"))
|
adjusted_net_amount = item.net_amount - distributed_amount
|
||||||
|
expected_net_total += adjusted_net_amount
|
||||||
|
item.net_amount = flt(adjusted_net_amount, item.precision("net_amount"))
|
||||||
net_total += item.net_amount
|
net_total += item.net_amount
|
||||||
|
|
||||||
# discount amount rounding loss adjustment if no taxes
|
# discount amount rounding adjustment
|
||||||
if (
|
if rounding_difference := flt(
|
||||||
self.doc.apply_discount_on == "Net Total"
|
expected_net_total - net_total, self.doc.precision("net_total")
|
||||||
or not taxes
|
):
|
||||||
or total_for_discount_amount == self.doc.net_total
|
|
||||||
) and i == len(self._items) - 1:
|
|
||||||
discount_amount_loss = flt(
|
|
||||||
self.doc.net_total - net_total - self.doc.discount_amount,
|
|
||||||
self.doc.precision("net_total"),
|
|
||||||
)
|
|
||||||
|
|
||||||
item.net_amount = flt(
|
item.net_amount = flt(
|
||||||
item.net_amount + discount_amount_loss, item.precision("net_amount")
|
item.net_amount + rounding_difference, item.precision("net_amount")
|
||||||
)
|
)
|
||||||
|
net_total += rounding_difference
|
||||||
|
|
||||||
item.net_rate = (
|
item.net_rate = (
|
||||||
flt(item.net_amount / item.qty, item.precision("net_rate")) if item.qty else 0
|
flt(item.net_amount / item.qty, item.precision("net_rate")) if item.qty else 0
|
||||||
@@ -705,20 +696,44 @@ class calculate_taxes_and_totals:
|
|||||||
def get_total_for_discount_amount(self):
|
def get_total_for_discount_amount(self):
|
||||||
if self.doc.apply_discount_on == "Net Total":
|
if self.doc.apply_discount_on == "Net Total":
|
||||||
return self.doc.net_total
|
return self.doc.net_total
|
||||||
else:
|
|
||||||
actual_taxes_dict = {}
|
|
||||||
|
|
||||||
for tax in self.doc.get("taxes"):
|
total_actual_tax = 0
|
||||||
if tax.charge_type in ["Actual", "On Item Quantity"]:
|
actual_taxes_dict = {}
|
||||||
tax_amount = self.get_tax_amount_if_for_valuation_or_deduction(tax.tax_amount, tax)
|
|
||||||
actual_taxes_dict.setdefault(tax.idx, tax_amount)
|
|
||||||
elif tax.row_id in actual_taxes_dict:
|
|
||||||
actual_tax_amount = flt(actual_taxes_dict.get(tax.row_id, 0)) * flt(tax.rate) / 100
|
|
||||||
actual_taxes_dict.setdefault(tax.idx, actual_tax_amount)
|
|
||||||
|
|
||||||
return flt(
|
def update_actual_tax_dict(tax, tax_amount):
|
||||||
self.doc.grand_total - sum(actual_taxes_dict.values()), self.doc.precision("grand_total")
|
nonlocal total_actual_tax
|
||||||
|
|
||||||
|
if tax.get("add_deduct_tax") == "Deduct":
|
||||||
|
tax_amount *= -1
|
||||||
|
|
||||||
|
if tax.get("category") != "Valuation":
|
||||||
|
total_actual_tax += tax_amount
|
||||||
|
|
||||||
|
actual_taxes_dict[int(tax.idx)] = {
|
||||||
|
"tax_amount": tax_amount,
|
||||||
|
"cumulative_tax_amount": total_actual_tax,
|
||||||
|
}
|
||||||
|
|
||||||
|
for tax in self.doc.get("taxes"):
|
||||||
|
if tax.charge_type in ["Actual", "On Item Quantity"]:
|
||||||
|
update_actual_tax_dict(tax, tax.tax_amount)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not tax.row_id:
|
||||||
|
continue
|
||||||
|
|
||||||
|
base_row = actual_taxes_dict.get(int(tax.row_id))
|
||||||
|
if not base_row:
|
||||||
|
continue
|
||||||
|
|
||||||
|
base_tax_amount = (
|
||||||
|
base_row["tax_amount"]
|
||||||
|
if tax.charge_type == "On Previous Row Amount"
|
||||||
|
else base_row["cumulative_tax_amount"]
|
||||||
)
|
)
|
||||||
|
update_actual_tax_dict(tax, base_tax_amount * tax.rate / 100)
|
||||||
|
|
||||||
|
return self.doc.grand_total - total_actual_tax
|
||||||
|
|
||||||
def calculate_total_advance(self):
|
def calculate_total_advance(self):
|
||||||
if not self.doc.docstatus.is_cancelled():
|
if not self.doc.docstatus.is_cancelled():
|
||||||
@@ -780,9 +795,12 @@ class calculate_taxes_and_totals:
|
|||||||
if (
|
if (
|
||||||
self.doc.is_return
|
self.doc.is_return
|
||||||
and self.doc.return_against
|
and self.doc.return_against
|
||||||
|
and not self.doc.update_outstanding_for_self
|
||||||
and not self.doc.get("is_pos")
|
and not self.doc.get("is_pos")
|
||||||
or self.is_internal_invoice()
|
or self.is_internal_invoice()
|
||||||
):
|
):
|
||||||
|
# Do not calculate the outstanding amount for a return invoice if 'update_outstanding_for_self' is not enabled.
|
||||||
|
self.doc.outstanding_amount = 0
|
||||||
return
|
return
|
||||||
|
|
||||||
self.doc.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount"])
|
self.doc.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount"])
|
||||||
|
|||||||
@@ -336,7 +336,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
|
|
||||||
calculate_taxes() {
|
calculate_taxes() {
|
||||||
var me = this;
|
var me = this;
|
||||||
this.frm.doc.rounding_adjustment = 0;
|
this.grand_total_diff = 0;
|
||||||
var actual_tax_dict = {};
|
var actual_tax_dict = {};
|
||||||
|
|
||||||
// maintain actual tax rate based on idx
|
// maintain actual tax rate based on idx
|
||||||
@@ -407,7 +407,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
// adjust Discount Amount loss in last tax iteration
|
// adjust Discount Amount loss in last tax iteration
|
||||||
if ((i == me.frm.doc["taxes"].length - 1) && me.discount_amount_applied
|
if ((i == me.frm.doc["taxes"].length - 1) && me.discount_amount_applied
|
||||||
&& me.frm.doc.apply_discount_on == "Grand Total" && me.frm.doc.discount_amount) {
|
&& me.frm.doc.apply_discount_on == "Grand Total" && me.frm.doc.discount_amount) {
|
||||||
me.frm.doc.rounding_adjustment = flt(me.frm.doc.grand_total -
|
me.grand_total_diff = flt(me.frm.doc.grand_total -
|
||||||
flt(me.frm.doc.discount_amount) - tax.total, precision("rounding_adjustment"));
|
flt(me.frm.doc.discount_amount) - tax.total, precision("rounding_adjustment"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -519,7 +519,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
adjust_grand_total_for_inclusive_tax() {
|
adjust_grand_total_for_inclusive_tax() {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
// if fully inclusive taxes and diff
|
// if any inclusive taxes and diff
|
||||||
if (this.frm.doc["taxes"] && this.frm.doc["taxes"].length) {
|
if (this.frm.doc["taxes"] && this.frm.doc["taxes"].length) {
|
||||||
var any_inclusive_tax = false;
|
var any_inclusive_tax = false;
|
||||||
$.each(this.frm.doc.taxes || [], function(i, d) {
|
$.each(this.frm.doc.taxes || [], function(i, d) {
|
||||||
@@ -530,7 +530,9 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
var non_inclusive_tax_amount = frappe.utils.sum($.map(this.frm.doc.taxes || [],
|
var non_inclusive_tax_amount = frappe.utils.sum($.map(this.frm.doc.taxes || [],
|
||||||
function(d) {
|
function(d) {
|
||||||
if(!d.included_in_print_rate) {
|
if(!d.included_in_print_rate) {
|
||||||
return flt(d.tax_amount_after_discount_amount);
|
let tax_amount = d.category === "Valuation" ? 0 : d.tax_amount_after_discount_amount;
|
||||||
|
if (d.add_deduct_tax === "Deduct") tax_amount *= -1;
|
||||||
|
return tax_amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
@@ -544,9 +546,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
diff = flt(diff, precision("rounding_adjustment"));
|
diff = flt(diff, precision("rounding_adjustment"));
|
||||||
|
|
||||||
if ( diff && Math.abs(diff) <= (5.0 / Math.pow(10, precision("tax_amount", last_tax))) ) {
|
if ( diff && Math.abs(diff) <= (5.0 / Math.pow(10, precision("tax_amount", last_tax))) ) {
|
||||||
me.frm.doc.grand_total_diff = diff;
|
me.grand_total_diff = diff;
|
||||||
} else {
|
|
||||||
me.frm.doc.grand_total_diff = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -557,7 +557,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
var me = this;
|
var me = this;
|
||||||
var tax_count = this.frm.doc["taxes"] ? this.frm.doc["taxes"].length : 0;
|
var tax_count = this.frm.doc["taxes"] ? this.frm.doc["taxes"].length : 0;
|
||||||
this.frm.doc.grand_total = flt(tax_count
|
this.frm.doc.grand_total = flt(tax_count
|
||||||
? this.frm.doc["taxes"][tax_count - 1].total + flt(this.frm.doc.grand_total_diff)
|
? this.frm.doc["taxes"][tax_count - 1].total + this.grand_total_diff
|
||||||
: this.frm.doc.net_total);
|
: this.frm.doc.net_total);
|
||||||
|
|
||||||
if(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice", "POS Invoice"].includes(this.frm.doc.doctype)) {
|
if(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice", "POS Invoice"].includes(this.frm.doc.doctype)) {
|
||||||
@@ -589,9 +589,9 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.frm.doc.total_taxes_and_charges = flt(this.frm.doc.grand_total - this.frm.doc.net_total
|
this.frm.doc.total_taxes_and_charges = flt(this.frm.doc.grand_total - this.frm.doc.net_total
|
||||||
- flt(this.frm.doc.rounding_adjustment), precision("total_taxes_and_charges"));
|
- this.grand_total_diff, precision("total_taxes_and_charges"));
|
||||||
|
|
||||||
this.set_in_company_currency(this.frm.doc, ["total_taxes_and_charges", "rounding_adjustment"]);
|
this.set_in_company_currency(this.frm.doc, ["total_taxes_and_charges"]);
|
||||||
|
|
||||||
// Round grand total as per precision
|
// Round grand total as per precision
|
||||||
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "base_grand_total"]);
|
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "base_grand_total"]);
|
||||||
@@ -611,6 +611,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
if (cint(disable_rounded_total)) {
|
if (cint(disable_rounded_total)) {
|
||||||
this.frm.doc.rounded_total = 0;
|
this.frm.doc.rounded_total = 0;
|
||||||
this.frm.doc.base_rounded_total = 0;
|
this.frm.doc.base_rounded_total = 0;
|
||||||
|
this.frm.doc.rounding_adjustment = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,22 +680,26 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var total_for_discount_amount = this.get_total_for_discount_amount();
|
const total_for_discount_amount = this.get_total_for_discount_amount();
|
||||||
var net_total = 0;
|
let net_total = 0;
|
||||||
|
let expected_net_total = 0;
|
||||||
|
|
||||||
// calculate item amount after Discount Amount
|
// calculate item amount after Discount Amount
|
||||||
if (total_for_discount_amount) {
|
if (total_for_discount_amount) {
|
||||||
$.each(this.frm._items || [], function(i, item) {
|
$.each(this.frm._items || [], function(i, item) {
|
||||||
distributed_amount = flt(me.frm.doc.discount_amount) * item.net_amount / total_for_discount_amount;
|
distributed_amount = flt(me.frm.doc.discount_amount) * item.net_amount / total_for_discount_amount;
|
||||||
item.net_amount = flt(item.net_amount - distributed_amount, precision("net_amount", item));
|
|
||||||
|
const adjusted_net_amount = item.net_amount - distributed_amount;
|
||||||
|
expected_net_total += adjusted_net_amount
|
||||||
|
item.net_amount = flt(adjusted_net_amount, precision("net_amount", item));
|
||||||
net_total += item.net_amount;
|
net_total += item.net_amount;
|
||||||
|
|
||||||
// discount amount rounding loss adjustment if no taxes
|
// discount amount rounding adjustment
|
||||||
if ((!(me.frm.doc.taxes || []).length || total_for_discount_amount==me.frm.doc.net_total || (me.frm.doc.apply_discount_on == "Net Total"))
|
// assignment to rounding_difference is intentional
|
||||||
&& i == (me.frm._items || []).length - 1) {
|
const rounding_difference = flt(expected_net_total - net_total, precision("net_total"));
|
||||||
var discount_amount_loss = flt(me.frm.doc.net_total - net_total
|
if (rounding_difference) {
|
||||||
- me.frm.doc.discount_amount, precision("net_total"));
|
item.net_amount = flt(item.net_amount + rounding_difference, precision("net_amount", item));
|
||||||
item.net_amount = flt(item.net_amount + discount_amount_loss,
|
net_total += rounding_difference;
|
||||||
precision("net_amount", item));
|
|
||||||
}
|
}
|
||||||
item.net_rate = item.qty ? flt(item.net_amount / item.qty, precision("net_rate", item)) : 0;
|
item.net_rate = item.qty ? flt(item.net_amount / item.qty, precision("net_rate", item)) : 0;
|
||||||
me.set_in_company_currency(item, ["net_rate", "net_amount"]);
|
me.set_in_company_currency(item, ["net_rate", "net_amount"]);
|
||||||
@@ -707,29 +712,38 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_total_for_discount_amount() {
|
get_total_for_discount_amount() {
|
||||||
if(this.frm.doc.apply_discount_on == "Net Total") {
|
if(this.frm.doc.apply_discount_on == "Net Total")
|
||||||
return this.frm.doc.net_total;
|
return this.frm.doc.net_total;
|
||||||
} else {
|
|
||||||
var total_actual_tax = 0.0;
|
|
||||||
var actual_taxes_dict = {};
|
|
||||||
|
|
||||||
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
|
let total_actual_tax = 0.0;
|
||||||
if (["Actual", "On Item Quantity"].includes(tax.charge_type)) {
|
let actual_taxes_dict = {};
|
||||||
var tax_amount = (tax.category == "Valuation") ? 0.0 : tax.tax_amount;
|
|
||||||
tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
|
|
||||||
actual_taxes_dict[tax.idx] = tax_amount;
|
|
||||||
} else if (actual_taxes_dict[tax.row_id] !== null) {
|
|
||||||
var actual_tax_amount = flt(actual_taxes_dict[tax.row_id]) * flt(tax.rate) / 100;
|
|
||||||
actual_taxes_dict[tax.idx] = actual_tax_amount;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$.each(actual_taxes_dict, function(key, value) {
|
function update_actual_taxes_dict(tax, tax_amount) {
|
||||||
if (value) total_actual_tax += value;
|
if (tax.add_deduct_tax == "Deduct") tax_amount *= -1;
|
||||||
});
|
if (tax.category != "Valuation") total_actual_tax += tax_amount;
|
||||||
|
|
||||||
return flt(this.frm.doc.grand_total - total_actual_tax, precision("grand_total"));
|
actual_taxes_dict[tax.idx] = {
|
||||||
|
tax_amount: tax_amount,
|
||||||
|
cumulative_total: total_actual_tax
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
|
||||||
|
if (["Actual", "On Item Quantity"].includes(tax.charge_type)) {
|
||||||
|
update_actual_taxes_dict(tax, tax.tax_amount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const base_row = actual_taxes_dict[tax.row_id];
|
||||||
|
if (!base_row) return;
|
||||||
|
|
||||||
|
// if charge type is 'On Previous Row Amount', calculate tax on previous row amount
|
||||||
|
// else (On Previous Row Total) calculate tax on cumulative total
|
||||||
|
const base_tax_amount = tax.charge_type == "On Previous Row Amount" ? base_row["tax_amount"]: base_row["cumulative_total"];
|
||||||
|
update_actual_taxes_dict(tax, base_tax_amount * tax.rate / 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.frm.doc.grand_total - total_actual_tax;
|
||||||
}
|
}
|
||||||
|
|
||||||
calculate_total_advance(update_paid_amount) {
|
calculate_total_advance(update_paid_amount) {
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
let d = locals[cdt][cdn];
|
let d = locals[cdt][cdn];
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
docstatus: 1,
|
docstatus: ["<", 2],
|
||||||
inspection_type: inspection_type,
|
inspection_type: inspection_type,
|
||||||
reference_name: doc.name,
|
reference_name: doc.name,
|
||||||
item_code: d.item_code
|
item_code: d.item_code
|
||||||
|
|||||||
@@ -121,10 +121,10 @@ erpnext.accounts.unreconcile_payment = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let d = new frappe.ui.Dialog({
|
let d = new frappe.ui.Dialog({
|
||||||
title: "UnReconcile Allocations",
|
title: __("UnReconcile Allocations"),
|
||||||
fields: unreconcile_dialog_fields,
|
fields: unreconcile_dialog_fields,
|
||||||
size: "large",
|
size: "large",
|
||||||
primary_action_label: "UnReconcile",
|
primary_action_label: __("UnReconcile"),
|
||||||
primary_action(values) {
|
primary_action(values) {
|
||||||
let selected_allocations = values.allocations.filter((x) => x.__checked);
|
let selected_allocations = values.allocations.filter((x) => x.__checked);
|
||||||
if (selected_allocations.length > 0) {
|
if (selected_allocations.length > 0) {
|
||||||
@@ -138,7 +138,7 @@ erpnext.accounts.unreconcile_payment = {
|
|||||||
);
|
);
|
||||||
d.hide();
|
d.hide();
|
||||||
} else {
|
} else {
|
||||||
frappe.msgprint("No Selection");
|
frappe.msgprint(__("No Selection"));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ frappe.ui.form.on("Customer", {
|
|||||||
|
|
||||||
frm.add_fetch("lead_name", "company_name", "customer_name");
|
frm.add_fetch("lead_name", "company_name", "customer_name");
|
||||||
frm.add_fetch("default_sales_partner", "commission_rate", "default_commission_rate");
|
frm.add_fetch("default_sales_partner", "commission_rate", "default_commission_rate");
|
||||||
frm.set_query("customer_group", { is_group: 0 });
|
|
||||||
frm.set_query("default_price_list", { selling: 1 });
|
frm.set_query("default_price_list", { selling: 1 });
|
||||||
frm.set_query("account", "accounts", function (doc, cdt, cdn) {
|
frm.set_query("account", "accounts", function (doc, cdt, cdn) {
|
||||||
var d = locals[cdt][cdn];
|
var d = locals[cdt][cdn];
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user