Merge branch 'develop' into fix/notification-comply-with-upstream

This commit is contained in:
mergify[bot] 2024-01-30 09:49:57 +00:00 committed by GitHub
commit e9dfb45fca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 1882 additions and 1671 deletions

View File

@ -462,7 +462,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2023-11-20 09:37:47.650347",
"modified": "2024-01-22 12:10:10.151819",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",

View File

@ -93,7 +93,7 @@ class TestPOSInvoice(unittest.TestCase):
inv.save()
self.assertEqual(inv.net_total, 4298.25)
self.assertEqual(inv.net_total, 4298.24)
self.assertEqual(inv.grand_total, 4900.00)
def test_tax_calculation_with_multiple_items(self):

View File

@ -351,7 +351,7 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
inv.load_from_db()
consolidated_invoice = frappe.get_doc("Sales Invoice", inv.consolidated_invoice)
self.assertEqual(consolidated_invoice.status, "Return")
self.assertEqual(consolidated_invoice.rounding_adjustment, -0.001)
self.assertEqual(consolidated_invoice.rounding_adjustment, -0.002)
finally:
frappe.set_user("Administrator")

View File

@ -1995,6 +1995,21 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
self.assertEqual(pi.items[0].cost_center, "_Test Cost Center Buying - _TC")
def test_debit_note_with_account_mismatch(self):
new_creditors = create_account(
parent_account="Accounts Payable - _TC",
account_name="Creditors 2",
company="_Test Company",
account_type="Payable",
)
pi = make_purchase_invoice(qty=1, rate=1000)
dr_note = make_purchase_invoice(
qty=-1, rate=1000, is_return=1, return_against=pi.name, do_not_save=True
)
dr_note.credit_to = new_creditors
self.assertRaises(frappe.ValidationError, dr_note.save)
def test_debit_note_without_item(self):
pi = make_purchase_invoice(item_name="_Test Item", qty=10, do_not_submit=True)
pi.items[0].item_code = ""

View File

@ -323,7 +323,8 @@ class TestSalesInvoice(FrappeTestCase):
si.insert()
# with inclusive tax
self.assertEqual(si.items[0].net_amount, 3947.368421052631)
self.assertEqual(si.items[0].net_amount, 3947.37)
self.assertEqual(si.net_total, si.base_net_total)
self.assertEqual(si.net_total, 3947.37)
self.assertEqual(si.grand_total, 5000)
@ -667,7 +668,7 @@ class TestSalesInvoice(FrappeTestCase):
62.5,
625.0,
50,
499.97600115194473,
499.98,
],
"_Test Item Home Desktop 200": [
190.66,
@ -678,7 +679,7 @@ class TestSalesInvoice(FrappeTestCase):
190.66,
953.3,
150,
749.9968530500239,
750,
],
}
@ -691,20 +692,21 @@ class TestSalesInvoice(FrappeTestCase):
self.assertEqual(d.get(k), expected_values[d.item_code][i])
# check net total
self.assertEqual(si.net_total, 1249.97)
self.assertEqual(si.base_net_total, si.net_total)
self.assertEqual(si.net_total, 1249.98)
self.assertEqual(si.total, 1578.3)
# check tax calculation
expected_values = {
"keys": ["tax_amount", "total"],
"_Test Account Excise Duty - _TC": [140, 1389.97],
"_Test Account Education Cess - _TC": [2.8, 1392.77],
"_Test Account S&H Education Cess - _TC": [1.4, 1394.17],
"_Test Account CST - _TC": [27.88, 1422.05],
"_Test Account VAT - _TC": [156.25, 1578.30],
"_Test Account Customs Duty - _TC": [125, 1703.30],
"_Test Account Shipping Charges - _TC": [100, 1803.30],
"_Test Account Discount - _TC": [-180.33, 1622.97],
"_Test Account Excise Duty - _TC": [140, 1389.98],
"_Test Account Education Cess - _TC": [2.8, 1392.78],
"_Test Account S&H Education Cess - _TC": [1.4, 1394.18],
"_Test Account CST - _TC": [27.88, 1422.06],
"_Test Account VAT - _TC": [156.25, 1578.31],
"_Test Account Customs Duty - _TC": [125, 1703.31],
"_Test Account Shipping Charges - _TC": [100, 1803.31],
"_Test Account Discount - _TC": [-180.33, 1622.98],
}
for d in si.get("taxes"):
@ -740,7 +742,7 @@ class TestSalesInvoice(FrappeTestCase):
"base_rate": 2500,
"base_amount": 25000,
"net_rate": 40,
"net_amount": 399.9808009215558,
"net_amount": 399.98,
"base_net_rate": 2000,
"base_net_amount": 19999,
},
@ -754,7 +756,7 @@ class TestSalesInvoice(FrappeTestCase):
"base_rate": 7500,
"base_amount": 37500,
"net_rate": 118.01,
"net_amount": 590.0531205155963,
"net_amount": 590.05,
"base_net_rate": 5900.5,
"base_net_amount": 29502.5,
},
@ -792,8 +794,13 @@ class TestSalesInvoice(FrappeTestCase):
self.assertEqual(si.base_grand_total, 60795)
self.assertEqual(si.grand_total, 1215.90)
self.assertEqual(si.rounding_adjustment, 0.01)
self.assertEqual(si.base_rounding_adjustment, 0.50)
# no rounding adjustment as the Smallest Currency Fraction Value of USD is 0.01
if frappe.db.get_value("Currency", "USD", "smallest_currency_fraction_value") < 0.01:
self.assertEqual(si.rounding_adjustment, 0.10)
self.assertEqual(si.base_rounding_adjustment, 5.0)
else:
self.assertEqual(si.rounding_adjustment, 0.0)
self.assertEqual(si.base_rounding_adjustment, 0.0)
def test_outstanding(self):
w = self.make()
@ -1543,6 +1550,19 @@ class TestSalesInvoice(FrappeTestCase):
self.assertEqual(frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount"), -1000)
self.assertEqual(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"), 2500)
def test_return_invoice_with_account_mismatch(self):
debtors2 = create_account(
parent_account="Accounts Receivable - _TC",
account_name="Debtors 2",
company="_Test Company",
account_type="Receivable",
)
si = create_sales_invoice(qty=1, rate=1000)
cr_note = create_sales_invoice(
qty=-1, rate=1000, is_return=1, return_against=si.name, debit_to=debtors2, do_not_save=True
)
self.assertRaises(frappe.ValidationError, cr_note.save)
def test_gle_made_when_asset_is_returned(self):
create_asset_data()
asset = create_asset(item_code="Macbook Pro")
@ -2082,7 +2102,7 @@ class TestSalesInvoice(FrappeTestCase):
def test_rounding_adjustment_2(self):
si = create_sales_invoice(rate=400, do_not_save=True)
for rate in [400, 600, 100]:
for rate in [400.25, 600.30, 100.65]:
si.append(
"items",
{
@ -2108,17 +2128,18 @@ class TestSalesInvoice(FrappeTestCase):
)
si.save()
si.submit()
self.assertEqual(si.net_total, 1271.19)
self.assertEqual(si.grand_total, 1500)
self.assertEqual(si.total_taxes_and_charges, 228.82)
self.assertEqual(si.rounding_adjustment, -0.01)
self.assertEqual(si.net_total, si.base_net_total)
self.assertEqual(si.net_total, 1272.20)
self.assertEqual(si.grand_total, 1501.20)
self.assertEqual(si.total_taxes_and_charges, 229)
self.assertEqual(si.rounding_adjustment, -0.20)
expected_values = [
["_Test Account Service Tax - _TC", 0.0, 114.41],
["_Test Account VAT - _TC", 0.0, 114.41],
[si.debit_to, 1500, 0.0],
["Round Off - _TC", 0.01, 0.01],
["Sales - _TC", 0.0, 1271.18],
["_Test Account Service Tax - _TC", 0.0, 114.50],
["_Test Account VAT - _TC", 0.0, 114.50],
[si.debit_to, 1501, 0.0],
["Round Off - _TC", 0.20, 0.0],
["Sales - _TC", 0.0, 1272.20],
]
gl_entries = frappe.db.sql(
@ -2176,7 +2197,8 @@ class TestSalesInvoice(FrappeTestCase):
si.save()
si.submit()
self.assertEqual(si.net_total, 4007.16)
self.assertEqual(si.net_total, si.base_net_total)
self.assertEqual(si.net_total, 4007.15)
self.assertEqual(si.grand_total, 4488.02)
self.assertEqual(si.total_taxes_and_charges, 480.86)
self.assertEqual(si.rounding_adjustment, -0.02)
@ -2188,7 +2210,7 @@ class TestSalesInvoice(FrappeTestCase):
["_Test Account Service Tax - _TC", 0.0, 240.43],
["_Test Account VAT - _TC", 0.0, 240.43],
["Sales - _TC", 0.0, 4007.15],
["Round Off - _TC", 0.02, 0.01],
["Round Off - _TC", 0.01, 0.0],
]
)

View File

@ -8,6 +8,20 @@ frappe.query_reports["Balance Sheet"] = $.extend(
erpnext.utils.add_dimensions("Balance Sheet", 10);
frappe.query_reports["Balance Sheet"]["filters"].push(
{
"fieldname": "selected_view",
"label": __("Select View"),
"fieldtype": "Select",
"options": [
{ "value": "Report", "label": __("Report View") },
{ "value": "Growth", "label": __("Growth View") }
],
"default": "Report",
"reqd": 1
},
);
frappe.query_reports["Balance Sheet"]["filters"].push({
fieldname: "accumulated_values",
label: __("Accumulated Values"),

View File

@ -8,6 +8,21 @@ frappe.query_reports["Profit and Loss Statement"] = $.extend(
erpnext.utils.add_dimensions("Profit and Loss Statement", 10);
frappe.query_reports["Profit and Loss Statement"]["filters"].push(
{
"fieldname": "selected_view",
"label": __("Select View"),
"fieldtype": "Select",
"options": [
{ "value": "Report", "label": __("Report View") },
{ "value": "Growth", "label": __("Growth View") },
{ "value": "Margin", "label": __("Margin View") },
],
"default": "Report",
"reqd": 1
},
);
frappe.query_reports["Profit and Loss Statement"]["filters"].push({
fieldname: "accumulated_values",
label: __("Accumulated Values"),

View File

@ -202,6 +202,7 @@ class AccountsController(TransactionBase):
self.validate_party()
self.validate_currency()
self.validate_party_account_currency()
self.validate_return_against_account()
if self.doctype in ["Purchase Invoice", "Sales Invoice"]:
if invalid_advances := [
@ -350,6 +351,20 @@ class AccountsController(TransactionBase):
for bundle in bundles:
frappe.delete_doc("Serial and Batch Bundle", bundle.name)
def validate_return_against_account(self):
if (
self.doctype in ["Sales Invoice", "Purchase Invoice"] and self.is_return and self.return_against
):
cr_dr_account_field = "debit_to" if self.doctype == "Sales Invoice" else "credit_to"
cr_dr_account_label = "Debit To" if self.doctype == "Sales Invoice" else "Credit To"
cr_dr_account = self.get(cr_dr_account_field)
if frappe.get_value(self.doctype, self.return_against, cr_dr_account_field) != cr_dr_account:
frappe.throw(
_("'{0}' account: '{1}' should match the Return Against Invoice").format(
frappe.bold(cr_dr_account_label), frappe.bold(cr_dr_account)
)
)
def validate_deferred_income_expense_account(self):
field_map = {
"Sales Invoice": "deferred_revenue_account",

View File

@ -99,7 +99,8 @@ status_map = {
],
"Purchase Receipt": [
["Draft", None],
["To Bill", "eval:self.per_billed < 100 and self.docstatus == 1"],
["To Bill", "eval:self.per_billed == 0 and self.docstatus == 1"],
["Partly Billed", "eval:self.per_billed > 0 and self.per_billed < 100 and self.docstatus == 1"],
["Return Issued", "eval:self.per_returned == 100 and self.docstatus == 1"],
["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
["Cancelled", "eval:self.docstatus==2"],

View File

@ -260,18 +260,22 @@ class SubcontractingController(StockController):
return frappe.get_all(f"{doctype}", fields=fields, filters=filters)
def __get_consumed_items(self, doctype, receipt_items):
fields = [
"serial_no",
"rm_item_code",
"reference_name",
"batch_no",
"consumed_qty",
"main_item_code",
"parent as voucher_no",
]
if self.subcontract_data.receipt_supplied_items_field != "Purchase Receipt Item Supplied":
fields.append("serial_and_batch_bundle")
return frappe.get_all(
self.subcontract_data.receipt_supplied_items_field,
fields=[
"serial_no",
"rm_item_code",
"reference_name",
"serial_and_batch_bundle",
"batch_no",
"consumed_qty",
"main_item_code",
"parent as voucher_no",
],
fields=fields,
filters={"docstatus": 1, "reference_name": ("in", list(receipt_items)), "parenttype": doctype},
)

View File

@ -8,6 +8,7 @@ import frappe
from frappe import _, scrub
from frappe.model.document import Document
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
from frappe.utils.deprecations import deprecated
import erpnext
from erpnext.accounts.doctype.journal_entry.journal_entry import get_exchange_rate
@ -74,7 +75,7 @@ class calculate_taxes_and_totals(object):
self.calculate_net_total()
self.calculate_tax_withholding_net_total()
self.calculate_taxes()
self.manipulate_grand_total_for_inclusive_tax()
self.adjust_grand_total_for_inclusive_tax()
self.calculate_totals()
self._cleanup()
self.calculate_total_net_weight()
@ -279,7 +280,7 @@ class calculate_taxes_and_totals(object):
):
amount = flt(item.amount) - total_inclusive_tax_amount_per_qty
item.net_amount = flt(amount / (1 + cumulated_tax_fraction))
item.net_amount = flt(amount / (1 + cumulated_tax_fraction), item.precision("net_amount"))
item.net_rate = flt(item.net_amount / item.qty, item.precision("net_rate"))
item.discount_percentage = flt(item.discount_percentage, item.precision("discount_percentage"))
@ -516,7 +517,12 @@ class calculate_taxes_and_totals(object):
tax.base_tax_amount = round(tax.base_tax_amount, 0)
tax.base_tax_amount_after_discount_amount = round(tax.base_tax_amount_after_discount_amount, 0)
@deprecated
def manipulate_grand_total_for_inclusive_tax(self):
# for backward compatablility - if in case used by an external application
return self.adjust_grand_total_for_inclusive_tax()
def adjust_grand_total_for_inclusive_tax(self):
# if fully inclusive taxes and diff
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]
@ -538,17 +544,21 @@ class calculate_taxes_and_totals(object):
diff = flt(diff, self.doc.precision("rounding_adjustment"))
if diff and abs(diff) <= (5.0 / 10 ** last_tax.precision("tax_amount")):
self.doc.rounding_adjustment = diff
self.doc.grand_total_diff = diff
else:
self.doc.grand_total_diff = 0
def calculate_totals(self):
if self.doc.get("taxes"):
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment)
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(
self.doc.get("grand_total_diff")
)
else:
self.doc.grand_total = flt(self.doc.net_total)
if self.doc.get("taxes"):
self.doc.total_taxes_and_charges = flt(
self.doc.grand_total - self.doc.net_total - flt(self.doc.rounding_adjustment),
self.doc.grand_total - self.doc.net_total - flt(self.doc.get("grand_total_diff")),
self.doc.precision("total_taxes_and_charges"),
)
else:
@ -613,8 +623,8 @@ class calculate_taxes_and_totals(object):
self.doc.grand_total, self.doc.currency, self.doc.precision("rounded_total")
)
# if print_in_rate is set, we would have already calculated rounding adjustment
self.doc.rounding_adjustment += flt(
# rounding adjustment should always be the difference vetween grand and rounded total
self.doc.rounding_adjustment = flt(
self.doc.rounded_total - self.doc.grand_total, self.doc.precision("rounding_adjustment")
)
@ -832,7 +842,6 @@ class calculate_taxes_and_totals(object):
self.calculate_paid_amount()
def calculate_paid_amount(self):
paid_amount = base_paid_amount = 0.0
if self.doc.is_pos:

File diff suppressed because it is too large Load Diff

View File

@ -176,8 +176,10 @@ class BOM(WebsiteGenerator):
def autoname(self):
# ignore amended documents while calculating current index
search_key = f"{self.doctype}-{self.item}%"
existing_boms = frappe.get_all(
"BOM", filters={"item": self.item, "amended_from": ["is", "not set"]}, pluck="name"
"BOM", filters={"name": ("like", search_key), "amended_from": ["is", "not set"]}, pluck="name"
)
if existing_boms:

View File

@ -160,7 +160,7 @@ erpnext.accounts.taxes = {
let tax = frappe.get_doc(cdt, cdn);
try {
me.validate_taxes_and_charges(cdt, cdn);
me.validate_inclusive_tax(tax);
me.validate_inclusive_tax(tax, frm);
} catch(e) {
tax.included_in_print_rate = 0;
refresh_field("included_in_print_rate", tax.name, tax.parentfield);
@ -170,7 +170,8 @@ erpnext.accounts.taxes = {
});
},
validate_inclusive_tax: function(tax) {
validate_inclusive_tax: function(tax, frm) {
this.frm = this.frm || frm;
let actual_type_error = function() {
var msg = __("Actual type tax cannot be included in Item rate in row {0}", [tax.idx])
frappe.throw(msg);
@ -186,12 +187,12 @@ erpnext.accounts.taxes = {
if(tax.charge_type == "Actual") {
// inclusive tax cannot be of type Actual
actual_type_error();
} else if(tax.charge_type == "On Previous Row Amount" &&
} else if (tax.charge_type == "On Previous Row Amount" && this.frm &&
!cint(this.frm.doc["taxes"][tax.row_id - 1].included_in_print_rate)
) {
// referred row should also be an inclusive tax
on_previous_row_error(tax.row_id);
} else if(tax.charge_type == "On Previous Row Total") {
} else if (tax.charge_type == "On Previous Row Total" && this.frm) {
var taxes_not_included = $.map(this.frm.doc["taxes"].slice(0, tax.row_id),
function(t) { return cint(t.included_in_print_rate) ? null : t; });
if(taxes_not_included.length > 0) {

View File

@ -103,7 +103,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
this.determine_exclusive_rate();
this.calculate_net_total();
this.calculate_taxes();
this.manipulate_grand_total_for_inclusive_tax();
this.adjust_grand_total_for_inclusive_tax();
this.calculate_totals();
this._cleanup();
}
@ -185,7 +185,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
if (!this.discount_amount_applied) {
erpnext.accounts.taxes.validate_taxes_and_charges(tax.doctype, tax.name);
erpnext.accounts.taxes.validate_inclusive_tax(tax);
erpnext.accounts.taxes.validate_inclusive_tax(tax, this.frm);
}
frappe.model.round_floats_in(tax);
});
@ -248,7 +248,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
if(!me.discount_amount_applied && item.qty && (total_inclusive_tax_amount_per_qty || cumulated_tax_fraction)) {
var amount = flt(item.amount) - total_inclusive_tax_amount_per_qty;
item.net_amount = flt(amount / (1 + cumulated_tax_fraction));
item.net_amount = flt(amount / (1 + cumulated_tax_fraction), precision("net_amount", item));
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"]);
@ -303,6 +303,8 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
me.frm.doc.net_total += item.net_amount;
me.frm.doc.base_net_total += item.base_net_amount;
});
frappe.model.round_floats_in(this.frm.doc, ["total", "base_total", "net_total", "base_net_total"]);
}
calculate_shipping_charges() {
@ -521,8 +523,17 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
}
}
/**
* @deprecated Use adjust_grand_total_for_inclusive_tax instead.
*/
manipulate_grand_total_for_inclusive_tax() {
// for backward compatablility - if in case used by an external application
this.adjust_grand_total_for_inclusive_tax()
}
adjust_grand_total_for_inclusive_tax() {
var me = this;
// if fully inclusive taxes and diff
if (this.frm.doc["taxes"] && this.frm.doc["taxes"].length) {
var any_inclusive_tax = false;
@ -548,7 +559,9 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
diff = flt(diff, precision("rounding_adjustment"));
if ( diff && Math.abs(diff) <= (5.0 / Math.pow(10, precision("tax_amount", last_tax))) ) {
me.frm.doc.rounding_adjustment = diff;
me.frm.doc.grand_total_diff = diff;
} else {
me.frm.doc.grand_total_diff = 0;
}
}
}
@ -559,7 +572,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
var me = this;
var tax_count = this.frm.doc["taxes"] ? this.frm.doc["taxes"].length : 0;
this.frm.doc.grand_total = flt(tax_count
? this.frm.doc["taxes"][tax_count - 1].total + flt(this.frm.doc.rounding_adjustment)
? this.frm.doc["taxes"][tax_count - 1].total + flt(this.frm.doc.grand_total_diff)
: this.frm.doc.net_total);
if(in_list(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice", "POS Invoice"], this.frm.doc.doctype)) {
@ -619,7 +632,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
if(frappe.meta.get_docfield(this.frm.doc.doctype, "rounded_total", this.frm.doc.name)) {
this.frm.doc.rounded_total = round_based_on_smallest_currency_fraction(this.frm.doc.grand_total,
this.frm.doc.currency, precision("rounded_total"));
this.frm.doc.rounding_adjustment += flt(this.frm.doc.rounded_total - this.frm.doc.grand_total,
this.frm.doc.rounding_adjustment = flt(this.frm.doc.rounded_total - this.frm.doc.grand_total,
precision("rounding_adjustment"));
this.set_in_company_currency(this.frm.doc, ["rounding_adjustment", "rounded_total"]);
@ -687,8 +700,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
if (total_for_discount_amount) {
$.each(this.frm._items || [], function(i, item) {
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("base_amount", item));
item.net_amount = flt(item.net_amount - distributed_amount, precision("net_amount", item));
net_total += item.net_amount;
// discount amount rounding loss adjustment if no taxes

View File

@ -2,7 +2,58 @@ frappe.provide("erpnext.financial_statements");
erpnext.financial_statements = {
"filters": get_filters(),
"baseData": null,
"formatter": function(value, row, column, data, default_formatter, filter) {
if(frappe.query_report.get_filter_value("selected_view") == "Growth" && data && column.colIndex >= 3){
//Assuming that the first three columns are s.no, account name and the very first year of the accounting values, to calculate the relative percentage values of the successive columns.
const lastAnnualValue = row[column.colIndex - 1].content;
const currentAnnualvalue = data[column.fieldname];
if(currentAnnualvalue == undefined) return 'NA'; //making this not applicable for undefined/null values
let annualGrowth = 0;
if(lastAnnualValue == 0 && currentAnnualvalue > 0){
//If the previous year value is 0 and the current value is greater than 0
annualGrowth = 1;
}
else if(lastAnnualValue > 0){
annualGrowth = (currentAnnualvalue - lastAnnualValue) / lastAnnualValue;
}
const growthPercent = (Math.round(annualGrowth*10000)/100); //calculating the rounded off percentage
value = $(`<span>${((growthPercent >=0)? '+':'' )+growthPercent+'%'}</span>`);
if(growthPercent < 0){
value = $(value).addClass("text-danger");
}
else{
value = $(value).addClass("text-success");
}
value = $(value).wrap("<p></p>").parent().html();
return value;
}
else if(frappe.query_report.get_filter_value("selected_view") == "Margin" && data){
if(column.fieldname =="account" && data.account_name == __("Income")){
//Taking the total income from each column (for all the financial years) as the base (100%)
this.baseData = row;
}
if(column.colIndex >= 2){
//Assuming that the first two columns are s.no and account name, to calculate the relative percentage values of the successive columns.
const currentAnnualvalue = data[column.fieldname];
const baseValue = this.baseData[column.colIndex].content;
if(currentAnnualvalue == undefined || baseValue <= 0) return 'NA';
const marginPercent = Math.round((currentAnnualvalue/baseValue)*10000)/100;
value = $(`<span>${marginPercent+'%'}</span>`);
if(marginPercent < 0)
value = $(value).addClass("text-danger");
else
value = $(value).addClass("text-success");
value = $(value).wrap("<p></p>").parent().html();
return value;
}
}
if (data && column.fieldname=="account") {
value = data.account_name || value;

View File

@ -391,7 +391,6 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
balance_qty = obj.qty - ordered_items.get(obj.item_code, 0.0)
target.qty = balance_qty if balance_qty > 0 else 0
target.stock_qty = flt(target.qty) * flt(obj.conversion_factor)
target.delivery_date = nowdate()
if obj.against_blanket_order:
target.against_blanket_order = obj.against_blanket_order

View File

@ -99,7 +99,6 @@ class TestQuotation(FrappeTestCase):
self.assertEqual(sales_order.get("items")[0].prevdoc_docname, quotation.name)
self.assertEqual(sales_order.customer, "_Test Customer")
sales_order.delivery_date = "2014-01-01"
sales_order.naming_series = "_T-Quotation-"
sales_order.transaction_date = nowdate()
sales_order.insert()
@ -132,7 +131,6 @@ class TestQuotation(FrappeTestCase):
self.assertEqual(sales_order.get("items")[0].prevdoc_docname, quotation.name)
self.assertEqual(sales_order.customer, "_Test Customer")
sales_order.delivery_date = "2014-01-01"
sales_order.naming_series = "_T-Quotation-"
sales_order.transaction_date = nowdate()
sales_order.insert()

View File

@ -429,6 +429,9 @@ frappe.ui.form.on("Material Request Item", {
rate: function(frm, doctype, name) {
const item = locals[doctype][name];
item.amount = flt(item.qty) * flt(item.rate);
frappe.model.set_value(doctype, name, "amount", item.amount);
refresh_field("amount", item.name, item.parentfield);
frm.events.get_item_data(frm, item, false);
},

View File

@ -8,8 +8,10 @@ frappe.listview_settings['Purchase Receipt'] = {
return [__("Closed"), "green", "status,=,Closed"];
} else if (flt(doc.per_returned, 2) === 100) {
return [__("Return Issued"), "grey", "per_returned,=,100"];
} else if (flt(doc.grand_total) !== 0 && flt(doc.per_billed, 2) < 100) {
} else if (flt(doc.grand_total) !== 0 && flt(doc.per_billed, 2) == 0) {
return [__("To Bill"), "orange", "per_billed,<,100"];
} else if (flt(doc.per_billed, 2) > 0 && flt(doc.per_billed, 2) < 100) {
return [__("Partly Billed"), "yellow", "per_billed,<,100"];
} else if (flt(doc.grand_total) === 0 || flt(doc.per_billed, 2) === 100) {
return [__("Completed"), "green", "per_billed,=,100"];
}

View File

@ -720,7 +720,7 @@ class TestPurchaseReceipt(FrappeTestCase):
pr2.load_from_db()
self.assertEqual(pr2.get("items")[0].billed_amt, 2000)
self.assertEqual(pr2.per_billed, 80)
self.assertEqual(pr2.status, "To Bill")
self.assertEqual(pr2.status, "Partly Billed")
pr2.cancel()
pi2.reload()
@ -1152,7 +1152,7 @@ class TestPurchaseReceipt(FrappeTestCase):
pi.load_from_db()
pr.load_from_db()
self.assertEqual(pr.status, "To Bill")
self.assertEqual(pr.status, "Partly Billed")
self.assertAlmostEqual(pr.per_billed, 50.0, places=2)
def test_purchase_receipt_with_exchange_rate_difference(self):
@ -1675,9 +1675,10 @@ class TestPurchaseReceipt(FrappeTestCase):
make_stock_entry(
purpose="Material Receipt",
item_code=item.name,
qty=15,
qty=20,
company=company,
to_warehouse=from_warehouse,
posting_date=add_days(today(), -3),
)
# Step 3: Create Delivery Note with Internal Customer
@ -1700,6 +1701,8 @@ class TestPurchaseReceipt(FrappeTestCase):
from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt
pr = make_inter_company_purchase_receipt(dn.name)
pr.set_posting_time = 1
pr.posting_date = today()
pr.items[0].qty = 15
pr.items[0].from_warehouse = target_warehouse
pr.items[0].warehouse = to_warehouse
@ -1718,6 +1721,7 @@ class TestPurchaseReceipt(FrappeTestCase):
company=company,
from_warehouse=from_warehouse,
to_warehouse=target_warehouse,
posting_date=add_days(pr.posting_date, -1),
)
pr.reload()

View File

@ -228,7 +228,6 @@ class StockEntry(StockController):
self.fg_completed_qty = 0.0
self.validate_serialized_batch()
self.set_actual_qty()
self.calculate_rate_and_amount()
self.validate_putaway_capacity()