Date: Fri, 23 Apr 2021 08:04:00 +0530
Subject: [PATCH 013/149] refactor: Replace Class.extend with native class
---
.../doctype/journal_entry/journal_entry.js | 36 +-
.../payment_reconciliation.js | 38 +-
.../doctype/pos_invoice/pos_invoice.js | 50 +--
.../purchase_invoice/purchase_invoice.js | 98 ++---
.../doctype/sales_invoice/sales_invoice.js | 127 ++++---
.../doctype/purchase_order/purchase_order.js | 90 ++---
.../request_for_quotation.js | 22 +-
.../supplier_quotation/supplier_quotation.js | 22 +-
erpnext/crm/doctype/lead/lead.js | 38 +-
.../crm/doctype/opportunity/opportunity.js | 14 +-
.../student_attendance_tool.js | 14 +-
.../doctype/exercise_type/exercise_type.js | 26 +-
erpnext/hr/doctype/employee/employee.js | 20 +-
.../employee_attendance_tool.js | 20 +-
.../upload_attendance/upload_attendance.js | 18 +-
.../maintenance_schedule.js | 24 +-
.../maintenance_visit/maintenance_visit.js | 10 +-
erpnext/manufacturing/doctype/bom/bom.js | 24 +-
erpnext/public/js/account_tree_grid.js | 81 ++--
erpnext/public/js/controllers/buying.js | 122 +++---
.../public/js/controllers/stock_controller.js | 22 +-
.../public/js/controllers/taxes_and_totals.js | 146 +++----
erpnext/public/js/controllers/transaction.js | 358 +++++++++---------
erpnext/public/js/payment/payments.js | 92 ++---
erpnext/public/js/stock_analytics.js | 46 +--
erpnext/public/js/stock_grid_report.js | 24 +-
erpnext/public/js/telephony.js | 10 +-
.../public/js/utils/customer_quick_entry.js | 20 +-
erpnext/public/js/utils/item_quick_entry.js | 90 ++---
erpnext/public/js/utils/item_selector.js | 22 +-
.../js/utils/serial_no_batch_selector.js | 48 +--
.../installation_note/installation_note.js | 8 +-
.../selling/doctype/quotation/quotation.js | 44 +--
.../doctype/sales_order/sales_order.js | 90 ++---
erpnext/selling/sales_common.js | 144 +++----
erpnext/stock/dashboard/item_dashboard.js | 26 +-
.../doctype/delivery_note/delivery_note.js | 60 +--
.../landed_cost_voucher.js | 34 +-
.../material_request/material_request.js | 42 +-
.../purchase_receipt/purchase_receipt.js | 38 +-
.../stock/doctype/stock_entry/stock_entry.js | 82 ++--
.../stock_reconciliation.js | 12 +-
.../doctype/warranty_claim/warranty_claim.js | 10 +-
erpnext/templates/includes/rfq.js | 34 +-
44 files changed, 1200 insertions(+), 1196 deletions(-)
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 37b03f3f0e..2f8d3e31d9 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -194,19 +194,19 @@ var update_jv_details = function(doc, r) {
refresh_field("accounts");
}
-erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
- onload: function() {
+erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Controller {
+ onload() {
this.load_defaults();
this.setup_queries();
this.setup_balance_formatter();
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
- },
+ }
- onload_post_render: function() {
+ onload_post_render() {
cur_frm.get_field("accounts").grid.set_multiple_add("account");
- },
+ }
- load_defaults: function() {
+ load_defaults() {
//this.frm.show_print_first = true;
if(this.frm.doc.__islocal && this.frm.doc.company) {
frappe.model.set_default_values(this.frm.doc);
@@ -216,9 +216,9 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
var posting_date = this.frm.doc.posting_date;
if(!this.frm.doc.amended_from) this.frm.set_value('posting_date', posting_date || frappe.datetime.get_today());
}
- },
+ }
- setup_queries: function() {
+ setup_queries() {
var me = this;
me.frm.set_query("account", "accounts", function(doc, cdt, cdn) {
@@ -324,9 +324,9 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
});
- },
+ }
- setup_balance_formatter: function() {
+ setup_balance_formatter() {
var me = this;
$.each(["balance", "party_balance"], function(i, field) {
var df = frappe.meta.get_docfield("Journal Entry Account", field, me.frm.doc.name);
@@ -339,9 +339,9 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
+ "";
}
})
- },
+ }
- reference_name: function(doc, cdt, cdn) {
+ reference_name(doc, cdt, cdn) {
var d = frappe.get_doc(cdt, cdn);
if(d.reference_name) {
@@ -353,9 +353,9 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
this.get_outstanding('Journal Entry', d.reference_name, doc.company, d);
}
}
- },
+ }
- get_outstanding: function(doctype, docname, company, child, due_date) {
+ get_outstanding(doctype, docname, company, child, due_date) {
var me = this;
var args = {
"doctype": doctype,
@@ -377,9 +377,9 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
}
}
});
- },
+ }
- accounts_add: function(doc, cdt, cdn) {
+ accounts_add(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
$.each(doc.accounts, function(i, d) {
if(d.account && d.party && d.party_type) {
@@ -402,9 +402,9 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
cur_frm.cscript.update_totals(doc);
erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, 'accounts');
- },
+ }
-});
+};
cur_frm.script_manager.make(erpnext.accounts.JournalEntry);
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
index 6b07197ec1..dd91fec3c1 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
@@ -34,8 +34,8 @@ frappe.ui.form.on("Payment Reconciliation Payment", {
}
});
-erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.extend({
- onload: function() {
+erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationController extends frappe.ui.form.Controller {
+ onload() {
var me = this;
this.frm.set_query("party", function() {
@@ -84,18 +84,18 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
frappe.throw({message: __("Please Select Both Company and Party Type First"), title: title});
}
};
- },
+ }
- refresh: function() {
+ refresh() {
this.frm.disable_save();
this.toggle_primary_action();
- },
+ }
- onload_post_render: function() {
+ onload_post_render() {
this.toggle_primary_action();
- },
+ }
- party: function() {
+ party() {
var me = this
if (!me.frm.doc.receivable_payable_account && me.frm.doc.party_type && me.frm.doc.party) {
return frappe.call({
@@ -112,9 +112,9 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
}
});
}
- },
+ }
- get_unreconciled_entries: function() {
+ get_unreconciled_entries() {
var me = this;
return this.frm.call({
doc: me.frm.doc,
@@ -125,9 +125,9 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
}
});
- },
+ }
- reconcile: function() {
+ reconcile() {
var me = this;
var show_dialog = me.frm.doc.payments.filter(d => d.difference_amount && !d.difference_account);
@@ -209,9 +209,9 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
} else {
this.reconcile_payment_entries();
}
- },
+ }
- reconcile_payment_entries: function() {
+ reconcile_payment_entries() {
var me = this;
return this.frm.call({
@@ -222,9 +222,9 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
me.toggle_primary_action();
}
});
- },
+ }
- set_invoice_options: function() {
+ set_invoice_options() {
var me = this;
var invoices = [];
@@ -243,9 +243,9 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
}
refresh_field("payments");
- },
+ }
- toggle_primary_action: function() {
+ toggle_primary_action() {
if ((this.frm.doc.payments || []).length) {
this.frm.fields_dict.reconcile.$input
&& this.frm.fields_dict.reconcile.$input.addClass("btn-primary");
@@ -259,6 +259,6 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
}
}
-});
+};
$.extend(cur_frm.cscript, new erpnext.accounts.PaymentReconciliationController({frm: cur_frm}));
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
index 493bd44802..72d587afb5 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
@@ -4,18 +4,18 @@
{% include 'erpnext/selling/sales_common.js' %};
frappe.provide("erpnext.accounts");
-erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend({
+erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnext.selling.SellingController {
setup(doc) {
this.setup_posting_date_time_check();
- this._super(doc);
- },
+ super.setup(doc);
+ }
- company: function() {
+ company() {
erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
- },
+ }
onload(doc) {
- this._super();
+ super.onload();
this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice Merge Log'];
if(doc.__islocal && doc.is_pos && frappe.get_route_str() !== 'point-of-sale') {
this.frm.script_manager.trigger("is_pos");
@@ -23,10 +23,10 @@ erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend(
}
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
- },
+ }
refresh(doc) {
- this._super();
+ super.refresh();
if (doc.docstatus == 1 && !doc.is_return) {
this.frm.add_custom_button(__('Return'), this.make_sales_return, __('Create'));
this.frm.page.set_inner_btn_group_as_primary(__('Create'));
@@ -36,13 +36,13 @@ erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend(
this.frm.return_print_format = "Sales Invoice Return";
this.frm.set_value('consolidated_invoice', '');
}
- },
+ }
- is_pos: function() {
+ is_pos() {
this.set_pos_data();
- },
+ }
- set_pos_data: async function() {
+ async set_pos_data() {
if(this.frm.doc.is_pos) {
this.frm.set_value("allocate_advances_automatically", 0);
if(!this.frm.doc.company) {
@@ -69,7 +69,7 @@ erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend(
}
}
}
- },
+ }
customer() {
if (!this.frm.doc.customer) return
@@ -86,13 +86,13 @@ erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend(
}, () => {
this.apply_pricing_rule();
});
- },
+ }
- amount: function(){
+ amount(){
this.write_off_outstanding_amount_automatically()
- },
+ }
- change_amount: function(){
+ change_amount(){
if(this.frm.doc.paid_amount > this.frm.doc.grand_total){
this.calculate_write_off_amount();
}else {
@@ -101,16 +101,16 @@ erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend(
}
this.frm.refresh_fields();
- },
+ }
- loyalty_amount: function(){
+ loyalty_amount(){
this.calculate_outstanding_amount();
this.frm.refresh_field("outstanding_amount");
this.frm.refresh_field("paid_amount");
this.frm.refresh_field("base_paid_amount");
- },
+ }
- write_off_outstanding_amount_automatically: function() {
+ write_off_outstanding_amount_automatically() {
if(cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
// this will make outstanding amount 0
@@ -125,15 +125,15 @@ erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend(
this.calculate_outstanding_amount(false);
this.frm.refresh_fields();
- },
+ }
- make_sales_return: function() {
+ make_sales_return() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.pos_invoice.pos_invoice.make_sales_return",
frm: cur_frm
})
- },
-})
+ }
+}
$.extend(cur_frm.cscript, new erpnext.selling.POSInvoiceController({ frm: cur_frm }))
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 06aa20bfc5..b31cdce0b2 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -4,10 +4,10 @@
frappe.provide("erpnext.accounts");
{% include 'erpnext/public/js/controllers/buying.js' %};
-erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
- setup: function(doc) {
+erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.BuyingController {
+ setup(doc) {
this.setup_posting_date_time_check();
- this._super(doc);
+ super.setup(doc);
// formatter for purchase invoice item
if(this.frm.doc.update_stock) {
@@ -25,14 +25,14 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
}
};
});
- },
+ }
- company: function() {
+ company() {
erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
- },
+ }
- onload: function() {
- this._super();
+ onload() {
+ super.onload();
if(!this.frm.doc.__islocal) {
// show credit_to in print format
@@ -48,11 +48,11 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
}
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
- },
+ }
- refresh: function(doc) {
+ refresh(doc) {
const me = this;
- this._super();
+ super.refresh();
hide_fields(this.frm.doc);
// Show / Hide button
@@ -161,26 +161,26 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
}
this.frm.set_df_property("tax_withholding_category", "hidden", doc.apply_tds ? 0 : 1);
- },
+ }
- unblock_invoice: function() {
+ unblock_invoice() {
const me = this;
frappe.call({
'method': 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.unblock_invoice',
'args': {'name': me.frm.doc.name},
'callback': (r) => me.frm.reload_doc()
});
- },
+ }
- block_invoice: function() {
+ block_invoice() {
this.make_comment_dialog_and_block_invoice();
- },
+ }
- change_release_date: function() {
+ change_release_date() {
this.make_dialog_and_set_release_date();
- },
+ }
- can_change_release_date: function(date) {
+ can_change_release_date(date) {
const diff = frappe.datetime.get_diff(date, frappe.datetime.nowdate());
if (diff < 0) {
frappe.throw(__('New release date should be in the future'));
@@ -188,9 +188,9 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
} else {
return true;
}
- },
+ }
- make_comment_dialog_and_block_invoice: function(){
+ make_comment_dialog_and_block_invoice(){
const me = this;
const title = __('Block Invoice');
@@ -232,9 +232,9 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
});
this.dialog.show();
- },
+ }
- make_dialog_and_set_release_date: function() {
+ make_dialog_and_set_release_date() {
const me = this;
const title = __('Set New Release Date');
@@ -263,17 +263,17 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
});
this.dialog.show();
- },
+ }
- set_release_date: function(data) {
+ set_release_date(data) {
return frappe.call({
'method': 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.change_release_date',
'args': data,
'callback': (r) => this.frm.reload_doc()
});
- },
+ }
- supplier: function() {
+ supplier() {
var me = this;
// Do not update if inter company reference is there as the details will already be updated
@@ -295,9 +295,9 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
me.frm.set_df_property("apply_tds", "read_only", me.frm.supplier_tds ? 0 : 1);
me.frm.set_df_property("tax_withholding_category", "hidden", me.frm.supplier_tds ? 0 : 1);
})
- },
+ }
- apply_tds: function(frm) {
+ apply_tds(frm) {
var me = this;
if (!me.frm.doc.apply_tds) {
@@ -307,9 +307,9 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
me.frm.set_value("tax_withholding_category", me.frm.supplier_tds);
me.frm.set_df_property("tax_withholding_category", "hidden", 0);
}
- },
+ }
- credit_to: function() {
+ credit_to() {
var me = this;
if(this.frm.doc.credit_to) {
me.frm.call({
@@ -327,16 +327,16 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
}
});
}
- },
+ }
- make_inter_company_invoice: function(frm) {
+ make_inter_company_invoice(frm) {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_inter_company_sales_invoice",
frm: frm
});
- },
+ }
- is_paid: function() {
+ is_paid() {
hide_fields(this.frm.doc);
if(cint(this.frm.doc.is_paid)) {
this.frm.set_value("allocate_advances_automatically", 0);
@@ -347,44 +347,44 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
}
this.calculate_outstanding_amount();
this.frm.refresh_fields();
- },
+ }
- write_off_amount: function() {
+ write_off_amount() {
this.set_in_company_currency(this.frm.doc, ["write_off_amount"]);
this.calculate_outstanding_amount();
this.frm.refresh_fields();
- },
+ }
- paid_amount: function() {
+ paid_amount() {
this.set_in_company_currency(this.frm.doc, ["paid_amount"]);
this.write_off_amount();
this.frm.refresh_fields();
- },
+ }
- allocated_amount: function() {
+ allocated_amount() {
this.calculate_total_advance();
this.frm.refresh_fields();
- },
+ }
- items_add: function(doc, cdt, cdn) {
+ items_add(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
this.frm.script_manager.copy_from_first_row("items", row,
["expense_account", "cost_center", "project"]);
- },
+ }
- on_submit: function() {
+ on_submit() {
$.each(this.frm.doc["items"] || [], function(i, row) {
if(row.purchase_receipt) frappe.model.clear_doc("Purchase Receipt", row.purchase_receipt)
})
- },
+ }
- make_debit_note: function() {
+ make_debit_note() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_debit_note",
frm: cur_frm
})
- },
-});
+ }
+};
cur_frm.script_manager.make(erpnext.accounts.PurchaseInvoice);
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index b361c0c345..8e8f85a3e4 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -2,23 +2,24 @@
// License: GNU General Public License v3. See license.txt
// print heading
+frappe.provide('cur_frm.pformat')
cur_frm.pformat.print_heading = 'Invoice';
{% include 'erpnext/selling/sales_common.js' %};
frappe.provide("erpnext.accounts");
-erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.extend({
- setup: function(doc) {
+erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends erpnext.selling.SellingController {
+ setup(doc) {
this.setup_posting_date_time_check();
- this._super(doc);
- },
- company: function() {
+ super.setup(doc);
+ }
+ company() {
erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
- },
- onload: function() {
+ }
+ onload() {
var me = this;
- this._super();
+ super.onload();
this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice'];
if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) {
@@ -38,11 +39,11 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}
erpnext.queries.setup_warehouse_query(this.frm);
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
- },
+ }
- refresh: function(doc, dt, dn) {
+ refresh(doc, dt, dn) {
const me = this;
- this._super();
+ super.refresh();
if(cur_frm.msgbox && cur_frm.msgbox.$wrapper.is(":visible")) {
// hide new msgbox
cur_frm.msgbox.hide();
@@ -141,16 +142,16 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}, __('Create'));
}
}
- },
+ }
- make_maintenance_schedule: function() {
+ make_maintenance_schedule() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_maintenance_schedule",
frm: cur_frm
})
- },
+ }
- on_submit: function(doc, dt, dn) {
+ on_submit(doc, dt, dn) {
var me = this;
if (frappe.get_route()[0] != 'Form') {
@@ -160,9 +161,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
$.each(doc["items"], function(i, row) {
if(row.delivery_note) frappe.model.clear_doc("Delivery Note", row.delivery_note)
})
- },
+ }
- set_default_print_format: function() {
+ set_default_print_format() {
// set default print format to POS type or Credit Note
if(cur_frm.doc.is_pos) {
if(cur_frm.pos_print_format) {
@@ -183,9 +184,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
cur_frm.meta._default_print_format = null;
}
}
- },
+ }
- sales_order_btn: function() {
+ sales_order_btn() {
var me = this;
this.$sales_order_btn = this.frm.add_custom_button(__('Sales Order'),
function() {
@@ -204,9 +205,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}
})
}, __("Get Items From"));
- },
+ }
- quotation_btn: function() {
+ quotation_btn() {
var me = this;
this.$quotation_btn = this.frm.add_custom_button(__('Quotation'),
function() {
@@ -228,9 +229,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}
})
}, __("Get Items From"));
- },
+ }
- delivery_note_btn: function() {
+ delivery_note_btn() {
var me = this;
this.$delivery_note_btn = this.frm.add_custom_button(__('Delivery Note'),
function() {
@@ -256,12 +257,12 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}
});
}, __("Get Items From"));
- },
+ }
- tc_name: function() {
+ tc_name() {
this.get_terms();
- },
- customer: function() {
+ }
+ customer() {
if (this.frm.doc.is_pos){
var pos_profile = this.frm.doc.pos_profile;
}
@@ -292,16 +293,16 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}
});
}
- },
+ }
- make_inter_company_invoice: function() {
+ make_inter_company_invoice() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_inter_company_purchase_invoice",
frm: me.frm
});
- },
+ }
- debit_to: function() {
+ debit_to() {
var me = this;
if(this.frm.doc.debit_to) {
me.frm.call({
@@ -319,14 +320,14 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}
});
}
- },
+ }
- allocated_amount: function() {
+ allocated_amount() {
this.calculate_total_advance();
this.frm.refresh_fields();
- },
+ }
- write_off_outstanding_amount_automatically: function() {
+ write_off_outstanding_amount_automatically() {
if(cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
// this will make outstanding amount 0
@@ -341,39 +342,39 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
this.calculate_outstanding_amount(false);
this.frm.refresh_fields();
- },
+ }
- write_off_amount: function() {
+ write_off_amount() {
this.set_in_company_currency(this.frm.doc, ["write_off_amount"]);
this.write_off_outstanding_amount_automatically();
- },
+ }
- items_add: function(doc, cdt, cdn) {
+ items_add(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
this.frm.script_manager.copy_from_first_row("items", row, ["income_account", "cost_center"]);
- },
+ }
- set_dynamic_labels: function() {
- this._super();
+ set_dynamic_labels() {
+ super.set_dynamic_labels();
this.frm.events.hide_fields(this.frm)
- },
+ }
- items_on_form_rendered: function() {
+ items_on_form_rendered() {
erpnext.setup_serial_no();
- },
+ }
- packed_items_on_form_rendered: function(doc, grid_row) {
+ packed_items_on_form_rendered(doc, grid_row) {
erpnext.setup_serial_no();
- },
+ }
- make_sales_return: function() {
+ make_sales_return() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_sales_return",
frm: cur_frm
})
- },
+ }
- asset: function(frm, cdt, cdn) {
+ asset(frm, cdt, cdn) {
var row = locals[cdt][cdn];
if(row.asset) {
frappe.call({
@@ -387,18 +388,18 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}
})
}
- },
+ }
- is_pos: function(frm){
+ is_pos(frm){
this.set_pos_data();
- },
+ }
- pos_profile: function() {
+ pos_profile() {
this.frm.doc.taxes = []
this.set_pos_data();
- },
+ }
- set_pos_data: function() {
+ set_pos_data() {
if(this.frm.doc.is_pos) {
this.frm.set_value("allocate_advances_automatically", 0);
if(!this.frm.doc.company) {
@@ -428,13 +429,13 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}
}
else this.frm.trigger("refresh");
- },
+ }
- amount: function(){
+ amount(){
this.write_off_outstanding_amount_automatically()
- },
+ }
- change_amount: function(){
+ change_amount(){
if(this.frm.doc.paid_amount > this.frm.doc.grand_total){
this.calculate_write_off_amount();
}else {
@@ -443,15 +444,15 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}
this.frm.refresh_fields();
- },
+ }
- loyalty_amount: function(){
+ loyalty_amount(){
this.calculate_outstanding_amount();
this.frm.refresh_field("outstanding_amount");
this.frm.refresh_field("paid_amount");
this.frm.refresh_field("base_paid_amount");
}
-});
+};
// for backward compatibility: combine new and previous states
$.extend(cur_frm.cscript, new erpnext.accounts.SalesInvoiceController({frm: cur_frm}));
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index dd0f065848..c0e19e9c3d 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -61,8 +61,8 @@ frappe.ui.form.on("Purchase Order Item", {
}
});
-erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend({
- setup: function() {
+erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends erpnext.buying.BuyingController {
+ setup() {
this.frm.custom_make_buttons = {
'Purchase Receipt': 'Purchase Receipt',
'Purchase Invoice': 'Purchase Invoice',
@@ -70,13 +70,13 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
'Payment Entry': 'Payment',
}
- this._super();
+ super.setup();
- },
+ }
- refresh: function(doc, cdt, cdn) {
+ refresh(doc, cdt, cdn) {
var me = this;
- this._super();
+ super.refresh();
var allow_receipt = false;
var is_drop_ship = false;
@@ -182,9 +182,9 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
} else if(doc.docstatus===0) {
cur_frm.cscript.add_from_mappers();
}
- },
+ }
- get_items_from_open_material_requests: function() {
+ get_items_from_open_material_requests() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order_based_on_supplier",
args: {
@@ -202,17 +202,17 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
},
get_query_method: "erpnext.stock.doctype.material_request.material_request.get_material_requests_based_on_supplier"
});
- },
+ }
- validate: function() {
+ validate() {
set_schedule_date(this.frm);
- },
+ }
- has_unsupplied_items: function() {
+ has_unsupplied_items() {
return this.frm.doc['supplied_items'].some(item => item.required_qty != item.supplied_qty)
- },
+ }
- make_stock_entry: function() {
+ make_stock_entry() {
var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; });
var me = this;
@@ -326,9 +326,9 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
me.dialog.hide();
});
- },
+ }
- _make_rm_stock_entry: function(rm_items) {
+ _make_rm_stock_entry(rm_items) {
frappe.call({
method:"erpnext.buying.doctype.purchase_order.purchase_order.make_rm_stock_entry",
args: {
@@ -341,31 +341,31 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
}
});
- },
+ }
- make_inter_company_order: function(frm) {
+ make_inter_company_order(frm) {
frappe.model.open_mapped_doc({
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_inter_company_sales_order",
frm: frm
});
- },
+ }
- make_purchase_receipt: function() {
+ make_purchase_receipt() {
frappe.model.open_mapped_doc({
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_receipt",
frm: cur_frm,
freeze_message: __("Creating Purchase Receipt ...")
})
- },
+ }
- make_purchase_invoice: function() {
+ make_purchase_invoice() {
frappe.model.open_mapped_doc({
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice",
frm: cur_frm
})
- },
+ }
- add_from_mappers: function() {
+ add_from_mappers() {
var me = this;
this.frm.add_custom_button(__('Material Request'),
function() {
@@ -471,13 +471,13 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
}
});
}, __("Tools"));
- },
+ }
- tc_name: function() {
+ tc_name() {
this.get_terms();
- },
+ }
- items_add: function(doc, cdt, cdn) {
+ items_add(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
if(doc.schedule_date) {
row.schedule_date = doc.schedule_date;
@@ -485,13 +485,13 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
} else {
this.frm.script_manager.copy_from_first_row("items", row, ["schedule_date"]);
}
- },
+ }
- unhold_purchase_order: function(){
+ unhold_purchase_order(){
cur_frm.cscript.update_status("Resume", "Draft")
- },
+ }
- hold_purchase_order: function(){
+ hold_purchase_order(){
var me = this;
var d = new frappe.ui.Dialog({
title: __('Reason for Hold'),
@@ -523,28 +523,28 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
}
});
d.show();
- },
+ }
- unclose_purchase_order: function(){
+ unclose_purchase_order(){
cur_frm.cscript.update_status('Re-open', 'Submitted')
- },
+ }
- close_purchase_order: function(){
+ close_purchase_order(){
cur_frm.cscript.update_status('Close', 'Closed')
- },
+ }
- delivered_by_supplier: function(){
+ delivered_by_supplier(){
cur_frm.cscript.update_status('Deliver', 'Delivered')
- },
+ }
- items_on_form_rendered: function() {
- set_schedule_date(this.frm);
- },
-
- schedule_date: function() {
+ items_on_form_rendered() {
set_schedule_date(this.frm);
}
-});
+
+ schedule_date() {
+ set_schedule_date(this.frm);
+ }
+};
// for backward compatibility: combine new and previous states
$.extend(cur_frm.cscript, new erpnext.buying.PurchaseOrderController({frm: cur_frm}));
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
index b76c3784a4..ee0e1ef576 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
@@ -205,10 +205,10 @@ frappe.ui.form.on("Request for Quotation Supplier",{
})
-erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.extend({
- refresh: function() {
+erpnext.buying.RequestforQuotationController = class RequestforQuotationController extends erpnext.buying.BuyingController {
+ refresh() {
var me = this;
- this._super();
+ super.refresh();
if (this.frm.doc.docstatus===0) {
this.frm.add_custom_button(__('Material Request'),
function() {
@@ -302,17 +302,17 @@ erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.e
me.get_suppliers_button(me.frm);
}, __("Tools"));
}
- },
+ }
- calculate_taxes_and_totals: function() {
+ calculate_taxes_and_totals() {
return;
- },
+ }
- tc_name: function() {
+ tc_name() {
this.get_terms();
- },
+ }
- get_suppliers_button: function (frm) {
+ get_suppliers_button (frm) {
var doc = frm.doc;
var dialog = new frappe.ui.Dialog({
title: __("Get Suppliers"),
@@ -410,8 +410,8 @@ erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.e
});
dialog.show();
- },
-});
+ }
+};
// for backward compatibility: combine new and previous states
$.extend(cur_frm.cscript, new erpnext.buying.RequestforQuotationController({frm: cur_frm}));
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
index a0187b0a82..a3ba52e67b 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
@@ -4,19 +4,19 @@
// attach required files
{% include 'erpnext/public/js/controllers/buying.js' %};
-erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.extend({
- setup: function() {
+erpnext.buying.SupplierQuotationController = class SupplierQuotationController extends erpnext.buying.BuyingController {
+ setup() {
this.frm.custom_make_buttons = {
'Purchase Order': 'Purchase Order',
'Quotation': 'Quotation'
}
- this._super();
- },
+ super.setup();
+ }
- refresh: function() {
+ refresh() {
var me = this;
- this._super();
+ super.refresh();
if (this.frm.doc.__islocal && !this.frm.doc.valid_till) {
this.frm.set_value('valid_till', frappe.datetime.add_months(this.frm.doc.transaction_date, 1));
@@ -77,22 +77,22 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext
})
}, __("Get Items From"));
}
- },
+ }
- make_purchase_order: function() {
+ make_purchase_order() {
frappe.model.open_mapped_doc({
method: "erpnext.buying.doctype.supplier_quotation.supplier_quotation.make_purchase_order",
frm: cur_frm
})
- },
- make_quotation: function() {
+ }
+ make_quotation() {
frappe.model.open_mapped_doc({
method: "erpnext.buying.doctype.supplier_quotation.supplier_quotation.make_quotation",
frm: cur_frm
})
}
-});
+};
// for backward compatibility: combine new and previous states
$.extend(cur_frm.cscript, new erpnext.buying.SupplierQuotationController({frm: cur_frm}));
diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js
index 0c88d2826f..8dfee1d6c7 100644
--- a/erpnext/crm/doctype/lead/lead.js
+++ b/erpnext/crm/doctype/lead/lead.js
@@ -4,8 +4,8 @@
frappe.provide("erpnext");
cur_frm.email_field = "email_id";
-erpnext.LeadController = frappe.ui.form.Controller.extend({
- setup: function () {
+erpnext.LeadController = class LeadController extends frappe.ui.form.Controller {
+ setup () {
this.frm.make_methods = {
'Customer': this.make_customer,
'Quotation': this.make_quotation,
@@ -13,9 +13,9 @@ erpnext.LeadController = frappe.ui.form.Controller.extend({
};
this.frm.toggle_reqd("lead_name", !this.frm.doc.organization_lead);
- },
+ }
- onload: function () {
+ onload () {
this.frm.set_query("customer", function (doc, cdt, cdn) {
return { query: "erpnext.controllers.queries.customer_query" }
});
@@ -27,9 +27,9 @@ erpnext.LeadController = frappe.ui.form.Controller.extend({
this.frm.set_query("contact_by", function (doc, cdt, cdn) {
return { query: "frappe.core.doctype.user.user.user_query" }
});
- },
+ }
- refresh: function () {
+ refresh () {
let doc = this.frm.doc;
erpnext.toggle_naming_series();
frappe.dynamic_link = { doc: doc, fieldname: 'name', doctype: 'Lead' }
@@ -45,47 +45,47 @@ erpnext.LeadController = frappe.ui.form.Controller.extend({
} else {
frappe.contacts.clear_address_and_contact(this.frm);
}
- },
+ }
- make_customer: function () {
+ make_customer () {
frappe.model.open_mapped_doc({
method: "erpnext.crm.doctype.lead.lead.make_customer",
frm: cur_frm
})
- },
+ }
- make_opportunity: function () {
+ make_opportunity () {
frappe.model.open_mapped_doc({
method: "erpnext.crm.doctype.lead.lead.make_opportunity",
frm: cur_frm
})
- },
+ }
- make_quotation: function () {
+ make_quotation () {
frappe.model.open_mapped_doc({
method: "erpnext.crm.doctype.lead.lead.make_quotation",
frm: cur_frm
})
- },
+ }
- organization_lead: function () {
+ organization_lead () {
this.frm.toggle_reqd("lead_name", !this.frm.doc.organization_lead);
this.frm.toggle_reqd("company_name", this.frm.doc.organization_lead);
- },
+ }
- company_name: function () {
+ company_name () {
if (this.frm.doc.organization_lead && !this.frm.doc.lead_name) {
this.frm.set_value("lead_name", this.frm.doc.company_name);
}
- },
+ }
- contact_date: function () {
+ contact_date () {
if (this.frm.doc.contact_date) {
let d = moment(this.frm.doc.contact_date);
d.add(1, "day");
this.frm.set_value("ends_on", d.format(frappe.defaultDatetimeFormat));
}
}
-});
+};
$.extend(cur_frm.cscript, new erpnext.LeadController({ frm: cur_frm }));
diff --git a/erpnext/crm/doctype/opportunity/opportunity.js b/erpnext/crm/doctype/opportunity/opportunity.js
index ac374a95f4..925c30b451 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.js
+++ b/erpnext/crm/doctype/opportunity/opportunity.js
@@ -145,8 +145,8 @@ frappe.ui.form.on("Opportunity", {
})
// TODO commonify this code
-erpnext.crm.Opportunity = frappe.ui.form.Controller.extend({
- onload: function() {
+erpnext.crm.Opportunity = class Opportunity extends frappe.ui.form.Controller {
+ onload() {
if(!this.frm.doc.status) {
frm.set_value('status', 'Open');
@@ -159,9 +159,9 @@ erpnext.crm.Opportunity = frappe.ui.form.Controller.extend({
}
this.setup_queries();
- },
+ }
- setup_queries: function() {
+ setup_queries() {
var me = this;
if(this.frm.fields_dict.contact_by.df.options.match(/^User/)) {
@@ -185,15 +185,15 @@ erpnext.crm.Opportunity = frappe.ui.form.Controller.extend({
else if (me.frm.doc.opportunity_from == "Customer") {
me.frm.set_query('party_name', erpnext.queries['customer']);
}
- },
+ }
- create_quotation: function() {
+ create_quotation() {
frappe.model.open_mapped_doc({
method: "erpnext.crm.doctype.opportunity.opportunity.make_quotation",
frm: cur_frm
})
}
-});
+};
$.extend(cur_frm.cscript, new erpnext.crm.Opportunity({frm: cur_frm}));
diff --git a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js
index b59d848828..68e7780039 100644
--- a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js
+++ b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js
@@ -72,8 +72,8 @@ frappe.ui.form.on('Student Attendance Tool', {
});
-education.StudentsEditor = Class.extend({
- init: function(frm, wrapper, students) {
+education.StudentsEditor = class StudentsEditor {
+ constructor(frm, wrapper, students) {
this.wrapper = wrapper;
this.frm = frm;
if(students.length > 0) {
@@ -81,8 +81,8 @@ education.StudentsEditor = Class.extend({
} else {
this.show_empty_state();
}
- },
- make: function(frm, students) {
+ }
+ make(frm, students) {
var me = this;
$(this.wrapper).empty();
@@ -173,13 +173,13 @@ education.StudentsEditor = Class.extend({
});
$(htmls.join("")).appendTo(me.wrapper);
- },
+ }
- show_empty_state: function() {
+ show_empty_state() {
$(this.wrapper).html(
`
${__("No Students in")} ${this.frm.doc.student_group}
`
);
}
-});
+};
diff --git a/erpnext/healthcare/doctype/exercise_type/exercise_type.js b/erpnext/healthcare/doctype/exercise_type/exercise_type.js
index b49b00e219..06146047eb 100644
--- a/erpnext/healthcare/doctype/exercise_type/exercise_type.js
+++ b/erpnext/healthcare/doctype/exercise_type/exercise_type.js
@@ -9,14 +9,14 @@ frappe.ui.form.on('Exercise Type', {
}
});
-erpnext.ExerciseEditor = Class.extend({
- init: function(frm, wrapper) {
+erpnext.ExerciseEditor = class ExerciseEditor {
+ constructor(frm, wrapper) {
this.wrapper = wrapper;
this.frm = frm;
this.make(frm, wrapper);
- },
+ }
- make: function(frm, wrapper) {
+ make(frm, wrapper) {
$(this.wrapper).empty();
this.exercise_toolbar = $('\
@@ -38,9 +38,9 @@ erpnext.ExerciseEditor = Class.extend({
this.make_cards(frm);
this.make_buttons(frm);
}
- },
+ }
- make_cards: function(frm) {
+ make_cards(frm) {
var me = this;
$(me.exercise_cards).empty();
@@ -60,9 +60,9 @@ erpnext.ExerciseEditor = Class.extend({
`, {image_src: step.image, title: step.title, description: step.description, col_id: "col-"+i, card_id: "card-"+i, id: i})).appendTo(me.row);
});
- },
+ }
- make_buttons: function(frm) {
+ make_buttons(frm) {
let me = this;
$('.btn-edit').on('click', function() {
let id = $(this).attr('data-id');
@@ -82,9 +82,9 @@ erpnext.ExerciseEditor = Class.extend({
frm.dirty();
}, 300);
});
- },
+ }
- show_add_card_dialog: function(frm) {
+ show_add_card_dialog(frm) {
let me = this;
let d = new frappe.ui.Dialog({
title: __('Add Exercise Step'),
@@ -137,9 +137,9 @@ erpnext.ExerciseEditor = Class.extend({
primary_action_label: __('Add')
});
d.show();
- },
+ }
- show_edit_card_dialog: function(frm, id) {
+ show_edit_card_dialog(frm, id) {
let new_dialog = new frappe.ui.Dialog({
title: __("Edit Exercise Step"),
fields: [
@@ -183,4 +183,4 @@ erpnext.ExerciseEditor = Class.extend({
});
new_dialog.show();
}
-});
+};
diff --git a/erpnext/hr/doctype/employee/employee.js b/erpnext/hr/doctype/employee/employee.js
index c21d4b893c..5639cc9ea4 100755
--- a/erpnext/hr/doctype/employee/employee.js
+++ b/erpnext/hr/doctype/employee/employee.js
@@ -2,8 +2,8 @@
// License: GNU General Public License v3. See license.txt
frappe.provide("erpnext.hr");
-erpnext.hr.EmployeeController = frappe.ui.form.Controller.extend({
- setup: function() {
+erpnext.hr.EmployeeController = class EmployeeController extends frappe.ui.form.Controller {
+ setup() {
this.frm.fields_dict.user_id.get_query = function(doc, cdt, cdn) {
return {
query: "frappe.core.doctype.user.user.user_query",
@@ -12,30 +12,30 @@ erpnext.hr.EmployeeController = frappe.ui.form.Controller.extend({
}
this.frm.fields_dict.reports_to.get_query = function(doc, cdt, cdn) {
return { query: "erpnext.controllers.queries.employee_query"} }
- },
+ }
- refresh: function() {
+ refresh() {
var me = this;
erpnext.toggle_naming_series();
- },
+ }
- date_of_birth: function() {
+ date_of_birth() {
return cur_frm.call({
method: "get_retirement_date",
args: {date_of_birth: this.frm.doc.date_of_birth}
});
- },
+ }
- salutation: function() {
+ salutation() {
if(this.frm.doc.salutation) {
this.frm.set_value("gender", {
"Mr": "Male",
"Ms": "Female"
}[this.frm.doc.salutation]);
}
- },
+ }
-});
+};
frappe.ui.form.on('Employee',{
setup: function(frm) {
frm.set_query("leave_policy", function() {
diff --git a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js
index 3205a92b1b..ab965d54e3 100644
--- a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js
+++ b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js
@@ -68,13 +68,13 @@ erpnext.employee_attendance_tool = {
}
}
-erpnext.MarkedEmployee = Class.extend({
- init: function(frm, wrapper, employee) {
+erpnext.MarkedEmployee = class MarkedEmployee {
+ constructor(frm, wrapper, employee) {
this.wrapper = wrapper;
this.frm = frm;
this.make(frm, employee);
- },
- make: function(frm, employee) {
+ }
+ make(frm, employee) {
var me = this;
$(this.wrapper).empty();
@@ -104,16 +104,16 @@ erpnext.MarkedEmployee = Class.extend({
})).appendTo(row);
});
}
-});
+};
-erpnext.EmployeeSelector = Class.extend({
- init: function(frm, wrapper, employee) {
+erpnext.EmployeeSelector = class EmployeeSelector {
+ constructor(frm, wrapper, employee) {
this.wrapper = wrapper;
this.frm = frm;
this.make(frm, employee);
- },
- make: function(frm, employee) {
+ }
+ make(frm, employee) {
var me = this;
$(this.wrapper).empty();
@@ -266,6 +266,6 @@ erpnext.EmployeeSelector = Class.extend({
mark_employee_toolbar.appendTo($(this.wrapper));
}
-});
+};
diff --git a/erpnext/hr/doctype/upload_attendance/upload_attendance.js b/erpnext/hr/doctype/upload_attendance/upload_attendance.js
index 29aa85484a..bbafc82076 100644
--- a/erpnext/hr/doctype/upload_attendance/upload_attendance.js
+++ b/erpnext/hr/doctype/upload_attendance/upload_attendance.js
@@ -5,19 +5,19 @@
frappe.provide("erpnext.hr");
-erpnext.hr.AttendanceControlPanel = frappe.ui.form.Controller.extend({
- onload: function() {
+erpnext.hr.AttendanceControlPanel = class AttendanceControlPanel extends frappe.ui.form.Controller {
+ onload() {
this.frm.set_value("att_fr_date", frappe.datetime.get_today());
this.frm.set_value("att_to_date", frappe.datetime.get_today());
- },
+ }
- refresh: function() {
+ refresh() {
this.frm.disable_save();
this.show_upload();
this.setup_import_progress();
- },
+ }
- get_template:function() {
+ get_template() {
if(!this.frm.doc.att_fr_date || !this.frm.doc.att_to_date) {
frappe.msgprint(__("Attendance From Date and Attendance To Date is mandatory"));
return;
@@ -28,7 +28,7 @@ erpnext.hr.AttendanceControlPanel = frappe.ui.form.Controller.extend({
from_date: this.frm.doc.att_fr_date,
to_date: this.frm.doc.att_to_date,
});
- },
+ }
show_upload() {
var $wrapper = $(cur_frm.fields_dict.upload_html.wrapper).empty();
@@ -36,7 +36,7 @@ erpnext.hr.AttendanceControlPanel = frappe.ui.form.Controller.extend({
wrapper: $wrapper,
method: 'erpnext.hr.doctype.upload_attendance.upload_attendance.upload'
});
- },
+ }
setup_import_progress() {
var $log_wrapper = $(this.frm.fields_dict.import_log.wrapper).empty();
@@ -64,6 +64,6 @@ erpnext.hr.AttendanceControlPanel = frappe.ui.form.Controller.extend({
}
});
}
-})
+}
cur_frm.cscript = new erpnext.hr.AttendanceControlPanel({frm: cur_frm});
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
index ddbcdfde57..2adfaf45ef 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
@@ -45,8 +45,8 @@ frappe.ui.form.on('Maintenance Schedule', {
})
// TODO commonify this code
-erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({
- refresh: function() {
+erpnext.maintenance.MaintenanceSchedule = class MaintenanceSchedule extends frappe.ui.form.Controller {
+ refresh() {
frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
var me = this;
@@ -76,21 +76,21 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({
});
}, __('Create'));
}
- },
+ }
- start_date: function(doc, cdt, cdn) {
+ start_date(doc, cdt, cdn) {
this.set_no_of_visits(doc, cdt, cdn);
- },
+ }
- end_date: function(doc, cdt, cdn) {
+ end_date(doc, cdt, cdn) {
this.set_no_of_visits(doc, cdt, cdn);
- },
+ }
- periodicity: function(doc, cdt, cdn) {
+ periodicity(doc, cdt, cdn) {
this.set_no_of_visits(doc, cdt, cdn);
- },
+ }
- set_no_of_visits: function(doc, cdt, cdn) {
+ set_no_of_visits(doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
if (item.start_date && item.end_date && item.periodicity) {
@@ -112,8 +112,8 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({
var no_of_visits = cint(date_diff / days_in_period[item.periodicity]);
frappe.model.set_value(item.doctype, item.name, "no_of_visits", no_of_visits);
}
- },
-});
+ }
+};
$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceSchedule({frm: cur_frm}));
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
index 4cbb02a5b3..12dc59ccfc 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
@@ -41,8 +41,8 @@ frappe.ui.form.on('Maintenance Visit', {
})
// TODO commonify this code
-erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({
- refresh: function() {
+erpnext.maintenance.MaintenanceVisit = class MaintenanceVisit extends frappe.ui.form.Controller {
+ refresh() {
frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
var me = this;
@@ -96,7 +96,7 @@ erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({
})
}, __("Get Items From"));
}
- },
-});
+ }
+};
-$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({frm: cur_frm}));
\ No newline at end of file
+$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({frm: cur_frm}));
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index fbfd801a11..2b329448fb 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -357,16 +357,16 @@ frappe.ui.form.on("BOM", {
}
});
-erpnext.bom.BomController = erpnext.TransactionController.extend({
- conversion_rate: function(doc) {
+erpnext.bom.BomController = class BomController extends erpnext.TransactionController {
+ conversion_rate(doc) {
if(this.frm.doc.currency === this.get_company_currency()) {
this.frm.set_value("conversion_rate", 1.0);
} else {
erpnext.bom.update_cost(doc);
}
- },
+ }
- item_code: function(doc, cdt, cdn){
+ item_code(doc, cdt, cdn){
var scrap_items = false;
var child = locals[cdt][cdn];
if (child.doctype == 'BOM Scrap Item') {
@@ -378,19 +378,19 @@ erpnext.bom.BomController = erpnext.TransactionController.extend({
}
get_bom_material_detail(doc, cdt, cdn, scrap_items);
- },
+ }
- buying_price_list: function(doc) {
+ buying_price_list(doc) {
this.apply_price_list();
- },
+ }
- plc_conversion_rate: function(doc) {
+ plc_conversion_rate(doc) {
if (!this.in_apply_price_list) {
this.apply_price_list(null, true);
}
- },
+ }
- conversion_factor: function(doc, cdt, cdn) {
+ conversion_factor(doc, cdt, cdn) {
if (frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
var item = frappe.get_doc(cdt, cdn);
frappe.model.round_floats_in(item, ["qty", "conversion_factor"]);
@@ -399,8 +399,8 @@ erpnext.bom.BomController = erpnext.TransactionController.extend({
this.toggle_conversion_factor(item);
this.frm.events.update_cost(this.frm);
}
- },
-});
+ }
+};
$.extend(cur_frm.cscript, new erpnext.bom.BomController({frm: cur_frm}));
diff --git a/erpnext/public/js/account_tree_grid.js b/erpnext/public/js/account_tree_grid.js
index 757f33eecc..413a5ee971 100644
--- a/erpnext/public/js/account_tree_grid.js
+++ b/erpnext/public/js/account_tree_grid.js
@@ -14,9 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-erpnext.AccountTreeGrid = frappe.views.TreeGridReport.extend({
- init: function(wrapper, title) {
- this._super({
+erpnext.AccountTreeGrid = class AccountTreeGrid extends frappe.views.TreeGridReport {
+ constructor(wrapper, title) {
+ super({
title: title,
parent: $(wrapper).find('.layout-main'),
page: wrapper.page,
@@ -33,8 +33,24 @@ erpnext.AccountTreeGrid = frappe.views.TreeGridReport.extend({
}
},
});
- },
- setup_columns: function() {
+
+ this.filters = [
+ {fieldtype: "Select", label: __("Company"), link:"Company", fieldname: "company",
+ default_value: __("Select Company..."),
+ filter: function(val, item, opts, me) {
+ if (item.company == val || val == opts.default_value) {
+ return me.apply_zero_filter(val, item, opts, me);
+ }
+ return false;
+ }},
+ {fieldtype: "Select", label: "Fiscal Year", link:"Fiscal Year", fieldname: "fiscal_year",
+ default_value: __("Select Fiscal Year...")},
+ {fieldtype: "Date", label: __("From Date"), fieldname: "from_date"},
+ {fieldtype: "Label", label: __("To")},
+ {fieldtype: "Date", label: __("To Date"), fieldname: "to_date"}
+ ]
+ }
+ setup_columns() {
this.columns = [
{id: "name", name: __("Account"), field: "name", width: 300, cssClass: "cell-title"},
{id: "opening_dr", name: __("Opening (Dr)"), field: "opening_dr", width: 100,
@@ -50,25 +66,10 @@ erpnext.AccountTreeGrid = frappe.views.TreeGridReport.extend({
{id: "closing_cr", name: __("Closing (Cr)"), field: "closing_cr", width: 100,
formatter: this.currency_formatter}
];
+ }
- },
- filters: [
- {fieldtype: "Select", label: __("Company"), link:"Company", fieldname: "company",
- default_value: __("Select Company..."),
- filter: function(val, item, opts, me) {
- if (item.company == val || val == opts.default_value) {
- return me.apply_zero_filter(val, item, opts, me);
- }
- return false;
- }},
- {fieldtype: "Select", label: "Fiscal Year", link:"Fiscal Year", fieldname: "fiscal_year",
- default_value: __("Select Fiscal Year...")},
- {fieldtype: "Date", label: __("From Date"), fieldname: "from_date"},
- {fieldtype: "Label", label: __("To")},
- {fieldtype: "Date", label: __("To Date"), fieldname: "to_date"}
- ],
- setup_filters: function() {
- this._super();
+ setup_filters() {
+ super.setup_filters();
var me = this;
// default filters
this.filter_inputs.fiscal_year.change(function() {
@@ -83,8 +84,8 @@ erpnext.AccountTreeGrid = frappe.views.TreeGridReport.extend({
});
me.show_zero_check()
if(me.ignore_closing_entry) me.ignore_closing_entry();
- },
- prepare_data: function() {
+ }
+ prepare_data() {
var me = this;
if(!this.primary_data) {
// make accounts list
@@ -113,12 +114,12 @@ erpnext.AccountTreeGrid = frappe.views.TreeGridReport.extend({
this.set_indent();
this.prepare_balances();
- },
- init_account: function(d) {
+ }
+ init_account(d) {
this.reset_item_values(d);
- },
+ }
- prepare_balances: function() {
+ prepare_balances() {
var gl = frappe.report_dump.data['GL Entry'];
var me = this;
@@ -139,8 +140,8 @@ erpnext.AccountTreeGrid = frappe.views.TreeGridReport.extend({
});
this.update_groups();
- },
- update_balances: function(account, posting_date, v) {
+ }
+ update_balances(account, posting_date, v) {
// opening
if (posting_date < this.opening_date || v.is_opening === "Yes") {
if (account.report_type === "Profit and Loss" &&
@@ -161,8 +162,8 @@ erpnext.AccountTreeGrid = frappe.views.TreeGridReport.extend({
var closing_bal = flt(account.opening_dr) - flt(account.opening_cr) +
flt(account.debit) - flt(account.credit);
this.set_debit_or_credit(account, "closing", closing_bal);
- },
- set_debit_or_credit: function(account, field, balance) {
+ }
+ set_debit_or_credit(account, field, balance) {
if(balance > 0) {
account[field+"_dr"] = balance;
account[field+"_cr"] = 0;
@@ -170,8 +171,8 @@ erpnext.AccountTreeGrid = frappe.views.TreeGridReport.extend({
account[field+"_cr"] = Math.abs(balance);
account[field+"_dr"] = 0;
}
- },
- update_groups: function() {
+ }
+ update_groups() {
// update groups
var me= this;
$.each(this.data, function(i, account) {
@@ -202,9 +203,9 @@ erpnext.AccountTreeGrid = frappe.views.TreeGridReport.extend({
}
}
});
- },
+ }
- set_fiscal_year: function() {
+ set_fiscal_year() {
if (this.opening_date > this.closing_date) {
frappe.msgprint(__("Opening Date should be before Closing Date"));
return;
@@ -223,9 +224,9 @@ erpnext.AccountTreeGrid = frappe.views.TreeGridReport.extend({
frappe.msgprint(__("Opening Date and Closing Date should be within same Fiscal Year"));
return;
}
- },
+ }
- show_general_ledger: function(account) {
+ show_general_ledger(account) {
frappe.route_options = {
account: account,
company: this.company,
@@ -234,4 +235,4 @@ erpnext.AccountTreeGrid = frappe.views.TreeGridReport.extend({
};
frappe.set_route("query-report", "General Ledger");
}
-});
+};
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index 67b12fbca4..8ceae83620 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -9,14 +9,14 @@ cur_frm.cscript.tax_table = "Purchase Taxes and Charges";
cur_frm.email_field = "contact_email";
-erpnext.buying.BuyingController = erpnext.TransactionController.extend({
- setup: function() {
- this._super();
- },
+erpnext.buying.BuyingController = class BuyingController extends erpnext.TransactionController {
+ setup() {
+ super.setup();
+ }
- onload: function(doc, cdt, cdn) {
+ onload(doc, cdt, cdn) {
this.setup_queries(doc, cdt, cdn);
- this._super();
+ super.onload();
this.frm.set_query('shipping_rule', function() {
return {
@@ -48,9 +48,9 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
});
}
/* eslint-enable */
- },
+ }
- setup_queries: function(doc, cdt, cdn) {
+ setup_queries(doc, cdt, cdn) {
var me = this;
if(this.frm.fields_dict.buying_price_list) {
@@ -109,9 +109,9 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
return me.set_query_for_item_tax_template(doc, cdt, cdn)
});
}
- },
+ }
- refresh: function(doc) {
+ refresh(doc) {
frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'supplier', doctype: 'Supplier'};
this.frm.toggle_display("supplier_name",
@@ -122,38 +122,38 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
this.set_from_product_bundle();
}
- this._super();
- },
+ super.refresh();
+ }
- supplier: function() {
+ supplier() {
var me = this;
erpnext.utils.get_party_details(this.frm, null, null, function(){
me.apply_price_list();
});
- },
+ }
- supplier_address: function() {
+ supplier_address() {
erpnext.utils.get_address_display(this.frm);
erpnext.utils.set_taxes_from_address(this.frm, "supplier_address", "supplier_address", "supplier_address");
- },
+ }
- buying_price_list: function() {
+ buying_price_list() {
this.apply_price_list();
- },
+ }
- discount_percentage: function(doc, cdt, cdn) {
+ discount_percentage(doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
item.discount_amount = 0.0;
this.price_list_rate(doc, cdt, cdn);
- },
+ }
- discount_amount: function(doc, cdt, cdn) {
+ discount_amount(doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
item.discount_percentage = 0.0;
this.price_list_rate(doc, cdt, cdn);
- },
+ }
- qty: function(doc, cdt, cdn) {
+ qty(doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
if ((doc.doctype == "Purchase Receipt") || (doc.doctype == "Purchase Invoice" && (doc.update_stock || doc.is_return))) {
frappe.model.round_floats_in(item, ["qty", "received_qty"]);
@@ -168,22 +168,22 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
item.rejected_qty = flt(item.received_qty - item.qty, precision("rejected_qty", item));
item.received_stock_qty = flt(item.conversion_factor, precision("conversion_factor", item)) * flt(item.received_qty);
}
- this._super(doc, cdt, cdn);
- },
+ super.qty(doc, cdt, cdn);
+ }
- batch_no: function(doc, cdt, cdn) {
- this._super(doc, cdt, cdn);
- },
+ batch_no(doc, cdt, cdn) {
+ super.batch_no(doc, cdt, cdn);
+ }
- received_qty: function(doc, cdt, cdn) {
+ received_qty(doc, cdt, cdn) {
this.calculate_accepted_qty(doc, cdt, cdn)
- },
+ }
- rejected_qty: function(doc, cdt, cdn) {
+ rejected_qty(doc, cdt, cdn) {
this.calculate_accepted_qty(doc, cdt, cdn)
- },
+ }
- calculate_accepted_qty: function(doc, cdt, cdn){
+ calculate_accepted_qty(doc, cdt, cdn){
var item = frappe.get_doc(cdt, cdn);
frappe.model.round_floats_in(item, ["received_qty", "rejected_qty"]);
@@ -191,9 +191,9 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
item.qty = flt(item.received_qty - item.rejected_qty, precision("qty", item));
this.qty(doc, cdt, cdn);
- },
+ }
- validate_negative_quantity: function(cdt, cdn, item, fieldnames){
+ validate_negative_quantity(cdt, cdn, item, fieldnames){
if(!item || !fieldnames) { return }
var is_negative_qty = false;
@@ -206,9 +206,9 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
}
return is_negative_qty
- },
+ }
- warehouse: function(doc, cdt, cdn) {
+ warehouse(doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
if(item.item_code && item.warehouse) {
return this.frm.call({
@@ -220,9 +220,9 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
}
});
}
- },
+ }
- project: function(doc, cdt, cdn) {
+ project(doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
if(item.project) {
$.each(this.frm.doc["items"] || [],
@@ -233,48 +233,48 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
}
});
}
- },
+ }
- rejected_warehouse: function(doc, cdt) {
+ rejected_warehouse(doc, cdt) {
// trigger autofill_warehouse only if parent rejected_warehouse field is triggered
if (["Purchase Invoice", "Purchase Receipt"].includes(cdt)) {
this.autofill_warehouse(doc.items, "rejected_warehouse", doc.rejected_warehouse);
}
- },
+ }
- category: function(doc, cdt, cdn) {
+ category(doc, cdt, cdn) {
// should be the category field of tax table
if(cdt != doc.doctype) {
this.calculate_taxes_and_totals();
}
- },
- add_deduct_tax: function(doc, cdt, cdn) {
+ }
+ add_deduct_tax(doc, cdt, cdn) {
this.calculate_taxes_and_totals();
- },
+ }
- set_from_product_bundle: function() {
+ set_from_product_bundle() {
var me = this;
this.frm.add_custom_button(__("Product Bundle"), function() {
erpnext.buying.get_items_from_product_bundle(me.frm);
}, __("Get Items From"));
- },
+ }
- shipping_address: function(){
+ shipping_address(){
var me = this;
erpnext.utils.get_address_display(this.frm, "shipping_address",
"shipping_address_display", true);
- },
+ }
- billing_address: function() {
+ billing_address() {
erpnext.utils.get_address_display(this.frm, "billing_address",
"billing_address_display", true);
- },
+ }
- tc_name: function() {
+ tc_name() {
this.get_terms();
- },
+ }
- update_auto_repeat_reference: function(doc) {
+ update_auto_repeat_reference(doc) {
if (doc.auto_repeat) {
frappe.call({
method:"frappe.automation.doctype.auto_repeat.auto_repeat.update_reference",
@@ -291,9 +291,9 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
}
})
}
- },
+ }
- manufacturer: function(doc, cdt, cdn) {
+ manufacturer(doc, cdt, cdn) {
const row = locals[cdt][cdn];
if(row.manufacturer) {
@@ -310,9 +310,9 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
}
});
}
- },
+ }
- manufacturer_part_no: function(doc, cdt, cdn) {
+ manufacturer_part_no(doc, cdt, cdn) {
const row = locals[cdt][cdn];
if (row.manufacturer_part_no) {
@@ -335,7 +335,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
}
}
-});
+};
cur_frm.add_fetch('project', 'cost_center', 'cost_center');
@@ -496,4 +496,4 @@ erpnext.buying.get_items_from_product_bundle = function(frm) {
});
dialog.show();
-}
\ No newline at end of file
+}
diff --git a/erpnext/public/js/controllers/stock_controller.js b/erpnext/public/js/controllers/stock_controller.js
index 87b21b78de..d346357a8f 100644
--- a/erpnext/public/js/controllers/stock_controller.js
+++ b/erpnext/public/js/controllers/stock_controller.js
@@ -3,22 +3,22 @@
frappe.provide("erpnext.stock");
-erpnext.stock.StockController = frappe.ui.form.Controller.extend({
- onload: function() {
+erpnext.stock.StockController = class StockController extends frappe.ui.form.Controller {
+ onload() {
// warehouse query if company
if (this.frm.fields_dict.company) {
this.setup_warehouse_query();
}
- },
+ }
- setup_warehouse_query: function() {
+ setup_warehouse_query() {
var me = this;
erpnext.queries.setup_queries(this.frm, "Warehouse", function() {
return erpnext.queries.warehouse(me.frm.doc);
});
- },
+ }
- setup_posting_date_time_check: function() {
+ setup_posting_date_time_check() {
// make posting date default and read only unless explictly checked
frappe.ui.form.on(this.frm.doctype, 'set_posting_date_and_time_read_only', function(frm) {
if(frm.doc.docstatus == 0 && frm.doc.set_posting_time) {
@@ -46,9 +46,9 @@ erpnext.stock.StockController = frappe.ui.form.Controller.extend({
frm.trigger('set_posting_date_and_time_read_only');
}
});
- },
+ }
- show_stock_ledger: function() {
+ show_stock_ledger() {
var me = this;
if(this.frm.doc.docstatus > 0) {
cur_frm.add_custom_button(__("Stock Ledger"), function() {
@@ -63,9 +63,9 @@ erpnext.stock.StockController = frappe.ui.form.Controller.extend({
}, __("View"));
}
- },
+ }
- show_general_ledger: function() {
+ show_general_ledger() {
var me = this;
if(this.frm.doc.docstatus > 0) {
cur_frm.add_custom_button(__('Accounting Ledger'), function() {
@@ -81,4 +81,4 @@ erpnext.stock.StockController = frappe.ui.form.Controller.extend({
}, __("View"));
}
}
-});
+};
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 3a3ee3858b..448bb65364 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -1,12 +1,12 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-erpnext.taxes_and_totals = erpnext.payments.extend({
- setup: function() {
+erpnext.taxes_and_totals = class taxes_and_totals extends erpnext.payments {
+ setup() {
this.fetch_round_off_accounts();
- },
+ }
- apply_pricing_rule_on_item: function(item) {
+ apply_pricing_rule_on_item(item) {
let effective_item_rate = item.price_list_rate;
let item_rate = item.rate;
if (in_list(["Sales Order", "Quotation"], item.parenttype) && item.blanket_order_rate) {
@@ -32,9 +32,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
}
frappe.model.set_value(item.doctype, item.name, "rate", item_rate);
- },
+ }
- calculate_taxes_and_totals: function(update_paid_amount) {
+ calculate_taxes_and_totals(update_paid_amount) {
this.discount_amount_applied = false;
this._calculate_taxes_and_totals();
this.calculate_discount_amount();
@@ -63,16 +63,16 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
}
this.frm.refresh_fields();
- },
+ }
- calculate_discount_amount: function(){
+ calculate_discount_amount(){
if (frappe.meta.get_docfield(this.frm.doc.doctype, "discount_amount")) {
this.set_discount_amount();
this.apply_discount_amount();
}
- },
+ }
- _calculate_taxes_and_totals: function() {
+ _calculate_taxes_and_totals() {
this.validate_conversion_rate();
this.calculate_item_values();
this.initialize_taxes();
@@ -82,9 +82,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.manipulate_grand_total_for_inclusive_tax();
this.calculate_totals();
this._cleanup();
- },
+ }
- validate_conversion_rate: function() {
+ validate_conversion_rate() {
this.frm.doc.conversion_rate = flt(this.frm.doc.conversion_rate, (cur_frm) ? precision("conversion_rate") : 9);
var conversion_rate_label = frappe.meta.get_label(this.frm.doc.doctype, "conversion_rate",
this.frm.doc.name);
@@ -99,9 +99,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
frappe.throw(err_message);
}
}
- },
+ }
- calculate_item_values: function() {
+ calculate_item_values() {
var me = this;
if (!this.discount_amount_applied) {
$.each(this.frm.doc["items"] || [], function(i, item) {
@@ -121,16 +121,16 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
me.set_in_company_currency(item, ["price_list_rate", "rate", "amount", "net_rate", "net_amount"]);
});
}
- },
+ }
- set_in_company_currency: function(doc, fields) {
+ set_in_company_currency(doc, fields) {
var me = this;
$.each(fields, function(i, f) {
doc["base_"+f] = flt(flt(doc[f], precision(f, doc)) * me.frm.doc.conversion_rate, precision("base_" + f, doc));
});
- },
+ }
- initialize_taxes: function() {
+ initialize_taxes() {
var me = this;
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
@@ -152,9 +152,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
}
frappe.model.round_floats_in(tax);
});
- },
+ }
- fetch_round_off_accounts: function() {
+ fetch_round_off_accounts() {
let me = this;
frappe.flags.round_off_applicable_accounts = [];
@@ -170,9 +170,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
}
});
}
- },
+ }
- determine_exclusive_rate: function() {
+ determine_exclusive_rate() {
var me = this;
var has_inclusive_tax = false;
@@ -210,9 +210,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
me.set_in_company_currency(item, ["net_rate", "net_amount"]);
}
});
- },
+ }
- get_current_tax_fraction: function(tax, item_tax_map) {
+ get_current_tax_fraction(tax, item_tax_map) {
// Get tax fraction for calculating tax exclusive amount
// from tax inclusive amount
var current_tax_fraction = 0.0;
@@ -241,14 +241,14 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
inclusive_tax_amount_per_qty *= -1;
}
return [current_tax_fraction, inclusive_tax_amount_per_qty];
- },
+ }
- _get_tax_rate: function(tax, item_tax_map) {
+ _get_tax_rate(tax, item_tax_map) {
return (Object.keys(item_tax_map).indexOf(tax.account_head) != -1) ?
flt(item_tax_map[tax.account_head], precision("rate", tax)) : tax.rate;
- },
+ }
- calculate_net_total: function() {
+ calculate_net_total() {
var me = this;
this.frm.doc.total_qty = this.frm.doc.total = this.frm.doc.base_total = this.frm.doc.net_total = this.frm.doc.base_net_total = 0.0;
@@ -261,9 +261,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
});
frappe.model.round_floats_in(this.frm.doc, ["total", "base_total", "net_total", "base_net_total"]);
- },
+ }
- calculate_taxes: function() {
+ calculate_taxes() {
var me = this;
this.frm.doc.rounding_adjustment = 0;
var actual_tax_dict = {};
@@ -339,9 +339,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
}
});
});
- },
+ }
- set_cumulative_total: function(row_idx, tax) {
+ set_cumulative_total(row_idx, tax) {
var tax_amount = tax.tax_amount_after_discount_amount;
if (tax.category == 'Valuation') {
tax_amount = 0;
@@ -354,13 +354,13 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
} else {
tax.total = flt(this.frm.doc["taxes"][row_idx-1].total + tax_amount, precision("total", tax));
}
- },
+ }
- _load_item_tax_rate: function(item_tax_rate) {
+ _load_item_tax_rate(item_tax_rate) {
return item_tax_rate ? JSON.parse(item_tax_rate) : {};
- },
+ }
- get_current_tax_amount: function(item, tax, item_tax_map) {
+ get_current_tax_amount(item, tax, item_tax_map) {
var tax_rate = this._get_tax_rate(tax, item_tax_map);
var current_tax_amount = 0.0;
@@ -397,17 +397,17 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.set_item_wise_tax(item, tax, tax_rate, current_tax_amount);
return current_tax_amount;
- },
+ }
- get_final_tax_amount: function(tax, current_tax_amount) {
+ get_final_tax_amount(tax, current_tax_amount) {
if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
current_tax_amount = Math.round(current_tax_amount);
}
return current_tax_amount;
- },
+ }
- set_item_wise_tax: function(item, tax, tax_rate, current_tax_amount) {
+ set_item_wise_tax(item, tax, tax_rate, current_tax_amount) {
// store tax breakup for each item
let tax_detail = tax.item_wise_tax_detail;
let key = item.item_code || item.item_name;
@@ -417,14 +417,14 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
item_wise_tax_amount += tax_detail[key][1];
tax_detail[key] = [tax_rate, flt(item_wise_tax_amount, precision("base_tax_amount", tax))];
- },
+ }
- round_off_totals: function(tax) {
+ round_off_totals(tax) {
tax.tax_amount = flt(tax.tax_amount, precision("tax_amount", tax));
tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount, precision("tax_amount", tax));
- },
+ }
- manipulate_grand_total_for_inclusive_tax: function() {
+ manipulate_grand_total_for_inclusive_tax() {
var me = this;
// if fully inclusive taxes and diff
if (this.frm.doc["taxes"] && this.frm.doc["taxes"].length) {
@@ -455,9 +455,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
}
}
}
- },
+ }
- calculate_totals: function() {
+ calculate_totals() {
// Changing sequence can cause rounding_adjustmentng issue and on-screen discrepency
var me = this;
var tax_count = this.frm.doc["taxes"] ? this.frm.doc["taxes"].length : 0;
@@ -503,9 +503,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
// rounded totals
this.set_rounded_total();
- },
+ }
- set_rounded_total: function() {
+ set_rounded_total() {
var disable_rounded_total = 0;
if(frappe.meta.get_docfield(this.frm.doc.doctype, "disable_rounded_total", this.frm.doc.name)) {
disable_rounded_total = this.frm.doc.disable_rounded_total;
@@ -527,9 +527,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.set_in_company_currency(this.frm.doc, ["rounding_adjustment", "rounded_total"]);
}
- },
+ }
- _cleanup: function() {
+ _cleanup() {
this.frm.doc.base_in_words = this.frm.doc.in_words = "";
if(this.frm.doc["items"] && this.frm.doc["items"].length) {
@@ -556,16 +556,16 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail);
});
}
- },
+ }
- set_discount_amount: function() {
+ set_discount_amount() {
if(this.frm.doc.additional_discount_percentage) {
this.frm.doc.discount_amount = flt(flt(this.frm.doc[frappe.scrub(this.frm.doc.apply_discount_on)])
* this.frm.doc.additional_discount_percentage / 100, precision("discount_amount"));
}
- },
+ }
- apply_discount_amount: function() {
+ apply_discount_amount() {
var me = this;
var distributed_amount = 0.0;
this.frm.doc.base_discount_amount = 0.0;
@@ -603,9 +603,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this._calculate_taxes_and_totals();
}
}
- },
+ }
- get_total_for_discount_amount: function() {
+ get_total_for_discount_amount() {
if(this.frm.doc.apply_discount_on == "Net Total") {
return this.frm.doc.net_total;
} else {
@@ -629,27 +629,27 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
return flt(this.frm.doc.grand_total - total_actual_tax, precision("grand_total"));
}
- },
+ }
- calculate_total_advance: function(update_paid_amount) {
+ calculate_total_advance(update_paid_amount) {
var total_allocated_amount = frappe.utils.sum($.map(this.frm.doc["advances"] || [], function(adv) {
return flt(adv.allocated_amount, precision("allocated_amount", adv));
}));
this.frm.doc.total_advance = flt(total_allocated_amount, precision("total_advance"));
this.calculate_outstanding_amount(update_paid_amount);
- },
+ }
- is_internal_invoice: function() {
+ is_internal_invoice() {
if (['Sales Invoice', 'Purchase Invoice'].includes(this.frm.doc.doctype)) {
if (this.frm.doc.company === this.frm.doc.represents_company) {
return true;
}
}
return false;
- },
+ }
- calculate_outstanding_amount: function(update_paid_amount) {
+ calculate_outstanding_amount(update_paid_amount) {
// NOTE:
// paid_amount and write_off_amount is only for POS/Loyalty Point Redemption Invoice
// total_advance is only for non POS Invoice
@@ -697,9 +697,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.frm.doc.outstanding_amount = flt(total_amount_to_pay - flt(paid_amount) +
flt(this.frm.doc.change_amount * this.frm.doc.conversion_rate), precision("outstanding_amount"));
}
- },
+ }
- update_paid_amount_for_return: function() {
+ update_paid_amount_for_return() {
var grand_total = this.frm.doc.rounded_total || this.frm.doc.grand_total;
if(this.frm.doc.party_account_currency == this.frm.doc.currency) {
@@ -723,9 +723,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.frm.refresh_fields();
this.calculate_paid_amount();
- },
+ }
- set_default_payment: function(total_amount_to_pay, update_paid_amount) {
+ set_default_payment(total_amount_to_pay, update_paid_amount) {
var me = this;
var payment_status = true;
if(this.frm.doc.is_pos && (update_paid_amount===undefined || update_paid_amount)) {
@@ -741,9 +741,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
}
});
}
- },
+ }
- calculate_paid_amount: function() {
+ calculate_paid_amount() {
var me = this;
var paid_amount = 0.0;
var base_paid_amount = 0.0;
@@ -763,9 +763,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.frm.set_value('paid_amount', flt(paid_amount, precision("paid_amount")));
this.frm.set_value('base_paid_amount', flt(base_paid_amount, precision("base_paid_amount")));
- },
+ }
- calculate_change_amount: function(){
+ calculate_change_amount(){
this.frm.doc.change_amount = 0.0;
this.frm.doc.base_change_amount = 0.0;
if(in_list(["Sales Invoice", "POS Invoice"], this.frm.doc.doctype)
@@ -784,9 +784,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
precision("base_change_amount"));
}
}
- },
+ }
- calculate_write_off_amount: function(){
+ calculate_write_off_amount(){
if(this.frm.doc.paid_amount > this.frm.doc.grand_total){
this.frm.doc.write_off_amount = flt(this.frm.doc.grand_total - this.frm.doc.paid_amount
+ this.frm.doc.change_amount, precision("write_off_amount"));
@@ -798,4 +798,4 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
}
this.calculate_outstanding_amount(false);
}
-});
+};
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 1c0abdffcf..a4c165e9ee 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -3,9 +3,9 @@
frappe.provide('erpnext.accounts.dimensions');
-erpnext.TransactionController = erpnext.taxes_and_totals.extend({
- setup: function() {
- this._super();
+erpnext.TransactionController = class TransactionController extends erpnext.taxes_and_totals {
+ setup() {
+ super.setup();
frappe.flags.hide_serial_batch_dialog = true;
frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
@@ -222,8 +222,8 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
});
}
- },
- onload: function() {
+ }
+ onload() {
var me = this;
if(this.frm.doc.__islocal) {
@@ -249,15 +249,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
]);
}
- },
+ }
- is_return: function() {
+ is_return() {
if(!this.frm.doc.is_return && this.frm.doc.return_against) {
this.frm.set_value('return_against', '');
}
- },
+ }
- setup_quality_inspection: function() {
+ setup_quality_inspection() {
if(!in_list(["Delivery Note", "Sales Invoice", "Purchase Receipt", "Purchase Invoice"], this.frm.doc.doctype)) {
return;
}
@@ -290,9 +290,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
}
});
- },
+ }
- make_payment_request: function() {
+ make_payment_request() {
var me = this;
const payment_request_type = (in_list(['Sales Order', 'Sales Invoice'], this.frm.doc.doctype))
? "Inward" : "Outward";
@@ -314,9 +314,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
}
})
- },
+ }
- onload_post_render: function() {
+ onload_post_render() {
if(this.frm.doc.__islocal && !(this.frm.doc.taxes || []).length
&& !(this.frm.doc.__onload ? this.frm.doc.__onload.load_after_mapping : false)) {
frappe.after_ajax(() => this.apply_default_taxes());
@@ -328,9 +328,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
this.setup_item_selector();
this.frm.get_field("items").grid.set_multiple_add("item_code", "qty");
}
- },
+ }
- refresh: function() {
+ refresh() {
erpnext.toggle_naming_series();
erpnext.hide_company();
this.set_dynamic_labels();
@@ -360,9 +360,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
.appendTo($input_group);
}
}
- },
+ }
- scan_barcode: function() {
+ scan_barcode() {
let scan_barcode_field = this.frm.fields_dict["scan_barcode"];
let show_description = function(idx, exist = null) {
@@ -434,9 +434,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
});
}
return false;
- },
+ }
- apply_default_taxes: function() {
+ apply_default_taxes() {
var me = this;
var taxes_and_charges_field = frappe.meta.get_docfield(me.frm.doc.doctype, "taxes_and_charges",
me.frm.doc.name);
@@ -475,22 +475,22 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
});
}
- },
+ }
- setup_sms: function() {
+ setup_sms() {
var me = this;
let blacklist = ['Purchase Invoice', 'BOM'];
if(this.frm.doc.docstatus===1 && !in_list(["Lost", "Stopped", "Closed"], this.frm.doc.status)
&& !blacklist.includes(this.frm.doctype)) {
this.frm.page.add_menu_item(__('Send SMS'), function() { me.send_sms(); });
}
- },
+ }
- send_sms: function() {
+ send_sms() {
var sms_man = new erpnext.SMSManager(this.frm.doc);
- },
+ }
- barcode: function(doc, cdt, cdn) {
+ barcode(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if(d.barcode=="" || d.barcode==null) {
// barcode cleared, remove item
@@ -499,9 +499,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
this.frm.from_barcode = this.frm.from_barcode ? this.frm.from_barcode + 1 : 1;
this.item_code(doc, cdt, cdn);
- },
+ }
- item_code: function(doc, cdt, cdn) {
+ item_code(doc, cdt, cdn) {
var me = this;
var item = frappe.get_doc(cdt, cdn);
var update_stock = 0, show_batch_dialog = 0;
@@ -647,9 +647,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
});
}
}
- },
+ }
- price_list_rate: function(doc, cdt, cdn) {
+ price_list_rate(doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
frappe.model.round_floats_in(item, ["price_list_rate", "discount_percentage"]);
@@ -661,17 +661,17 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
precision("rate", item));
this.calculate_taxes_and_totals();
- },
+ }
- margin_rate_or_amount: function(doc, cdt, cdn) {
+ margin_rate_or_amount(doc, cdt, cdn) {
// calculated the revised total margin and rate on margin rate changes
let item = frappe.get_doc(cdt, cdn);
this.apply_pricing_rule_on_item(item);
this.calculate_taxes_and_totals();
cur_frm.refresh_fields();
- },
+ }
- margin_type: function(doc, cdt, cdn) {
+ margin_type(doc, cdt, cdn) {
// calculate the revised total margin and rate on margin type changes
let item = frappe.get_doc(cdt, cdn);
if (!item.margin_type) {
@@ -681,9 +681,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
this.calculate_taxes_and_totals();
cur_frm.refresh_fields();
}
- },
+ }
- get_incoming_rate: function(item, posting_date, posting_time, voucher_type, company) {
+ get_incoming_rate(item, posting_date, posting_time, voucher_type, company) {
let item_args = {
'item_code': item.item_code,
@@ -706,9 +706,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
frappe.model.set_value(item.doctype, item.name, 'rate', r.message * item.conversion_factor);
}
});
- },
+ }
- add_taxes_from_item_tax_template: function(item_tax_map) {
+ add_taxes_from_item_tax_template(item_tax_map) {
let me = this;
if(item_tax_map && cint(frappe.defaults.get_default("add_taxes_from_item_tax_template"))) {
@@ -726,9 +726,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
});
}
- },
+ }
- serial_no: function(doc, cdt, cdn) {
+ serial_no(doc, cdt, cdn) {
var me = this;
var item = frappe.get_doc(cdt, cdn);
@@ -763,17 +763,17 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
}
}
- },
+ }
- validate: function() {
+ validate() {
this.calculate_taxes_and_totals(false);
- },
+ }
- update_stock: function() {
+ update_stock() {
this.frm.trigger('set_default_internal_warehouse');
- },
+ }
- set_default_internal_warehouse: function() {
+ set_default_internal_warehouse() {
let me = this;
if ((this.frm.doc.doctype === 'Sales Invoice' && me.frm.doc.update_stock)
|| this.frm.doc.doctype == 'Delivery Note') {
@@ -792,9 +792,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
});
}
}
- },
+ }
- company: function() {
+ company() {
var me = this;
var set_pricing = function() {
if(me.frm.doc.company && me.frm.fields_dict.currency) {
@@ -901,16 +901,16 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
if(this.frm.doc.company) {
erpnext.last_selected_company = this.frm.doc.company;
}
- },
+ }
- transaction_date: function() {
+ transaction_date() {
if (this.frm.doc.transaction_date) {
this.frm.transaction_date = this.frm.doc.transaction_date;
frappe.ui.form.trigger(this.frm.doc.doctype, "currency");
}
- },
+ }
- posting_date: function() {
+ posting_date() {
var me = this;
if (this.frm.doc.posting_date) {
this.frm.posting_date = this.frm.doc.posting_date;
@@ -939,9 +939,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
frappe.ui.form.trigger(me.frm.doc.doctype, "currency");
}
}
- },
+ }
- due_date: function() {
+ due_date() {
// due_date is to be changed, payment terms template and/or payment schedule must
// be removed as due_date is automatically changed based on payment terms
if (this.frm.doc.due_date && !this.frm.updating_party_details && !this.frm.doc.is_pos) {
@@ -964,13 +964,13 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
frappe.msgprint(final_message);
}
}
- },
+ }
- bill_date: function() {
+ bill_date() {
this.posting_date();
- },
+ }
- recalculate_terms: function() {
+ recalculate_terms() {
const doc = this.frm.doc;
if (doc.payment_terms_template) {
this.payment_terms_template();
@@ -989,17 +989,17 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
);
}
- },
+ }
- get_company_currency: function() {
+ get_company_currency() {
return erpnext.get_currency(this.frm.doc.company);
- },
+ }
- contact_person: function() {
+ contact_person() {
erpnext.utils.get_contact_details(this.frm);
- },
+ }
- currency: function() {
+ currency() {
/* manqala 19/09/2016: let the translation date be whichever of the transaction_date or posting_date is available */
var transaction_date = this.frm.doc.transaction_date || this.frm.doc.posting_date;
/* end manqala */
@@ -1021,9 +1021,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
} else {
this.conversion_rate();
}
- },
+ }
- conversion_rate: function() {
+ conversion_rate() {
const me = this.frm;
if(this.frm.doc.currency === this.get_company_currency()) {
this.frm.set_value("conversion_rate", 1.0);
@@ -1043,9 +1043,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
// Make read only if Accounts Settings doesn't allow stale rates
this.frm.set_df_property("conversion_rate", "read_only", erpnext.stale_rate_allowed() ? 0 : 1);
- },
+ }
- shipping_rule: function() {
+ shipping_rule() {
var me = this;
if(this.frm.doc.shipping_rule) {
return this.frm.call({
@@ -1061,9 +1061,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
else {
me.calculate_taxes_and_totals();
}
- },
+ }
- set_margin_amount_based_on_currency: function(exchange_rate) {
+ set_margin_amount_based_on_currency(exchange_rate) {
if (in_list(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice", "Purchase Invoice", "Purchase Order", "Purchase Receipt"]), this.frm.doc.doctype) {
var me = this;
$.each(this.frm.doc.items || [], function(i, d) {
@@ -1073,9 +1073,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
});
}
- },
+ }
- set_actual_charges_based_on_currency: function(exchange_rate) {
+ set_actual_charges_based_on_currency(exchange_rate) {
var me = this;
$.each(this.frm.doc.taxes || [], function(i, d) {
if(d.charge_type == "Actual") {
@@ -1083,9 +1083,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
flt(d.tax_amount) / flt(exchange_rate));
}
});
- },
+ }
- get_exchange_rate: function(transaction_date, from_currency, to_currency, callback) {
+ get_exchange_rate(transaction_date, from_currency, to_currency, callback) {
var args;
if (["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"].includes(this.frm.doctype)) {
args = "for_selling";
@@ -1107,9 +1107,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
callback(flt(r.message));
}
});
- },
+ }
- price_list_currency: function() {
+ price_list_currency() {
var me=this;
this.set_dynamic_labels();
@@ -1123,9 +1123,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
} else {
this.plc_conversion_rate();
}
- },
+ }
- plc_conversion_rate: function() {
+ plc_conversion_rate() {
if(this.frm.doc.price_list_currency === this.get_company_currency()) {
this.frm.set_value("plc_conversion_rate", 1.0);
} else if(this.frm.doc.price_list_currency === this.frm.doc.currency
@@ -1137,9 +1137,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
if(!this.in_apply_price_list) {
this.apply_price_list(null, true);
}
- },
+ }
- uom: function(doc, cdt, cdn) {
+ uom(doc, cdt, cdn) {
var me = this;
var item = frappe.get_doc(cdt, cdn);
if(item.item_code && item.uom) {
@@ -1157,9 +1157,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
});
}
me.calculate_stock_uom_rate(doc, cdt, cdn);
- },
+ }
- conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
+ conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate) {
if(frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
var item = frappe.get_doc(cdt, cdn);
frappe.model.round_floats_in(item, ["qty", "conversion_factor"]);
@@ -1179,35 +1179,35 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
this.calculate_stock_uom_rate(doc, cdt, cdn);
}
- },
+ }
- batch_no: function(doc, cdt, cdn) {
+ batch_no(doc, cdt, cdn) {
let item = frappe.get_doc(cdt, cdn);
this.apply_price_list(item, true);
- },
+ }
- toggle_conversion_factor: function(item) {
+ toggle_conversion_factor(item) {
// toggle read only property for conversion factor field if the uom and stock uom are same
if(this.frm.get_field('items').grid.fields_map.conversion_factor) {
this.frm.fields_dict.items.grid.toggle_enable("conversion_factor",
((item.uom != item.stock_uom) && !frappe.meta.get_docfield(cur_frm.fields_dict.items.grid.doctype, "conversion_factor").read_only)? true: false);
}
- },
+ }
- qty: function(doc, cdt, cdn) {
+ qty(doc, cdt, cdn) {
let item = frappe.get_doc(cdt, cdn);
this.conversion_factor(doc, cdt, cdn, true);
this.calculate_stock_uom_rate(doc, cdt, cdn);
this.apply_pricing_rule(item, true);
- },
+ }
- calculate_stock_uom_rate: function(doc, cdt, cdn) {
+ calculate_stock_uom_rate(doc, cdt, cdn) {
let item = frappe.get_doc(cdt, cdn);
- item.stock_uom_rate = flt(item.rate)/flt(item.conversion_factor);
+ item.stock_uom_rate = flt(item.rate)/flt(item.conversion_factor);
refresh_field("stock_uom_rate", item.name, item.parentfield);
- },
- service_stop_date: function(frm, cdt, cdn) {
+ }
+ service_stop_date(frm, cdt, cdn) {
var child = locals[cdt][cdn];
if(child.service_stop_date) {
@@ -1223,9 +1223,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
frappe.throw(__("Service Stop Date cannot be after Service End Date"));
}
}
- },
+ }
- service_start_date: function(frm, cdt, cdn) {
+ service_start_date(frm, cdt, cdn) {
var child = locals[cdt][cdn];
if(child.service_start_date) {
@@ -1237,9 +1237,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
})
}
- },
+ }
- calculate_net_weight: function(){
+ calculate_net_weight(){
/* Calculate Total Net Weight then further applied shipping rule to calculate shipping charges.*/
var me = this;
this.frm.doc.total_net_weight= 0.0;
@@ -1249,9 +1249,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
});
refresh_field("total_net_weight");
this.shipping_rule();
- },
+ }
- set_dynamic_labels: function() {
+ set_dynamic_labels() {
// What TODO? should we make price list system non-mandatory?
this.frm.toggle_reqd("plc_conversion_rate",
!!(this.frm.doc.price_list_name && this.frm.doc.price_list_currency));
@@ -1260,9 +1260,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
this.change_form_labels(company_currency);
this.change_grid_labels(company_currency);
this.frm.refresh_fields();
- },
+ }
- change_form_labels: function(company_currency) {
+ change_form_labels(company_currency) {
var me = this;
this.frm.set_currency_labels(["base_total", "base_net_total", "base_total_taxes_and_charges",
@@ -1309,9 +1309,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
if(frappe.meta.get_docfield(cur_frm.doctype, "base_net_total"))
cur_frm.toggle_display("base_net_total", (show && (me.frm.doc.currency != company_currency)));
- },
+ }
- change_grid_labels: function(company_currency) {
+ change_grid_labels(company_currency) {
var me = this;
this.frm.set_currency_labels(["base_rate", "base_net_rate", "base_price_list_rate", "base_amount", "base_net_amount", "base_rate_with_margin"],
@@ -1375,21 +1375,21 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
// set labels
var $wrapper = $(this.frm.wrapper);
- },
+ }
- recalculate: function() {
+ recalculate() {
this.calculate_taxes_and_totals();
- },
+ }
- recalculate_values: function() {
+ recalculate_values() {
this.calculate_taxes_and_totals();
- },
+ }
- calculate_charges: function() {
+ calculate_charges() {
this.calculate_taxes_and_totals();
- },
+ }
- ignore_pricing_rule: function() {
+ ignore_pricing_rule() {
if(this.frm.doc.ignore_pricing_rule) {
var me = this;
var item_list = [];
@@ -1423,9 +1423,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
} else {
this.apply_pricing_rule();
}
- },
+ }
- apply_pricing_rule: function(item, calculate_taxes_and_totals) {
+ apply_pricing_rule(item, calculate_taxes_and_totals) {
var me = this;
var args = this._get_args(item);
if (!(args.items && args.items.length)) {
@@ -1444,9 +1444,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
}
});
- },
+ }
- _get_args: function(item) {
+ _get_args(item) {
var me = this;
return {
"items": this._get_item_list(item),
@@ -1474,9 +1474,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
"pos_profile": me.frm.doc.doctype == 'Sales Invoice' ? me.frm.doc.pos_profile : '',
"coupon_code": me.frm.doc.coupon_code
};
- },
+ }
- _get_item_list: function(item) {
+ _get_item_list(item) {
var item_list = [];
var append_item = function(d) {
if (d.item_code) {
@@ -1517,9 +1517,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
});
}
return item_list;
- },
+ }
- _set_values_for_item_list: function(children) {
+ _set_values_for_item_list(children) {
var me = this;
var price_list_rate_changed = false;
var items_rule_dict = {};
@@ -1556,9 +1556,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
me.apply_rule_on_other_items(items_rule_dict);
if(!price_list_rate_changed) me.calculate_taxes_and_totals();
- },
+ }
- apply_rule_on_other_items: function(args) {
+ apply_rule_on_other_items(args) {
const me = this;
const fields = ["discount_percentage", "pricing_rules", "discount_amount", "rate"];
@@ -1577,9 +1577,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
});
}
}
- },
+ }
- apply_product_discount: function(free_item_data) {
+ apply_product_discount(free_item_data) {
const items = this.frm.doc.items.filter(d => (d.item_code == free_item_data.item_code
&& d.is_free_item)) || [];
@@ -1593,9 +1593,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
} if (items && items.length && free_item_data) {
items[0].qty = free_item_data.qty
}
- },
+ }
- apply_price_list: function(item, reset_plc_conversion) {
+ apply_price_list(item, reset_plc_conversion) {
// We need to reset plc_conversion_rate sometimes because the call to
// `erpnext.stock.get_item_details.apply_price_list` is sensitive to its value
if (!reset_plc_conversion) {
@@ -1634,9 +1634,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}).always(() => {
me.in_apply_price_list = false;
});
- },
+ }
- remove_pricing_rule: function(item) {
+ remove_pricing_rule(item) {
let me = this;
const fields = ["discount_percentage",
"discount_amount", "margin_rate_or_amount", "rate_with_margin"];
@@ -1670,18 +1670,18 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
me.trigger_price_list_rate();
}
- },
+ }
- trigger_price_list_rate: function() {
+ trigger_price_list_rate() {
var me = this;
this.frm.doc.items.forEach(child_row => {
me.frm.script_manager.trigger("price_list_rate",
child_row.doctype, child_row.name);
})
- },
+ }
- validate_company_and_party: function() {
+ validate_company_and_party() {
var me = this;
var valid = true;
@@ -1696,9 +1696,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
});
return valid;
- },
+ }
- get_terms: function() {
+ get_terms() {
var me = this;
erpnext.utils.get_terms(this.frm.doc.tc_name, this.frm.doc, function(r) {
@@ -1706,9 +1706,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
me.frm.set_value("terms", r.message);
}
});
- },
+ }
- taxes_and_charges: function() {
+ taxes_and_charges() {
var me = this;
if(this.frm.doc.taxes_and_charges) {
return this.frm.call({
@@ -1734,9 +1734,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
});
}
- },
+ }
- tax_category: function() {
+ tax_category() {
var me = this;
if(me.frm.updating_party_details) return;
@@ -1744,9 +1744,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
() => this.update_item_tax_map(),
() => erpnext.utils.set_taxes(this.frm, "tax_category"),
]);
- },
+ }
- item_tax_template: function(doc, cdt, cdn) {
+ item_tax_template(doc, cdt, cdn) {
var me = this;
if(me.frm.updating_party_details) return;
@@ -1772,9 +1772,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
item.item_tax_rate = "{}";
me.calculate_taxes_and_totals();
}
- },
+ }
- update_item_tax_map: function() {
+ update_item_tax_map() {
var me = this;
var item_codes = [];
$.each(this.frm.doc.items || [], function(i, item) {
@@ -1810,9 +1810,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
});
}
- },
+ }
- is_recurring: function() {
+ is_recurring() {
// set default values for recurring documents
if(this.frm.doc.is_recurring && this.frm.doc.__islocal) {
frappe.msgprint(__("Please set recurring after saving"));
@@ -1835,9 +1835,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
refresh_many(["notification_email_address", "repeat_on_day_of_month"]);
- },
+ }
- from_date: function() {
+ from_date() {
// set to_date
if(this.frm.doc.from_date) {
var recurring_type_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6,
@@ -1851,25 +1851,25 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
refresh_field('to_date');
}
}
- },
+ }
- set_gross_profit: function(item) {
+ set_gross_profit(item) {
if (["Sales Order", "Quotation"].includes(this.frm.doc.doctype) && item.valuation_rate) {
var rate = flt(item.rate) * flt(this.frm.doc.conversion_rate || 1);
item.gross_profit = flt(((rate - item.valuation_rate) * item.stock_qty), precision("amount", item));
}
- },
+ }
- setup_item_selector: function() {
+ setup_item_selector() {
// TODO: remove item selector
return;
// if(!this.item_selector) {
// this.item_selector = new erpnext.ItemSelector({frm: this.frm});
// }
- },
+ }
- get_advances: function() {
+ get_advances() {
if(!this.frm.is_return) {
return this.frm.call({
method: "set_advances",
@@ -1879,9 +1879,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
})
}
- },
+ }
- make_payment_entry: function() {
+ make_payment_entry() {
return frappe.call({
method: cur_frm.cscript.get_method_for_payment(),
args: {
@@ -1894,9 +1894,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
// cur_frm.refresh_fields()
}
});
- },
+ }
- get_method_for_payment: function(){
+ get_method_for_payment(){
var method = "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry";
if(cur_frm.doc.__onload && cur_frm.doc.__onload.make_payment_via_journal_entry){
if(in_list(['Sales Invoice', 'Purchase Invoice'], cur_frm.doc.doctype)){
@@ -1907,9 +1907,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
return method
- },
+ }
- set_query_for_batch: function(doc, cdt, cdn) {
+ set_query_for_batch(doc, cdt, cdn) {
// Show item's batches in the dropdown of batch no
var me = this;
@@ -1939,9 +1939,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
filters: filters
}
}
- },
+ }
- set_query_for_item_tax_template: function(doc, cdt, cdn) {
+ set_query_for_item_tax_template(doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
if(!item.item_code) {
return doc.company ? {filters: {company: doc.company}} : {};
@@ -1961,9 +1961,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
filters: filters
}
}
- },
+ }
- payment_terms_template: function() {
+ payment_terms_template() {
var me = this;
const doc = this.frm.doc;
if(doc.payment_terms_template && doc.doctype !== 'Delivery Note') {
@@ -1983,9 +1983,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
})
}
- },
+ }
- payment_term: function(doc, cdt, cdn) {
+ payment_term(doc, cdt, cdn) {
var row = locals[cdt][cdn];
if(row.payment_term) {
frappe.call({
@@ -2005,17 +2005,17 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
})
}
- },
+ }
- against_blanket_order: function(doc, cdt, cdn) {
+ against_blanket_order(doc, cdt, cdn) {
var item = locals[cdt][cdn];
if(!item.against_blanket_order) {
frappe.model.set_value(this.frm.doctype + " Item", item.name, "blanket_order", null);
frappe.model.set_value(this.frm.doctype + " Item", item.name, "blanket_order_rate", 0.00);
}
- },
+ }
- blanket_order: function(doc, cdt, cdn) {
+ blanket_order(doc, cdt, cdn) {
var me = this;
var item = locals[cdt][cdn];
if (item.blanket_order && (item.parenttype=="Sales Order" || item.parenttype=="Purchase Order")) {
@@ -2043,34 +2043,34 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
})
}
- },
+ }
- set_reserve_warehouse: function() {
+ set_reserve_warehouse() {
this.autofill_warehouse(this.frm.doc.supplied_items, "reserve_warehouse", this.frm.doc.set_reserve_warehouse);
- },
+ }
- set_warehouse: function() {
+ set_warehouse() {
this.autofill_warehouse(this.frm.doc.items, "warehouse", this.frm.doc.set_warehouse);
- },
+ }
- set_target_warehouse: function() {
+ set_target_warehouse() {
this.autofill_warehouse(this.frm.doc.items, "target_warehouse", this.frm.doc.set_target_warehouse);
- },
+ }
- set_from_warehouse: function() {
+ set_from_warehouse() {
this.autofill_warehouse(this.frm.doc.items, "from_warehouse", this.frm.doc.set_from_warehouse);
- },
+ }
- autofill_warehouse : function (child_table, warehouse_field, warehouse) {
+ autofill_warehouse(child_table, warehouse_field, warehouse) {
if (warehouse && child_table && child_table.length) {
let doctype = child_table[0].doctype;
$.each(child_table || [], function(i, item) {
frappe.model.set_value(doctype, item.name, warehouse_field, warehouse);
});
}
- },
+ }
- coupon_code: function() {
+ coupon_code() {
var me = this;
frappe.run_serially([
() => this.frm.doc.ignore_pricing_rule=1,
@@ -2079,7 +2079,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
() => me.apply_pricing_rule()
]);
}
-});
+};
erpnext.show_serial_batch_selector = function (frm, d, callback, on_close, show_dialog) {
let warehouse, receiving_stock, existing_stock;
diff --git a/erpnext/public/js/payment/payments.js b/erpnext/public/js/payment/payments.js
index 0d656bc1fb..7df976c1be 100644
--- a/erpnext/public/js/payment/payments.js
+++ b/erpnext/public/js/payment/payments.js
@@ -1,31 +1,31 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-erpnext.payments = erpnext.stock.StockController.extend({
- make_payment: function() {
+erpnext.payments = class payments extends erpnext.stock.StockController {
+ make_payment() {
var me = this;
this.dialog = new frappe.ui.Dialog({
title: 'Payment'
});
-
+
this.dialog.show();
this.$body = this.dialog.body;
this.set_payment_primary_action();
this.make_keyboard();
this.select_text()
- },
+ }
- select_text: function(){
+ select_text(){
var me = this;
$(this.$body).find('.form-control').click(function(){
$(this).select();
})
- },
+ }
- set_payment_primary_action: function(){
+ set_payment_primary_action(){
var me = this;
-
+
this.dialog.set_primary_action(__("Submit"), function() {
// Allow no ZERO payment
$.each(me.frm.doc.payments, function (index, data) {
@@ -36,18 +36,18 @@ erpnext.payments = erpnext.stock.StockController.extend({
}
});
})
- },
+ }
- make_keyboard: function(){
+ make_keyboard(){
var me = this;
$(this.$body).empty();
$(this.$body).html(frappe.render_template('pos_payment', this.frm.doc))
this.show_payment_details();
this.bind_keyboard_event()
this.clear_amount()
- },
+ }
- make_multimode_payment: function(){
+ make_multimode_payment(){
var me = this;
if(this.frm.doc.change_amount > 0){
@@ -57,9 +57,9 @@ erpnext.payments = erpnext.stock.StockController.extend({
this.payments = frappe.model.add_child(this.frm.doc, 'Multi Mode Payment', "payments");
this.payments.mode_of_payment = this.dialog.fields_dict.mode_of_payment.get_value();
this.payments.amount = flt(this.payment_val);
- },
+ }
- show_payment_details: function(){
+ show_payment_details(){
var me = this;
var multimode_payments = $(this.$body).find('.multimode-payments').empty();
if(this.frm.doc.payments.length){
@@ -82,9 +82,9 @@ erpnext.payments = erpnext.stock.StockController.extend({
}else{
$("
No payment mode selected in pos profile
").appendTo(multimode_payments)
}
- },
+ }
- set_outstanding_amount: function(){
+ set_outstanding_amount(){
this.selected_mode = $(this.$body).find(repl("input[idx='%(idx)s']",{'idx': this.idx}));
this.highlight_selected_row()
this.payment_val = 0.0
@@ -99,47 +99,47 @@ erpnext.payments = erpnext.stock.StockController.extend({
}
this.selected_mode.select()
this.bind_amount_change_event();
- },
-
- bind_keyboard_event: function(){
+ }
+
+ bind_keyboard_event(){
var me = this;
this.payment_val = '';
this.bind_form_control_event();
this.bind_numeric_keys_event();
- },
+ }
- bind_form_control_event: function(){
+ bind_form_control_event(){
var me = this;
$(this.$body).find('.pos-payment-row').click(function(){
me.idx = $(this).attr("idx");
me.set_outstanding_amount()
})
-
+
$(this.$body).find('.form-control').click(function(){
me.idx = $(this).attr("idx");
me.set_outstanding_amount();
me.update_paid_amount(true);
})
-
+
$(this.$body).find('.write_off_amount').change(function(){
me.write_off_amount(flt($(this).val()), precision("write_off_amount"));
})
-
+
$(this.$body).find('.change_amount').change(function(){
me.change_amount(flt($(this).val()), precision("change_amount"));
})
- },
+ }
- highlight_selected_row: function(){
+ highlight_selected_row(){
var me = this;
var selected_row = $(this.$body).find(repl(".pos-payment-row[idx='%(idx)s']",{'idx': this.idx}));
$(this.$body).find('.pos-payment-row').removeClass('selected-payment-mode')
selected_row.addClass('selected-payment-mode')
$(this.$body).find('.amount').attr('disabled', true);
this.selected_mode.attr('disabled', false);
- },
-
- bind_numeric_keys_event: function(){
+ }
+
+ bind_numeric_keys_event(){
var me = this;
$(this.$body).find('.pos-keyboard-key').click(function(){
me.payment_val += $(this).text();
@@ -147,7 +147,7 @@ erpnext.payments = erpnext.stock.StockController.extend({
me.idx = me.selected_mode.attr("idx")
me.update_paid_amount()
})
-
+
$(this.$body).find('.delete-btn').click(function(){
me.payment_val = cstr(flt(me.selected_mode.val())).slice(0, -1);
me.selected_mode.val(format_currency(me.payment_val, me.frm.doc.currency));
@@ -155,9 +155,9 @@ erpnext.payments = erpnext.stock.StockController.extend({
me.update_paid_amount();
})
- },
-
- bind_amount_change_event: function(){
+ }
+
+ bind_amount_change_event(){
var me = this;
this.selected_mode.change(function(){
me.payment_val = flt($(this).val()) || 0.0;
@@ -165,9 +165,9 @@ erpnext.payments = erpnext.stock.StockController.extend({
me.idx = me.selected_mode.attr("idx")
me.update_payment_amount()
})
- },
+ }
- clear_amount: function() {
+ clear_amount() {
var me = this;
$(this.$body).find('.clr').click(function(e){
e.stopPropagation();
@@ -178,9 +178,9 @@ erpnext.payments = erpnext.stock.StockController.extend({
me.highlight_selected_row();
me.update_payment_amount();
})
- },
+ }
- write_off_amount: function(write_off_amount) {
+ write_off_amount(write_off_amount) {
var me = this;
this.frm.doc.write_off_amount = flt(write_off_amount, precision("write_off_amount"));
@@ -188,17 +188,17 @@ erpnext.payments = erpnext.stock.StockController.extend({
precision("base_write_off_amount"));
this.calculate_outstanding_amount(false)
this.show_amounts()
- },
+ }
- change_amount: function(change_amount) {
+ change_amount(change_amount) {
var me = this;
this.frm.doc.change_amount = flt(change_amount, precision("change_amount"));
this.calculate_write_off_amount()
this.show_amounts()
- },
+ }
- update_paid_amount: function(update_write_off) {
+ update_paid_amount(update_write_off) {
var me = this;
if(in_list(['change_amount', 'write_off_amount'], this.idx)){
var value = me.selected_mode.val();
@@ -213,9 +213,9 @@ erpnext.payments = erpnext.stock.StockController.extend({
}else{
this.update_payment_amount()
}
- },
+ }
- update_payment_amount: function(){
+ update_payment_amount(){
var me = this;
$.each(this.frm.doc.payments, function(index, data){
@@ -226,9 +226,9 @@ erpnext.payments = erpnext.stock.StockController.extend({
this.calculate_outstanding_amount(false);
this.show_amounts();
- },
+ }
- show_amounts: function(){
+ show_amounts(){
var me = this;
$(this.$body).find(".write_off_amount").val(format_currency(this.frm.doc.write_off_amount, this.frm.doc.currency));
$(this.$body).find('.paid_amount').text(format_currency(this.frm.doc.paid_amount, this.frm.doc.currency));
@@ -236,4 +236,4 @@ erpnext.payments = erpnext.stock.StockController.extend({
$(this.$body).find('.outstanding_amount').text(format_currency(this.frm.doc.outstanding_amount, frappe.get_doc(":Company", this.frm.doc.company).default_currency))
this.update_invoice();
}
-})
\ No newline at end of file
+}
diff --git a/erpnext/public/js/stock_analytics.js b/erpnext/public/js/stock_analytics.js
index 140c9dc90b..c74b45e6db 100644
--- a/erpnext/public/js/stock_analytics.js
+++ b/erpnext/public/js/stock_analytics.js
@@ -2,8 +2,8 @@
// License: GNU General Public License v3. See license.txt
-erpnext.StockAnalytics = erpnext.StockGridReport.extend({
- init: function(wrapper, opts) {
+erpnext.StockAnalytics = class StockAnalytics extends erpnext.StockGridReport {
+ constructor(wrapper, opts) {
var args = {
title: __("Stock Analytics"),
parent: $(wrapper).find('.layout-main'),
@@ -30,9 +30,9 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
if(opts) $.extend(args, opts);
- this._super(args);
- },
- setup_columns: function() {
+ super(args);
+ }
+ setup_columns() {
var std_columns = [
{id: "name", name: __("Item"), field: "name", width: 300},
{id: "brand", name: __("Brand"), field: "brand", width: 100},
@@ -43,8 +43,9 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
this.make_date_range_columns();
this.columns = std_columns.concat(this.columns);
- },
- filters: [
+ }
+
+ filters = [
{fieldtype:"Select", label: __("Value or Qty"), fieldname: "value_or_qty",
options:[{label:__("Value"), value:"Value"}, {label:__("Quantity"), value:"Quantity"}],
filter: function(val, item, opts, me) {
@@ -66,20 +67,21 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
{label:__("Quarterly"), value:"Quarterly"},
{label:__("Yearly"), value:"Yearly"},
]}
- ],
- setup_filters: function() {
+ ]
+
+ setup_filters() {
var me = this;
- this._super();
+ super.setup_filters();
this.trigger_refresh_on_change(["value_or_qty", "brand", "warehouse", "range"]);
this.show_zero_check();
- },
- init_filter_values: function() {
- this._super();
+ }
+ init_filter_values() {
+ super.init_filter_values();
this.filter_inputs.range && this.filter_inputs.range.val('Monthly');
- },
- prepare_data: function() {
+ }
+ prepare_data() {
var me = this;
if(!this.data) {
@@ -112,8 +114,8 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
this.prepare_balances();
this.update_groups();
- },
- prepare_balances: function() {
+ }
+ prepare_balances() {
var me = this;
var from_date = frappe.datetime.str_to_obj(this.from_date);
var to_date = frappe.datetime.str_to_obj(this.to_date);
@@ -164,8 +166,8 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
item.closing_qty_value += diff;
}
}
- },
- update_groups: function() {
+ }
+ update_groups() {
var me = this;
$.each(this.data, function(i, item) {
// update groups
@@ -192,8 +194,8 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
}
}
});
- },
- show_stock_ledger: function(item_code) {
+ }
+ show_stock_ledger(item_code) {
frappe.route_options = {
item_code: item_code,
from_date: this.from_date,
@@ -201,5 +203,5 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
};
frappe.set_route("query-report", "Stock Ledger");
}
-});
+};
diff --git a/erpnext/public/js/stock_grid_report.js b/erpnext/public/js/stock_grid_report.js
index 832fd3eccf..752fafdb97 100644
--- a/erpnext/public/js/stock_grid_report.js
+++ b/erpnext/public/js/stock_grid_report.js
@@ -1,16 +1,16 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-erpnext.StockGridReport = frappe.views.TreeGridReport.extend({
- get_item_warehouse: function(warehouse, item) {
+erpnext.StockGridReport = class StockGridReport extends frappe.views.TreeGridReport {
+ get_item_warehouse(warehouse, item) {
if(!this.item_warehouse[item]) this.item_warehouse[item] = {};
if(!this.item_warehouse[item][warehouse]) this.item_warehouse[item][warehouse] = {
balance_qty: 0.0, balance_value: 0.0, fifo_stack: []
};
return this.item_warehouse[item][warehouse];
- },
+ }
- get_value_diff: function(wh, sl, is_fifo) {
+ get_value_diff(wh, sl, is_fifo) {
// value
if(sl.qty > 0) {
// incoming - rate is given
@@ -59,8 +59,8 @@ erpnext.StockGridReport = frappe.views.TreeGridReport.extend({
wh.balance_qty += sl.qty;
wh.balance_value += value_diff;
return value_diff;
- },
- get_fifo_value_diff: function(wh, sl) {
+ }
+ get_fifo_value_diff(wh, sl) {
// get exact rate from fifo stack
var fifo_stack = (wh.fifo_stack || []).reverse();
var fifo_value_diff = 0.0;
@@ -89,9 +89,9 @@ erpnext.StockGridReport = frappe.views.TreeGridReport.extend({
// reset the updated stack
wh.fifo_stack = fifo_stack.reverse();
return -fifo_value_diff;
- },
+ }
- get_serialized_value_diff: function(sl) {
+ get_serialized_value_diff(sl) {
var me = this;
var value_diff = 0.0;
@@ -103,9 +103,9 @@ erpnext.StockGridReport = frappe.views.TreeGridReport.extend({
});
return value_diff;
- },
+ }
- get_serialized_buying_rates: function() {
+ get_serialized_buying_rates() {
var serialized_buying_rates = {};
if (frappe.report_dump.data["Serial No"]) {
@@ -115,5 +115,5 @@ erpnext.StockGridReport = frappe.views.TreeGridReport.extend({
}
return serialized_buying_rates;
- },
-});
+ }
+};
diff --git a/erpnext/public/js/telephony.js b/erpnext/public/js/telephony.js
index 9548d6c5f3..1c3e314797 100644
--- a/erpnext/public/js/telephony.js
+++ b/erpnext/public/js/telephony.js
@@ -1,19 +1,19 @@
-frappe.ui.form.ControlData = frappe.ui.form.ControlData.extend( {
+frappe.ui.form.ControlData = class ControlData extends frappe.ui.form.ControlData {
make_input() {
- this._super();
+ super.make_input();
if (this.df.options == 'Phone') {
this.setup_phone();
}
if (this.frm && this.frm.fields_dict) {
Object.values(this.frm.fields_dict).forEach(function(field) {
- if (field.df.read_only === 1 && field.df.options === 'Phone'
+ if (field.df.read_only === 1 && field.df.options === 'Phone'
&& field.disp_area.style[0] != 'display' && !field.has_icon) {
field.setup_phone();
field.has_icon = true;
}
});
}
- },
+ }
setup_phone() {
if (frappe.phone_call.handler) {
let control = this.df.read_only ? '.control-value' : '.control-input';
@@ -30,4 +30,4 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlData.extend( {
});
}
}
-});
+};
diff --git a/erpnext/public/js/utils/customer_quick_entry.js b/erpnext/public/js/utils/customer_quick_entry.js
index ebe6cd98f8..efb8dd9d5c 100644
--- a/erpnext/public/js/utils/customer_quick_entry.js
+++ b/erpnext/public/js/utils/customer_quick_entry.js
@@ -1,17 +1,17 @@
frappe.provide('frappe.ui.form');
-frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
- init: function(doctype, after_insert) {
+frappe.ui.form.CustomerQuickEntryForm = class CustomerQuickEntryForm extends frappe.ui.form.QuickEntryForm {
+ constructor(doctype, after_insert) {
+ super(doctype, after_insert);
this.skip_redirect_on_error = true;
- this._super(doctype, after_insert);
- },
+ }
- render_dialog: function() {
+ render_dialog() {
this.mandatory = this.mandatory.concat(this.get_variant_fields());
- this._super();
- },
+ super.render_dialog();
+ }
- get_variant_fields: function() {
+ get_variant_fields() {
var variant_fields = [{
fieldtype: "Section Break",
label: __("Primary Contact Details"),
@@ -77,5 +77,5 @@ frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
}];
return variant_fields;
- },
-})
\ No newline at end of file
+ }
+}
diff --git a/erpnext/public/js/utils/item_quick_entry.js b/erpnext/public/js/utils/item_quick_entry.js
index 27ef107ace..7e0198d33b 100644
--- a/erpnext/public/js/utils/item_quick_entry.js
+++ b/erpnext/public/js/utils/item_quick_entry.js
@@ -1,27 +1,27 @@
frappe.provide('frappe.ui.form');
-frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
- init: function(doctype, after_insert) {
- this._super(doctype, after_insert);
- },
+frappe.ui.form.ItemQuickEntryForm = class ItemQuickEntryForm extends frappe.ui.form.QuickEntryForm {
+ constructor(doctype, after_insert) {
+ super(doctype, after_insert);
+ }
- render_dialog: function() {
+ render_dialog() {
this.mandatory = this.get_variant_fields().concat(this.mandatory);
this.mandatory = this.mandatory.concat(this.get_attributes_fields());
this.check_naming_series_based_on();
- this._super();
+ super.render_dialog();
this.init_post_render_dialog_operations();
this.preset_fields_for_template();
this.dialog.$wrapper.find('.edit-full').text(__('Edit in full page for more options like assets, serial nos, batches etc.'))
- },
+ }
- check_naming_series_based_on: function() {
+ check_naming_series_based_on() {
if (frappe.defaults.get_default("item_naming_by") === "Naming Series") {
this.mandatory = this.mandatory.filter(d => d.fieldname !== "item_code");
}
- },
+ }
- init_post_render_dialog_operations: function() {
+ init_post_render_dialog_operations() {
this.dialog.fields_dict.attribute_html.$wrapper.append(frappe.render_template("item_quick_entry"));
this.init_for_create_variant_trigger();
this.init_for_item_template_trigger();
@@ -29,9 +29,9 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
this.toggle_manufacturer_fields();
this.dialog.get_field("item_template").df.hidden = 1;
this.dialog.get_field("item_template").refresh();
- },
+ }
- register_primary_action: function() {
+ register_primary_action() {
var me = this;
this.dialog.set_primary_action(__('Save'), function() {
if (me.dialog.working) return;
@@ -59,9 +59,9 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
me.insert(variant_values);
}
});
- },
+ }
- insert: function(variant_values) {
+ insert(variant_values) {
let me = this;
return new Promise(resolve => {
frappe.call({
@@ -94,9 +94,9 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
freeze: true
});
});
- },
+ }
- open_doc: function() {
+ open_doc() {
this.dialog.hide();
this.update_doc();
if (this.dialog.fields_dict.create_variant.$input.prop("checked")) {
@@ -106,9 +106,9 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
} else {
frappe.set_route('Form', this.doctype, this.doc.name);
}
- },
+ }
- get_variant_fields: function() {
+ get_variant_fields() {
var variant_fields = [{
fieldname: "create_variant",
fieldtype: "Check",
@@ -130,9 +130,9 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
}];
return variant_fields;
- },
+ }
- get_manufacturing_fields: function() {
+ get_manufacturing_fields() {
this.manufacturer_fields = [{
fieldtype: 'Link',
options: 'Manufacturer',
@@ -148,9 +148,9 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
reqd: 0
}];
return this.manufacturer_fields;
- },
+ }
- get_attributes_fields: function() {
+ get_attributes_fields() {
var attribute_fields = [{
fieldname: 'attribute_html',
fieldtype: 'HTML'
@@ -158,18 +158,18 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
attribute_fields = attribute_fields.concat(this.get_manufacturing_fields());
return attribute_fields;
- },
+ }
- init_for_create_variant_trigger: function() {
+ init_for_create_variant_trigger() {
var me = this;
this.dialog.fields_dict.create_variant.$input.on("click", function() {
me.preset_fields_for_template();
me.init_post_template_trigger_operations(false, [], true);
});
- },
+ }
- preset_fields_for_template: function() {
+ preset_fields_for_template() {
var for_variant = this.dialog.get_value('create_variant');
// setup template field, seen and mandatory if variant
@@ -195,9 +195,9 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
f.refresh();
});
- },
+ }
- init_for_item_template_trigger: function() {
+ init_for_item_template_trigger() {
var me = this;
me.dialog.fields_dict["item_template"].df.onchange = () => {
@@ -228,9 +228,9 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
me.init_post_template_trigger_operations(false, [], true);
}
}
- },
+ }
- init_post_template_trigger_operations: function(is_manufacturer, attributes, attributes_flag) {
+ init_post_template_trigger_operations(is_manufacturer, attributes, attributes_flag) {
this.attributes = attributes;
this.attribute_values = {};
this.attributes_count = attributes.length;
@@ -240,23 +240,23 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
this.toggle_manufacturer_fields();
this.dialog.fields_dict.attribute_html.$wrapper.find(".attributes").toggleClass("hide-control", attributes_flag);
this.dialog.fields_dict.attribute_html.$wrapper.find(".attributes-header").toggleClass("hide-control", attributes_flag);
- },
+ }
- toggle_manufacturer_fields: function() {
+ toggle_manufacturer_fields() {
var me = this;
$.each(this.manufacturer_fields, function(i, dialog_field) {
me.dialog.get_field(dialog_field.fieldname).df.hidden = !me.is_manufacturer;
me.dialog.get_field(dialog_field.fieldname).df.reqd = dialog_field.fieldname == 'manufacturer' ? me.is_manufacturer : false;
me.dialog.get_field(dialog_field.fieldname).refresh();
});
- },
+ }
- initiate_render_attributes: function() {
+ initiate_render_attributes() {
this.dialog.fields_dict.attribute_html.$wrapper.find(".attributes").empty();
this.render_attributes(this.attributes);
- },
+ }
- render_attributes: function(attributes) {
+ render_attributes(attributes) {
var me = this;
this.dialog.get_field('attribute_html').toggle(true);
@@ -291,9 +291,9 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
});
}
});
- },
+ }
- init_make_control: function(fieldtype, row) {
+ init_make_control(fieldtype, row) {
this[row.attribute] = frappe.ui.form.make_control({
df: {
"fieldtype": fieldtype,
@@ -305,9 +305,9 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
only_input: false
});
this[row.attribute].make_input();
- },
+ }
- init_awesomplete_for_attribute: function(row) {
+ init_awesomplete_for_attribute(row) {
var me = this;
this[row.attribute].input.awesomplete = new Awesomplete(this[row.attribute].input, {
@@ -343,9 +343,9 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
me.attribute_values[$(e.target).attr("data-fieldname")] = e.target.value;
$(e.target).closest(".frappe-control").toggleClass("has-error", e.target.value ? false : true);
});
- },
+ }
- get_variant_doc: function() {
+ get_variant_doc() {
var me = this;
var variant_doc = {};
var attribute = this.validate_mandatory_attributes();
@@ -381,9 +381,9 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
})
}
return variant_doc;
- },
+ }
- validate_mandatory_attributes: function() {
+ validate_mandatory_attributes() {
var me = this;
var attribute = {};
var mandatory = [];
@@ -404,4 +404,4 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
}
return attribute;
}
-});
\ No newline at end of file
+};
diff --git a/erpnext/public/js/utils/item_selector.js b/erpnext/public/js/utils/item_selector.js
index d04c488a59..9fc264086a 100644
--- a/erpnext/public/js/utils/item_selector.js
+++ b/erpnext/public/js/utils/item_selector.js
@@ -1,5 +1,5 @@
-erpnext.ItemSelector = Class.extend({
- init: function(opts) {
+erpnext.ItemSelector = class ItemSelector {
+ constructor(opts) {
$.extend(this, opts);
if (!this.item_field) {
@@ -12,9 +12,9 @@ erpnext.ItemSelector = Class.extend({
this.grid = this.frm.get_field("items").grid;
this.setup();
- },
+ }
- setup: function() {
+ setup() {
var me = this;
if(!this.grid.add_items_button) {
this.grid.add_items_button = this.grid.add_custom_button(__('Add Items'), function() {
@@ -26,9 +26,9 @@ erpnext.ItemSelector = Class.extend({
setTimeout(function() { me.dialog.input.focus(); }, 1000);
});
}
- },
+ }
- make_dialog: function() {
+ make_dialog() {
this.dialog = new frappe.ui.Dialog({
title: __('Add Items')
});
@@ -53,9 +53,9 @@ erpnext.ItemSelector = Class.extend({
me.timeout_id = undefined;
}, 500);
});
- },
+ }
- add_item: function(item_code) {
+ add_item(item_code) {
// add row or update qty
var added = false;
@@ -82,9 +82,9 @@ erpnext.ItemSelector = Class.extend({
]);
}
- },
+ }
- render_items: function() {
+ render_items() {
let args = {
query: this.item_query,
filters: {}
@@ -107,4 +107,4 @@ erpnext.ItemSelector = Class.extend({
me.dialog.results.html(frappe.render_template('item_selector', {'data':r.values}));
});
}
-});
\ No newline at end of file
+};
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index d49a8138fb..d44c708356 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -1,6 +1,6 @@
-erpnext.SerialNoBatchSelector = Class.extend({
- init: function(opts, show_dialog) {
+erpnext.SerialNoBatchSelector = class SerialNoBatchSelector {
+ constructor(opts, show_dialog) {
$.extend(this, opts);
this.show_dialog = show_dialog;
// frm, item, warehouse_details, has_batch, oldest
@@ -12,16 +12,16 @@ erpnext.SerialNoBatchSelector = Class.extend({
if(d && d.has_serial_no && !(this.show_dialog == false)) this.has_serial_no = 1;
this.setup();
- },
+ }
- setup: function() {
+ setup() {
this.item_code = this.item.item_code;
this.qty = this.item.qty;
this.make_dialog();
this.on_close_dialog();
- },
+ }
- make_dialog: function() {
+ make_dialog() {
var me = this;
this.data = this.oldest ? this.oldest : [];
@@ -176,15 +176,15 @@ erpnext.SerialNoBatchSelector = Class.extend({
}
this.dialog.show();
- },
+ }
- on_close_dialog: function() {
+ on_close_dialog() {
this.dialog.get_close_btn().on('click', () => {
this.on_close && this.on_close(this.item);
});
- },
+ }
- validate: function() {
+ validate() {
let values = this.values;
if(!values.warehouse) {
frappe.throw(__("Please select a warehouse"));
@@ -210,7 +210,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
}
return true;
}
- },
+ }
update_batch_items() {
// clones an items if muliple batches are selected.
@@ -233,14 +233,14 @@ erpnext.SerialNoBatchSelector = Class.extend({
'selected_qty', this.values.warehouse);
});
}
- },
+ }
update_serial_no_item() {
// just updates serial no for the item
if(this.has_serial_no && !this.has_batch) {
this.map_row_values(this.item, this.values, 'serial_no', 'qty');
}
- },
+ }
update_batch_serial_no_items() {
// if serial no selected is from different batches, adds new rows for each batch.
@@ -281,14 +281,14 @@ erpnext.SerialNoBatchSelector = Class.extend({
});
})
}
- },
+ }
- batch_exists: function(batch) {
+ batch_exists(batch) {
const batches = this.frm.doc.items.map(data => data.batch_no);
return (batches && in_list(batches, batch)) ? true : false;
- },
+ }
- map_row_values: function(row, values, number, qty_field, warehouse) {
+ map_row_values(row, values, number, qty_field, warehouse) {
row.qty = values[qty_field];
row.transfer_qty = flt(values[qty_field]) * flt(row.conversion_factor);
row[number] = values[number];
@@ -301,9 +301,9 @@ erpnext.SerialNoBatchSelector = Class.extend({
}
this.frm.dirty();
- },
+ }
- update_total_qty: function() {
+ update_total_qty() {
let qty_field = this.dialog.fields_dict.qty;
let total_qty = 0;
@@ -312,9 +312,9 @@ erpnext.SerialNoBatchSelector = Class.extend({
});
qty_field.set_input(total_qty);
- },
+ }
- get_batch_fields: function() {
+ get_batch_fields() {
var me = this;
return [
@@ -425,9 +425,9 @@ erpnext.SerialNoBatchSelector = Class.extend({
},
}
];
- },
+ }
- get_serial_no_fields: function() {
+ get_serial_no_fields() {
var me = this;
this.serial_list = [];
@@ -510,4 +510,4 @@ erpnext.SerialNoBatchSelector = Class.extend({
}
];
}
-});
+};
diff --git a/erpnext/selling/doctype/installation_note/installation_note.js b/erpnext/selling/doctype/installation_note/installation_note.js
index 7fd0877d11..ffa185baf6 100644
--- a/erpnext/selling/doctype/installation_note/installation_note.js
+++ b/erpnext/selling/doctype/installation_note/installation_note.js
@@ -30,8 +30,8 @@ frappe.ui.form.on('Installation Note', {
frappe.provide("erpnext.selling");
// TODO commonify this code
-erpnext.selling.InstallationNote = frappe.ui.form.Controller.extend({
- refresh: function() {
+erpnext.selling.InstallationNote = class InstallationNote extends frappe.ui.form.Controller {
+ refresh() {
var me = this;
if (this.frm.doc.docstatus===0) {
this.frm.add_custom_button(__('From Delivery Note'),
@@ -54,7 +54,7 @@ erpnext.selling.InstallationNote = frappe.ui.form.Controller.extend({
}, "fa fa-download", "btn-default"
);
}
- },
-});
+ }
+};
$.extend(cur_frm.cscript, new erpnext.selling.InstallationNote({frm: cur_frm}));
\ No newline at end of file
diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js
index 5a0d9c9065..10606bf81e 100644
--- a/erpnext/selling/doctype/quotation/quotation.js
+++ b/erpnext/selling/doctype/quotation/quotation.js
@@ -36,13 +36,13 @@ frappe.ui.form.on('Quotation', {
}
});
-erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
- onload: function(doc, dt, dn) {
+erpnext.selling.QuotationController = class QuotationController extends erpnext.selling.SellingController {
+ onload(doc, dt, dn) {
var me = this;
- this._super(doc, dt, dn);
+ super.(doc, dt, dn);
- },
- party_name: function() {
+ }
+ party_name() {
var me = this;
erpnext.utils.get_party_details(this.frm, null, null, function() {
me.apply_price_list();
@@ -51,9 +51,9 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
if(me.frm.doc.quotation_to=="Lead" && me.frm.doc.party_name) {
me.frm.trigger("get_lead_details");
}
- },
- refresh: function(doc, dt, dn) {
- this._super(doc, dt, dn);
+ }
+ refresh(doc, dt, dn) {
+ super.refresh(doc, dt, dn);
doctype = doc.quotation_to == 'Customer' ? 'Customer':'Lead';
frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'party_name', doctype: doctype}
@@ -121,9 +121,9 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
this.toggle_reqd_lead_customer();
- },
+ }
- set_dynamic_field_label: function(){
+ set_dynamic_field_label(){
if (this.frm.doc.quotation_to == "Customer")
{
this.frm.set_df_property("party_name", "label", "Customer");
@@ -138,22 +138,22 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
return{ query: "erpnext.controllers.queries.lead_query" }
}
}
- },
+ }
- toggle_reqd_lead_customer: function() {
+ toggle_reqd_lead_customer() {
var me = this;
// to overwrite the customer_filter trigger from queries.js
this.frm.toggle_reqd("party_name", this.frm.doc.quotation_to);
this.frm.set_query('customer_address', this.address_query);
this.frm.set_query('shipping_address_name', this.address_query);
- },
+ }
- tc_name: function() {
+ tc_name() {
this.get_terms();
- },
+ }
- address_query: function(doc) {
+ address_query(doc) {
return {
query: 'frappe.contacts.doctype.address.address.address_query',
filters: {
@@ -161,20 +161,20 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
link_name: doc.party_name
}
};
- },
+ }
- validate_company_and_party: function(party_field) {
+ validate_company_and_party(party_field) {
if(!this.frm.doc.quotation_to) {
frappe.msgprint(__("Please select a value for {0} quotation_to {1}", [this.frm.doc.doctype, this.frm.doc.name]));
return false;
} else if (this.frm.doc.quotation_to == "Lead") {
return true;
} else {
- return this._super(party_field);
+ return super.validate_company_and_party(party_field);
}
- },
+ }
- get_lead_details: function() {
+ get_lead_details() {
var me = this;
if(!this.frm.doc.quotation_to === "Lead") {
return;
@@ -198,7 +198,7 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
}
})
}
-});
+};
cur_frm.script_manager.make(erpnext.selling.QuotationController);
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index e3b41e66fb..d5ceca8ec8 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -102,14 +102,14 @@ frappe.ui.form.on("Sales Order Item", {
}
});
-erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
- onload: function(doc, dt, dn) {
- this._super();
- },
+erpnext.selling.SalesOrderController = class SalesOrderController extends erpnext.selling.SellingController {
+ onload(doc, dt, dn) {
+ super.onload();
+ }
- refresh: function(doc, dt, dn) {
+ refresh(doc, dt, dn) {
var me = this;
- this._super();
+ super.refresh();
let allow_delivery = false;
if (doc.docstatus==1) {
@@ -241,14 +241,14 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
}
this.order_type(doc);
- },
+ }
create_pick_list() {
frappe.model.open_mapped_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.create_pick_list",
frm: this.frm
})
- },
+ }
make_work_order() {
var me = this;
@@ -343,33 +343,33 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
}
}
});
- },
+ }
- order_type: function() {
+ order_type() {
this.toggle_delivery_date();
- },
+ }
- tc_name: function() {
+ tc_name() {
this.get_terms();
- },
+ }
- make_material_request: function() {
+ make_material_request() {
frappe.model.open_mapped_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_material_request",
frm: this.frm
})
- },
+ }
- skip_delivery_note: function() {
+ skip_delivery_note() {
this.toggle_delivery_date();
- },
+ }
- toggle_delivery_date: function() {
+ toggle_delivery_date() {
this.frm.fields_dict.items.grid.toggle_reqd("delivery_date",
(this.frm.doc.order_type == "Sales" && !this.frm.doc.skip_delivery_note));
- },
+ }
- make_raw_material_request: function() {
+ make_raw_material_request() {
var me = this;
this.frm.call({
doc: this.frm.doc,
@@ -390,9 +390,9 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
}
}
});
- },
+ }
- make_raw_material_request_dialog: function(r) {
+ make_raw_material_request_dialog(r) {
var fields = [
{fieldtype:'Check', fieldname:'include_exploded_items',
label: __('Include Exploded Items')},
@@ -447,9 +447,9 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
primary_action_label: __('Create')
});
d.show();
- },
+ }
- make_delivery_note_based_on_delivery_date: function() {
+ make_delivery_note_based_on_delivery_date() {
var me = this;
var delivery_dates = [];
@@ -509,51 +509,51 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
} else {
this.make_delivery_note();
}
- },
+ }
- make_delivery_note: function() {
+ make_delivery_note() {
frappe.model.open_mapped_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
frm: this.frm
})
- },
+ }
- make_sales_invoice: function() {
+ make_sales_invoice() {
frappe.model.open_mapped_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice",
frm: this.frm
})
- },
+ }
- make_maintenance_schedule: function() {
+ make_maintenance_schedule() {
frappe.model.open_mapped_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_schedule",
frm: this.frm
})
- },
+ }
- make_project: function() {
+ make_project() {
frappe.model.open_mapped_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_project",
frm: this.frm
})
- },
+ }
- make_inter_company_order: function() {
+ make_inter_company_order() {
frappe.model.open_mapped_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_inter_company_purchase_order",
frm: this.frm
});
- },
+ }
- make_maintenance_visit: function() {
+ make_maintenance_visit() {
frappe.model.open_mapped_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit",
frm: this.frm
})
- },
+ }
- make_purchase_order: function(){
+ make_purchase_order(){
let pending_items = this.frm.doc.items.some((item) =>{
let pending_qty = flt(item.stock_qty) - flt(item.ordered_qty);
return pending_qty > 0;
@@ -690,9 +690,9 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
dialog.get_field("items_for_po").refresh();
dialog.wrapper.find('.grid-heading-row .grid-row-check').click();
dialog.show();
- },
+ }
- hold_sales_order: function(){
+ hold_sales_order(){
var me = this;
var d = new frappe.ui.Dialog({
title: __('Reason for Hold'),
@@ -724,11 +724,11 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
}
});
d.show();
- },
- close_sales_order: function(){
+ }
+ close_sales_order(){
this.frm.cscript.update_status("Close", "Closed")
- },
- update_status: function(label, status){
+ }
+ update_status(label, status){
var doc = this.frm.doc;
var me = this;
frappe.ui.form.is_saving = true;
@@ -743,5 +743,5 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
}
});
}
-});
+};
$.extend(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm}));
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 04285735ab..eb02867720 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -9,15 +9,15 @@ cur_frm.cscript.tax_table = "Sales Taxes and Charges";
cur_frm.email_field = "contact_email";
frappe.provide("erpnext.selling");
-erpnext.selling.SellingController = erpnext.TransactionController.extend({
- setup: function() {
- this._super();
+erpnext.selling.SellingController = class SellingController extends erpnext.TransactionController {
+ setup() {
+ super.setup();
this.frm.add_fetch("sales_partner", "commission_rate", "commission_rate");
this.frm.add_fetch("sales_person", "commission_rate", "commission_rate");
- },
+ }
- onload: function() {
- this._super();
+ onload() {
+ super.onload();
this.setup_queries();
this.frm.set_query('shipping_rule', function() {
return {
@@ -26,9 +26,9 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
}
};
});
- },
+ }
- setup_queries: function() {
+ setup_queries() {
var me = this;
$.each([["customer", "customer"],
@@ -81,10 +81,10 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
});
}
- },
+ }
- refresh: function() {
- this._super();
+ refresh() {
+ super.refresh();
frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
@@ -95,45 +95,45 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
this.frm.toggle_display("packing_list", packing_list_exists ? true : false);
}
this.toggle_editable_price_list_rate();
- },
+ }
- customer: function() {
+ customer() {
var me = this;
erpnext.utils.get_party_details(this.frm, null, null, function() {
me.apply_price_list();
});
- },
+ }
- customer_address: function() {
+ customer_address() {
erpnext.utils.get_address_display(this.frm, "customer_address");
erpnext.utils.set_taxes_from_address(this.frm, "customer_address", "customer_address", "shipping_address_name");
- },
+ }
- shipping_address_name: function() {
+ shipping_address_name() {
erpnext.utils.get_address_display(this.frm, "shipping_address_name", "shipping_address");
erpnext.utils.set_taxes_from_address(this.frm, "shipping_address_name", "customer_address", "shipping_address_name");
- },
+ }
- sales_partner: function() {
+ sales_partner() {
this.apply_pricing_rule();
- },
+ }
- campaign: function() {
+ campaign() {
this.apply_pricing_rule();
- },
+ }
- selling_price_list: function() {
+ selling_price_list() {
this.apply_price_list();
this.set_dynamic_labels();
- },
+ }
- discount_percentage: function(doc, cdt, cdn) {
+ discount_percentage(doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
item.discount_amount = 0.0;
this.apply_discount_on_item(doc, cdt, cdn, 'discount_percentage');
- },
+ }
- discount_amount: function(doc, cdt, cdn) {
+ discount_amount(doc, cdt, cdn) {
if(doc.name === cdn) {
return;
@@ -142,9 +142,9 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
var item = frappe.get_doc(cdt, cdn);
item.discount_percentage = 0.0;
this.apply_discount_on_item(doc, cdt, cdn, 'discount_amount');
- },
+ }
- apply_discount_on_item: function(doc, cdt, cdn, field) {
+ apply_discount_on_item(doc, cdt, cdn, field) {
var item = frappe.get_doc(cdt, cdn);
if(!item.price_list_rate) {
item[field] = 0.0;
@@ -152,14 +152,14 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
this.price_list_rate(doc, cdt, cdn);
}
this.set_gross_profit(item);
- },
+ }
- commission_rate: function() {
+ commission_rate() {
this.calculate_commission();
refresh_field("total_commission");
- },
+ }
- total_commission: function() {
+ total_commission() {
if(this.frm.doc.base_net_total) {
frappe.model.round_floats_in(this.frm.doc, ["base_net_total", "total_commission"]);
@@ -175,9 +175,9 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
this.frm.set_value("commission_rate",
flt(this.frm.doc.total_commission * 100.0 / this.frm.doc.base_net_total));
}
- },
+ }
- allocated_percentage: function(doc, cdt, cdn) {
+ allocated_percentage(doc, cdt, cdn) {
var sales_person = frappe.get_doc(cdt, cdn);
if(sales_person.allocated_percentage) {
@@ -193,15 +193,15 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
refresh_field(["allocated_percentage", "allocated_amount", "commission_rate","incentives"], sales_person.name,
sales_person.parentfield);
}
- },
+ }
- sales_person: function(doc, cdt, cdn) {
+ sales_person(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
this.calculate_incentive(row);
refresh_field("incentives",row.name,row.parentfield);
- },
+ }
- warehouse: function(doc, cdt, cdn) {
+ warehouse(doc, cdt, cdn) {
var me = this;
var item = frappe.get_doc(cdt, cdn);
@@ -239,18 +239,18 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
});
}
})
- },
+ }
- toggle_editable_price_list_rate: function() {
+ toggle_editable_price_list_rate() {
var df = frappe.meta.get_docfield(this.frm.doc.doctype + " Item", "price_list_rate", this.frm.doc.name);
var editable_price_list_rate = cint(frappe.defaults.get_default("editable_price_list_rate"));
if(df && editable_price_list_rate) {
df.read_only = 0;
}
- },
+ }
- calculate_commission: function() {
+ calculate_commission() {
if(this.frm.fields_dict.commission_rate) {
if(this.frm.doc.commission_rate > 100) {
var msg = __(frappe.meta.get_label(this.frm.doc.doctype, "commission_rate", this.frm.doc.name)) +
@@ -262,9 +262,9 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
this.frm.doc.total_commission = flt(this.frm.doc.base_net_total * this.frm.doc.commission_rate / 100.0,
precision("total_commission"));
}
- },
+ }
- calculate_contribution: function() {
+ calculate_contribution() {
var me = this;
$.each(this.frm.doc.doctype.sales_team || [], function(i, sales_person) {
frappe.model.round_floats_in(sales_person);
@@ -274,18 +274,18 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
precision("allocated_amount", sales_person));
}
});
- },
+ }
- calculate_incentive: function(row) {
+ calculate_incentive(row) {
if(row.allocated_amount)
{
row.incentives = flt(
row.allocated_amount * row.commission_rate / 100.0,
precision("incentives", row));
}
- },
+ }
- batch_no: function(doc, cdt, cdn) {
+ batch_no(doc, cdt, cdn) {
var me = this;
var item = frappe.get_doc(cdt, cdn);
@@ -312,14 +312,14 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
});
}
})
- },
+ }
- set_dynamic_labels: function() {
- this._super();
+ set_dynamic_labels() {
+ super.set_dynamic_labels();
this.set_product_bundle_help(this.frm.doc);
- },
+ }
- set_product_bundle_help: function(doc) {
+ set_product_bundle_help(doc) {
if(!cur_frm.fields_dict.packing_list) return;
if ((doc.packed_items || []).length) {
$(cur_frm.fields_dict.packing_list.row.wrapper).toggle(true);
@@ -337,9 +337,9 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
}
}
refresh_field('product_bundle_help');
- },
+ }
- company_address: function() {
+ company_address() {
var me = this;
if(this.frm.doc.company_address) {
frappe.call({
@@ -354,42 +354,42 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
} else {
this.frm.set_value("company_address_display", "");
}
- },
+ }
- conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
- this._super(doc, cdt, cdn, dont_fetch_price_list_rate);
+ conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate) {
+ super.conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate);
if(frappe.meta.get_docfield(cdt, "stock_qty", cdn) &&
in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
if (doc.doctype === 'Sales Invoice' && (!doc.update_stock)) return;
this.set_batch_number(cdt, cdn);
}
- },
+ }
- batch_no: function(doc, cdt, cdn) {
- this._super(doc, cdt, cdn);
- },
+ batch_no(doc, cdt, cdn) {
+ super.batch_no(doc, cdt, cdn);
+ }
- qty: function(doc, cdt, cdn) {
- this._super(doc, cdt, cdn);
+ qty(doc, cdt, cdn) {
+ super.qty(doc, cdt, cdn);
if(in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
if (doc.doctype === 'Sales Invoice' && (!doc.update_stock)) return;
this.set_batch_number(cdt, cdn);
}
- },
+ }
/* Determine appropriate batch number and set it in the form.
* @param {string} cdt - Document Doctype
* @param {string} cdn - Document name
*/
- set_batch_number: function(cdt, cdn) {
+ set_batch_number(cdt, cdn) {
const doc = frappe.get_doc(cdt, cdn);
if (doc && doc.has_batch_no && doc.warehouse) {
this._set_batch_number(doc);
}
- },
+ }
- _set_batch_number: function(doc) {
+ _set_batch_number(doc) {
let args = {'item_code': doc.item_code, 'warehouse': doc.warehouse, 'qty': flt(doc.qty) * flt(doc.conversion_factor)};
if (doc.has_serial_no && doc.serial_no) {
args['serial_no'] = doc.serial_no
@@ -406,9 +406,9 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
}
}
});
- },
+ }
- update_auto_repeat_reference: function(doc) {
+ update_auto_repeat_reference(doc) {
if (doc.auto_repeat) {
frappe.call({
method:"frappe.automation.doctype.auto_repeat.auto_repeat.update_reference",
@@ -426,7 +426,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
})
}
}
-});
+};
frappe.ui.form.on(cur_frm.doctype,"project", function(frm) {
if(in_list(["Delivery Note", "Sales Invoice"], frm.doc.doctype)) {
diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js
index 95cb92b1b3..30e0b762bd 100644
--- a/erpnext/stock/dashboard/item_dashboard.js
+++ b/erpnext/stock/dashboard/item_dashboard.js
@@ -1,11 +1,11 @@
frappe.provide('erpnext.stock');
-erpnext.stock.ItemDashboard = Class.extend({
- init: function(opts) {
+erpnext.stock.ItemDashboard = class ItemDashboard {
+ constructor(opts) {
$.extend(this, opts);
this.make();
- },
- make: function() {
+ }
+ make() {
var me = this;
this.start = 0;
if(!this.sort_by) {
@@ -73,8 +73,8 @@ erpnext.stock.ItemDashboard = Class.extend({
me.refresh();
});
- },
- refresh: function() {
+ }
+ refresh() {
if(this.before_refresh) {
this.before_refresh();
}
@@ -98,8 +98,8 @@ erpnext.stock.ItemDashboard = Class.extend({
me.render(r.message);
}
});
- },
- render: function(data) {
+ }
+ render(data) {
if (this.start===0) {
this.max_count = 0;
this.result.empty();
@@ -135,9 +135,9 @@ erpnext.stock.ItemDashboard = Class.extend({
$(`
${message}
`).appendTo(this.result);
}
- },
+ }
- get_item_dashboard_data: function(data, max_count, show_item) {
+ get_item_dashboard_data(data, max_count, show_item) {
if(!max_count) max_count = 0;
if(!data) data = [];
@@ -164,9 +164,9 @@ erpnext.stock.ItemDashboard = Class.extend({
can_write:can_write,
show_item: show_item || false
};
- },
+ }
- get_capacity_dashboard_data: function(data) {
+ get_capacity_dashboard_data(data) {
if (!data) data = [];
data.forEach(function(d) {
@@ -183,7 +183,7 @@ erpnext.stock.ItemDashboard = Class.extend({
can_write: can_write,
};
}
-});
+};
erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callback) {
var dialog = new frappe.ui.Dialog({
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index 334bdeac9d..63ea198c59 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -123,17 +123,17 @@ frappe.ui.form.on("Delivery Note Item", {
}
});
-erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend({
- setup: function(doc) {
+erpnext.stock.DeliveryNoteController = class DeliveryNoteController extends erpnext.selling.SellingController {
+ setup(doc) {
this.setup_posting_date_time_check();
- this._super(doc);
+ super.setup(doc);
this.frm.make_methods = {
'Delivery Trip': this.make_delivery_trip,
};
- },
- refresh: function(doc, dt, dn) {
+ }
+ refresh(doc, dt, dn) {
var me = this;
- this._super();
+ super.refresh();
if ((!doc.is_return) && (doc.status!="Closed" || this.frm.is_new())) {
if (this.frm.doc.docstatus===0) {
this.frm.add_custom_button(__('Sales Order'),
@@ -231,64 +231,64 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend(
erpnext.utils.make_subscription(doc.doctype, doc.name)
}, __('Create'))
}
- },
+ }
- make_shipment: function() {
+ make_shipment() {
frappe.model.open_mapped_doc({
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_shipment",
frm: this.frm
})
- },
+ }
- make_sales_invoice: function() {
+ make_sales_invoice() {
frappe.model.open_mapped_doc({
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice",
frm: this.frm
})
- },
+ }
- make_installation_note: function() {
+ make_installation_note() {
frappe.model.open_mapped_doc({
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_installation_note",
frm: this.frm
});
- },
+ }
- make_sales_return: function() {
+ make_sales_return() {
frappe.model.open_mapped_doc({
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_return",
frm: this.frm
})
- },
+ }
- make_delivery_trip: function() {
+ make_delivery_trip() {
frappe.model.open_mapped_doc({
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_delivery_trip",
frm: cur_frm
})
- },
+ }
- tc_name: function() {
+ tc_name() {
this.get_terms();
- },
+ }
- items_on_form_rendered: function(doc, grid_row) {
+ items_on_form_rendered(doc, grid_row) {
erpnext.setup_serial_no();
- },
+ }
- packed_items_on_form_rendered: function(doc, grid_row) {
+ packed_items_on_form_rendered(doc, grid_row) {
erpnext.setup_serial_no();
- },
+ }
- close_delivery_note: function(doc){
+ close_delivery_note(doc){
this.update_status("Closed")
- },
+ }
- reopen_delivery_note : function() {
+ reopen_delivery_note() {
this.update_status("Submitted")
- },
+ }
- update_status: function(status) {
+ update_status(status) {
var me = this;
frappe.ui.form.is_saving = true;
frappe.call({
@@ -302,8 +302,8 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend(
frappe.ui.form.is_saving = false;
}
})
- },
-});
+ }
+};
$.extend(cur_frm.cscript, new erpnext.stock.DeliveryNoteController({frm: cur_frm}));
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
index 1abbc35334..433f78adc9 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
@@ -5,8 +5,8 @@
frappe.provide("erpnext.stock");
-erpnext.stock.LandedCostVoucher = erpnext.stock.StockController.extend({
- setup: function() {
+erpnext.stock.LandedCostVoucher = class LandedCostVoucher extends erpnext.stock.StockController {
+ setup() {
var me = this;
this.frm.fields_dict.purchase_receipts.grid.get_field('receipt_document').get_query =
function (doc, cdt, cdn) {
@@ -30,9 +30,9 @@ erpnext.stock.LandedCostVoucher = erpnext.stock.StockController.extend({
this.frm.add_fetch("receipt_document", "supplier", "supplier");
this.frm.add_fetch("receipt_document", "posting_date", "posting_date");
this.frm.add_fetch("receipt_document", "base_grand_total", "grand_total");
- },
+ }
- refresh: function() {
+ refresh() {
var help_content =
`
@@ -67,9 +67,9 @@ erpnext.stock.LandedCostVoucher = erpnext.stock.StockController.extend({
let company_currency = frappe.get_doc(":Company", this.frm.doc.company).default_currency;
this.frm.set_currency_labels(["total_taxes_and_charges"], company_currency);
}
- },
+ }
- get_items_from_purchase_receipts: function() {
+ get_items_from_purchase_receipts() {
var me = this;
if(!this.frm.doc.purchase_receipts.length) {
frappe.msgprint(__("Please enter Purchase Receipt first"));
@@ -82,22 +82,22 @@ erpnext.stock.LandedCostVoucher = erpnext.stock.StockController.extend({
}
});
}
- },
+ }
- amount: function(frm) {
+ amount(frm) {
this.set_total_taxes_and_charges();
this.set_applicable_charges_for_item();
- },
+ }
- set_total_taxes_and_charges: function() {
+ set_total_taxes_and_charges() {
var total_taxes_and_charges = 0.0;
$.each(this.frm.doc.taxes || [], function(i, d) {
total_taxes_and_charges += flt(d.base_amount);
});
this.frm.set_value("total_taxes_and_charges", total_taxes_and_charges);
- },
+ }
- set_applicable_charges_for_item: function() {
+ set_applicable_charges_for_item() {
var me = this;
if(this.frm.doc.taxes.length) {
@@ -123,15 +123,15 @@ erpnext.stock.LandedCostVoucher = erpnext.stock.StockController.extend({
refresh_field("items");
}
}
- },
- distribute_charges_based_on: function (frm) {
+ }
+ distribute_charges_based_on (frm) {
this.set_applicable_charges_for_item();
- },
+ }
- items_remove: () => {
+ items_remove() {
this.trigger('set_applicable_charges_for_item');
}
-});
+};
cur_frm.script_manager.make(erpnext.stock.LandedCostVoucher);
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index 527b0d3ea9..86936b4db3 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -403,28 +403,28 @@ frappe.ui.form.on("Material Request Item", {
}
});
-erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.extend({
- tc_name: function() {
+erpnext.buying.MaterialRequestController = class MaterialRequestController extends erpnext.buying.BuyingController {
+ tc_name() {
this.get_terms();
- },
+ }
- item_code: function() {
+ item_code() {
// to override item code trigger from transaction.js
- },
+ }
- validate_company_and_party: function() {
+ validate_company_and_party() {
return true;
- },
+ }
- calculate_taxes_and_totals: function() {
+ calculate_taxes_and_totals() {
return;
- },
+ }
- validate: function() {
+ validate() {
set_schedule_date(this.frm);
- },
+ }
- onload: function(doc, cdt, cdn) {
+ onload(doc, cdt, cdn) {
this.frm.set_query("item_code", "items", function() {
if (doc.material_request_type == "Customer Provided") {
return{
@@ -438,9 +438,9 @@ erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.exten
}
}
});
- },
+ }
- items_add: function(doc, cdt, cdn) {
+ items_add(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
if(doc.schedule_date) {
row.schedule_date = doc.schedule_date;
@@ -448,16 +448,16 @@ erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.exten
} else {
this.frm.script_manager.copy_from_first_row("items", row, ["schedule_date"]);
}
- },
+ }
- items_on_form_rendered: function() {
- set_schedule_date(this.frm);
- },
-
- schedule_date: function() {
+ items_on_form_rendered() {
set_schedule_date(this.frm);
}
-});
+
+ schedule_date() {
+ set_schedule_date(this.frm);
+ }
+};
// for backward compatibility: combine new and previous states
$.extend(cur_frm.cscript, new erpnext.buying.MaterialRequestController({frm: cur_frm}));
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index 57cc3504a9..f87b273d64 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -86,15 +86,15 @@ frappe.ui.form.on("Purchase Receipt", {
}
});
-erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend({
- setup: function(doc) {
+erpnext.stock.PurchaseReceiptController = class PurchaseReceiptController extends erpnext.buying.BuyingController {
+ setup(doc) {
this.setup_posting_date_time_check();
- this._super(doc);
- },
+ super.setup(doc);
+ }
- refresh: function() {
+ refresh() {
var me = this;
- this._super();
+ super.refresh();
if(this.frm.doc.docstatus > 0) {
this.show_stock_ledger();
//removed for temporary
@@ -173,31 +173,31 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend
}
this.frm.toggle_reqd("supplier_warehouse", this.frm.doc.is_subcontracted==="Yes");
- },
+ }
- make_purchase_invoice: function() {
+ make_purchase_invoice() {
frappe.model.open_mapped_doc({
method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_invoice",
frm: cur_frm
})
- },
+ }
- make_purchase_return: function() {
+ make_purchase_return() {
frappe.model.open_mapped_doc({
method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_return",
frm: cur_frm
})
- },
+ }
- close_purchase_receipt: function() {
+ close_purchase_receipt() {
cur_frm.cscript.update_status("Closed");
- },
+ }
- reopen_purchase_receipt: function() {
+ reopen_purchase_receipt() {
cur_frm.cscript.update_status("Submitted");
- },
+ }
- make_retention_stock_entry: function() {
+ make_retention_stock_entry() {
frappe.call({
method: "erpnext.stock.doctype.stock_entry.stock_entry.move_sample_to_retention_warehouse",
args:{
@@ -214,13 +214,13 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend
}
}
});
- },
+ }
- apply_putaway_rule: function() {
+ apply_putaway_rule() {
if (this.frm.doc.apply_putaway_rule) erpnext.apply_putaway_rule(this.frm);
}
-});
+};
// for backward compatibility: combine new and previous states
$.extend(cur_frm.cscript, new erpnext.stock.PurchaseReceiptController({frm: cur_frm}));
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 64dcbed1d8..16e74636ce 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -777,8 +777,8 @@ frappe.ui.form.on('Landed Cost Taxes and Charges', {
}
});
-erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
- setup: function() {
+erpnext.stock.StockEntry = class StockEntry extends erpnext.stock.StockController {
+ setup() {
var me = this;
this.setup_posting_date_time_check();
@@ -825,9 +825,9 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
frappe.dynamic_link = { doc: this.frm.doc, fieldname: 'supplier', doctype: 'Supplier' }
this.frm.set_query("supplier_address", erpnext.queries.address_query)
- },
+ }
- onload_post_render: function() {
+ onload_post_render() {
var me = this;
this.set_default_account(function() {
if(me.frm.doc.__islocal && me.frm.doc.company && !me.frm.doc.amended_from) {
@@ -836,9 +836,9 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
});
this.frm.get_field("items").grid.set_multiple_add("item_code", "qty");
- },
+ }
- refresh: function() {
+ refresh() {
var me = this;
erpnext.toggle_naming_series();
this.toggle_related_fields(this.frm.doc);
@@ -850,22 +850,22 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
erpnext.hide_company();
erpnext.utils.add_item(this.frm);
this.frm.trigger('add_to_transit');
- },
+ }
- scan_barcode: function() {
+ scan_barcode() {
let transaction_controller= new erpnext.TransactionController({frm:this.frm});
transaction_controller.scan_barcode();
- },
+ }
- on_submit: function() {
+ on_submit() {
this.clean_up();
- },
+ }
- after_cancel: function() {
+ after_cancel() {
this.clean_up();
- },
+ }
- set_default_account: function(callback) {
+ set_default_account(callback) {
var me = this;
if(this.frm.doc.company && erpnext.is_perpetual_inventory_enabled(this.frm.doc.company)) {
@@ -885,9 +885,9 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
}
});
}
- },
+ }
- clean_up: function() {
+ clean_up() {
// Clear Work Order record from locals, because it is updated via Stock Entry
if(this.frm.doc.work_order &&
in_list(["Manufacture", "Material Transfer for Manufacture", "Material Consumption for Manufacture"],
@@ -895,13 +895,13 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
frappe.model.remove_from_locals("Work Order",
this.frm.doc.work_order);
}
- },
+ }
- fg_completed_qty: function() {
+ fg_completed_qty() {
this.get_items();
- },
+ }
- get_items: function() {
+ get_items() {
var me = this;
if(!this.frm.doc.fg_completed_qty || !this.frm.doc.bom_no)
frappe.throw(__("BOM and Manufacturing Quantity are required"));
@@ -917,9 +917,9 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
}
});
}
- },
+ }
- work_order: function() {
+ work_order() {
var me = this;
this.toggle_enable_bom();
if(!me.frm.doc.work_order || me.frm.doc.job_card) {
@@ -952,13 +952,13 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
}
}
});
- },
+ }
- toggle_enable_bom: function() {
+ toggle_enable_bom() {
this.frm.toggle_enable("bom_no", !!!this.frm.doc.work_order);
- },
+ }
- add_excise_button: function() {
+ add_excise_button() {
if(frappe.boot.sysdefaults.country === "India")
this.frm.add_custom_button(__("Excise Invoice"), function() {
var excise = frappe.model.make_new_doc_and_get_name('Journal Entry');
@@ -966,35 +966,35 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
excise.voucher_type = 'Excise Entry';
frappe.set_route('Form', 'Journal Entry', excise.name);
}, __('Create'));
- },
+ }
- items_add: function(doc, cdt, cdn) {
+ items_add(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
this.frm.script_manager.copy_from_first_row("items", row, ["expense_account", "cost_center"]);
if(!row.s_warehouse) row.s_warehouse = this.frm.doc.from_warehouse;
if(!row.t_warehouse) row.t_warehouse = this.frm.doc.to_warehouse;
- },
+ }
- from_warehouse: function(doc) {
+ from_warehouse(doc) {
this.frm.trigger('set_tansit_warehouse');
this.set_warehouse_in_children(doc.items, "s_warehouse", doc.from_warehouse);
- },
+ }
- to_warehouse: function(doc) {
+ to_warehouse(doc) {
this.set_warehouse_in_children(doc.items, "t_warehouse", doc.to_warehouse);
- },
+ }
- set_warehouse_in_children: function(child_table, warehouse_field, warehouse) {
+ set_warehouse_in_children(child_table, warehouse_field, warehouse) {
let transaction_controller = new erpnext.TransactionController();
transaction_controller.autofill_warehouse(child_table, warehouse_field, warehouse);
- },
+ }
- items_on_form_rendered: function(doc, grid_row) {
+ items_on_form_rendered(doc, grid_row) {
erpnext.setup_serial_no();
- },
+ }
- toggle_related_fields: function(doc) {
+ toggle_related_fields(doc) {
this.frm.toggle_enable("from_warehouse", doc.purpose!='Material Receipt');
this.frm.toggle_enable("to_warehouse", doc.purpose!='Material Issue');
@@ -1021,12 +1021,12 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
doc.purpose!='Material Issue');
this.frm.fields_dict["items"].grid.set_column_disp("additional_cost", doc.purpose!='Material Issue');
- },
+ }
- supplier: function(doc) {
+ supplier(doc) {
erpnext.utils.get_party_details(this.frm, null, null, null);
}
-});
+};
erpnext.stock.select_batch_and_serial_no = (frm, item) => {
let get_warehouse_type_and_name = (item) => {
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
index ac4ed5e75d..3badc7ee60 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
@@ -220,8 +220,8 @@ frappe.ui.form.on("Stock Reconciliation Item", {
});
-erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({
- setup: function() {
+erpnext.stock.StockReconciliation = class StockReconciliation extends erpnext.stock.StockController {
+ setup() {
var me = this;
this.setup_posting_date_time_check();
@@ -249,17 +249,17 @@ erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({
}
}
}
- },
+ }
- refresh: function() {
+ refresh() {
if(this.frm.doc.docstatus > 0) {
this.show_stock_ledger();
if (erpnext.is_perpetual_inventory_enabled(this.frm.doc.company)) {
this.show_general_ledger();
}
}
- },
+ }
-});
+};
cur_frm.cscript = new erpnext.stock.StockReconciliation({frm: cur_frm});
diff --git a/erpnext/support/doctype/warranty_claim/warranty_claim.js b/erpnext/support/doctype/warranty_claim/warranty_claim.js
index 79f46758d1..c9aa41fdae 100644
--- a/erpnext/support/doctype/warranty_claim/warranty_claim.js
+++ b/erpnext/support/doctype/warranty_claim/warranty_claim.js
@@ -36,8 +36,8 @@ frappe.ui.form.on("Warranty Claim", {
}
});
-erpnext.support.WarrantyClaim = frappe.ui.form.Controller.extend({
- refresh: function() {
+erpnext.support.WarrantyClaim = class WarrantyClaim extends frappe.ui.form.Controller {
+ refresh() {
frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
if(!cur_frm.doc.__islocal &&
@@ -45,15 +45,15 @@ erpnext.support.WarrantyClaim = frappe.ui.form.Controller.extend({
cur_frm.add_custom_button(__('Maintenance Visit'),
this.make_maintenance_visit);
}
- },
+ }
- make_maintenance_visit: function() {
+ make_maintenance_visit() {
frappe.model.open_mapped_doc({
method: "erpnext.support.doctype.warranty_claim.warranty_claim.make_maintenance_visit",
frm: cur_frm
})
}
-});
+};
$.extend(cur_frm.cscript, new erpnext.support.WarrantyClaim({frm: cur_frm}));
diff --git a/erpnext/templates/includes/rfq.js b/erpnext/templates/includes/rfq.js
index b56c416dbd..37beb5a584 100644
--- a/erpnext/templates/includes/rfq.js
+++ b/erpnext/templates/includes/rfq.js
@@ -11,23 +11,23 @@ $(document).ready(function() {
doc.buying_price_list = "{{ doc.buying_price_list }}"
});
-rfq = Class.extend({
- init: function(){
+rfq = class rfq {
+ constructor(){
this.onfocus_select_all();
this.change_qty();
this.change_rate();
this.terms();
this.submit_rfq();
this.navigate_quotations();
- },
+ }
- onfocus_select_all: function(){
+ onfocus_select_all(){
$("input").click(function(){
$(this).select();
})
- },
+ }
- change_qty: function(){
+ change_qty(){
var me = this;
$('.rfq-items').on("change", ".rfq-qty", function(){
me.idx = parseFloat($(this).attr('data-idx'));
@@ -36,9 +36,9 @@ rfq = Class.extend({
me.update_qty_rate();
$(this).val(format_number(me.qty, doc.number_format, 2));
})
- },
+ }
- change_rate: function(){
+ change_rate(){
var me = this;
$(".rfq-items").on("change", ".rfq-rate", function(){
me.idx = parseFloat($(this).attr('data-idx'));
@@ -47,15 +47,15 @@ rfq = Class.extend({
me.update_qty_rate();
$(this).val(format_number(me.rate, doc.number_format, 2));
})
- },
+ }
- terms: function(){
+ terms(){
$(".terms").on("change", ".terms-feedback", function(){
doc.terms = $(this).val();
})
- },
+ }
- update_qty_rate: function(){
+ update_qty_rate(){
var me = this;
doc.grand_total = 0.0;
$.each(doc.items, function(idx, data){
@@ -69,9 +69,9 @@ rfq = Class.extend({
doc.grand_total += flt(data.amount);
$('.tax-grand-total').text(format_number(doc.grand_total, doc.number_format, 2));
})
- },
+ }
- submit_rfq: function(){
+ submit_rfq(){
$('.btn-sm').click(function(){
frappe.freeze();
frappe.call({
@@ -90,12 +90,12 @@ rfq = Class.extend({
}
})
})
- },
+ }
- navigate_quotations: function() {
+ navigate_quotations() {
$('.quotations').click(function(){
name = $(this).attr('idx')
window.location.href = "/quotations/" + encodeURIComponent(name);
})
}
-})
+}
From 5b9d3f15a243511a4fedcd12eb25fbd248399aac Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Tue, 27 Apr 2021 12:34:10 +0200
Subject: [PATCH 014/149] docs: replace whitespace indent in docstring with
tabs
---
erpnext/regional/report/datev/datev.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py
index 1a215031c1..a5ca7eee5d 100644
--- a/erpnext/regional/report/datev/datev.py
+++ b/erpnext/regional/report/datev/datev.py
@@ -3,9 +3,9 @@
Provide a report and downloadable CSV according to the German DATEV format.
- Query report showing only the columns that contain data, formatted nicely for
- dispay to the user.
+ dispay to the user.
- CSV download functionality `download_datev_csv` that provides a CSV file with
- all required columns. Used to import the data into the DATEV Software.
+ all required columns. Used to import the data into the DATEV Software.
"""
from __future__ import unicode_literals
From 35d4829383e278809bc64784b5d8a558db2ac61f Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Sat, 1 May 2021 13:07:26 +0530
Subject: [PATCH 015/149] fix: serial no changed after saving stock
reconciliation
---
.../report/project_profitability/project_profitability.py | 5 +++--
.../doctype/stock_reconciliation/stock_reconciliation.py | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/erpnext/projects/report/project_profitability/project_profitability.py b/erpnext/projects/report/project_profitability/project_profitability.py
index 5ad2d85232..9139d84fac 100644
--- a/erpnext/projects/report/project_profitability/project_profitability.py
+++ b/erpnext/projects/report/project_profitability/project_profitability.py
@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
+from frappe.utils import flt
def execute(filters=None):
columns, data = [], []
@@ -52,8 +53,8 @@ def get_rows(filters):
def calculate_cost_and_profit(data):
for row in data:
- row.fractional_cost = row.base_gross_pay * row.utilization
- row.profit = row.base_grand_total - row.base_gross_pay * row.utilization
+ row.fractional_cost = flt(row.base_gross_pay) * flt(row.utilization)
+ row.profit = flt(row.base_grand_total) - flt(row.base_gross_pay) * flt(row.utilization)
return data
def get_conditions(filters):
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 1396f19d3f..e4cdcb4116 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -72,7 +72,7 @@ class StockReconciliation(StockController):
if item_dict.get("serial_nos"):
item.current_serial_no = item_dict.get("serial_nos")
- if self.purpose == "Stock Reconciliation":
+ if self.purpose == "Stock Reconciliation" and not item.serial_no::
item.serial_no = item.current_serial_no
item.current_qty = item_dict.get("qty")
From 6a5a380c07893f45f72f57ff3ac135b48f207ed0 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Sun, 2 May 2021 18:02:28 +0530
Subject: [PATCH 016/149] fix: total stock summary report not working
---
erpnext/stock/report/total_stock_summary/total_stock_summary.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/stock/report/total_stock_summary/total_stock_summary.py b/erpnext/stock/report/total_stock_summary/total_stock_summary.py
index ed52393923..59c253c425 100644
--- a/erpnext/stock/report/total_stock_summary/total_stock_summary.py
+++ b/erpnext/stock/report/total_stock_summary/total_stock_summary.py
@@ -51,7 +51,7 @@ def get_total_stock(filters):
INNER JOIN `tabWarehouse` warehouse
ON warehouse.name = ledger.warehouse
WHERE
- actual_qty != 0 %s""" % (columns, conditions))
+ ledger.actual_qty != 0 %s""" % (columns, conditions))
def validate_filters(filters):
if filters.get("group_by") == 'Company' and \
From 9cc7c294e78b2580351b7e033bb6506143d3c263 Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Mon, 3 May 2021 10:25:53 +0530
Subject: [PATCH 017/149] Update stock_reconciliation.py
---
.../stock/doctype/stock_reconciliation/stock_reconciliation.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index e4cdcb4116..2029b0708a 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -72,7 +72,7 @@ class StockReconciliation(StockController):
if item_dict.get("serial_nos"):
item.current_serial_no = item_dict.get("serial_nos")
- if self.purpose == "Stock Reconciliation" and not item.serial_no::
+ if self.purpose == "Stock Reconciliation" and not item.serial_no:
item.serial_no = item.current_serial_no
item.current_qty = item_dict.get("qty")
From e36f3030422babc8aed6207c9534716bfb5ae921 Mon Sep 17 00:00:00 2001
From: 18alantom <2.alan.tom@gmail.com>
Date: Mon, 3 May 2021 19:49:22 +0530
Subject: [PATCH 018/149] fix: use percent string templates for db.sql calls
---
erpnext/stock/get_item_details.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 3fc1df76bc..98d08c0a18 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -935,8 +935,8 @@ def get_bin_details(item_code, warehouse, company=None):
def get_company_total_stock(item_code, company):
return frappe.db.sql("""SELECT sum(actual_qty) from
(`tabBin` INNER JOIN `tabWarehouse` ON `tabBin`.warehouse = `tabWarehouse`.name)
- WHERE `tabWarehouse`.company = '{0}' and `tabBin`.item_code = '{1}'"""
- .format(company, item_code))[0][0]
+ WHERE `tabWarehouse`.company = %s and `tabBin`.item_code = %s""",
+ (company, item_code))[0][0]
@frappe.whitelist()
def get_serial_no_details(item_code, warehouse, stock_qty, serial_no):
From 308905b1bee572c0161c26e0f89bf8a2a86c0c1f Mon Sep 17 00:00:00 2001
From: 18alantom <2.alan.tom@gmail.com>
Date: Mon, 3 May 2021 23:34:34 +0530
Subject: [PATCH 019/149] fix: semgrep, refactor default mutable dict
---
erpnext/stock/get_item_details.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 98d08c0a18..3832415db6 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -470,7 +470,9 @@ def get_item_tax_template(args, item, out):
item_tax_template = _get_item_tax_template(args, item_group_doc.taxes, out)
item_group = item_group_doc.parent_item_group
-def _get_item_tax_template(args, taxes, out={}, for_validate=False):
+def _get_item_tax_template(args, taxes, out=None, for_validate=False):
+ if out is None:
+ out = {}
taxes_with_validity = []
taxes_with_no_validity = []
From 076020643d55252c881cdc20ff1e169af97fb897 Mon Sep 17 00:00:00 2001
From: Saqib
Date: Tue, 4 May 2021 12:26:49 +0530
Subject: [PATCH 020/149] fix: empty payment term column in accounts receivable
report (#25556)
---
.../report/accounts_receivable/accounts_receivable.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 444b40ed79..db605f7285 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -364,7 +364,7 @@ class ReceivablePayableReport(object):
payment_terms_details = frappe.db.sql("""
select
si.name, si.party_account_currency, si.currency, si.conversion_rate,
- ps.due_date, ps.payment_amount, ps.description, ps.paid_amount, ps.discounted_amount
+ ps.due_date, ps.payment_term, ps.payment_amount, ps.description, ps.paid_amount, ps.discounted_amount
from `tab{0}` si, `tabPayment Schedule` ps
where
si.name = ps.parent and
@@ -394,7 +394,7 @@ class ReceivablePayableReport(object):
"due_date": d.due_date,
"invoiced": invoiced,
"invoice_grand_total": row.invoiced,
- "payment_term": d.description,
+ "payment_term": d.description or d.payment_term,
"paid": d.paid_amount + d.discounted_amount,
"credit_note": 0.0,
"outstanding": invoiced - d.paid_amount - d.discounted_amount
From 1e554378c7b79b03fc669056fc2653d993b3466a Mon Sep 17 00:00:00 2001
From: Saqib
Date: Tue, 4 May 2021 12:28:24 +0530
Subject: [PATCH 021/149] fix(pos): incorrect expense account set in pos
invoice (#25571)
From 384f4b5b7e6d23436046d0f84888c5687cdca7f7 Mon Sep 17 00:00:00 2001
From: Saqib
Date: Tue, 4 May 2021 12:33:49 +0530
Subject: [PATCH 022/149] fix: can't open general ledger from consolidated
financial report (#25542)
---
.../consolidated_financial_statement.js | 224 +++++++++---------
.../consolidated_financial_statement.py | 5 +-
2 files changed, 120 insertions(+), 109 deletions(-)
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
index 09479221fb..1363b53746 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
@@ -2,118 +2,128 @@
// For license information, please see license.txt
/* eslint-disable */
-frappe.query_reports["Consolidated Financial Statement"] = {
- "filters": [
- {
- "fieldname":"company",
- "label": __("Company"),
- "fieldtype": "Link",
- "options": "Company",
- "default": frappe.defaults.get_user_default("Company"),
- "reqd": 1
- },
- {
- "fieldname":"filter_based_on",
- "label": __("Filter Based On"),
- "fieldtype": "Select",
- "options": ["Fiscal Year", "Date Range"],
- "default": ["Fiscal Year"],
- "reqd": 1,
- on_change: function() {
- let filter_based_on = frappe.query_report.get_filter_value('filter_based_on');
- frappe.query_report.toggle_filter_display('from_fiscal_year', filter_based_on === 'Date Range');
- frappe.query_report.toggle_filter_display('to_fiscal_year', filter_based_on === 'Date Range');
- frappe.query_report.toggle_filter_display('period_start_date', filter_based_on === 'Fiscal Year');
- frappe.query_report.toggle_filter_display('period_end_date', filter_based_on === 'Fiscal Year');
+frappe.require("assets/erpnext/js/financial_statements.js", function() {
+ frappe.query_reports["Consolidated Financial Statement"] = {
+ "filters": [
+ {
+ "fieldname":"company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "default": frappe.defaults.get_user_default("Company"),
+ "reqd": 1
+ },
+ {
+ "fieldname":"filter_based_on",
+ "label": __("Filter Based On"),
+ "fieldtype": "Select",
+ "options": ["Fiscal Year", "Date Range"],
+ "default": ["Fiscal Year"],
+ "reqd": 1,
+ on_change: function() {
+ let filter_based_on = frappe.query_report.get_filter_value('filter_based_on');
+ frappe.query_report.toggle_filter_display('from_fiscal_year', filter_based_on === 'Date Range');
+ frappe.query_report.toggle_filter_display('to_fiscal_year', filter_based_on === 'Date Range');
+ frappe.query_report.toggle_filter_display('period_start_date', filter_based_on === 'Fiscal Year');
+ frappe.query_report.toggle_filter_display('period_end_date', filter_based_on === 'Fiscal Year');
- frappe.query_report.refresh();
+ frappe.query_report.refresh();
+ }
+ },
+ {
+ "fieldname":"period_start_date",
+ "label": __("Start Date"),
+ "fieldtype": "Date",
+ "hidden": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname":"period_end_date",
+ "label": __("End Date"),
+ "fieldtype": "Date",
+ "hidden": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname":"from_fiscal_year",
+ "label": __("Start Year"),
+ "fieldtype": "Link",
+ "options": "Fiscal Year",
+ "default": frappe.defaults.get_user_default("fiscal_year"),
+ "reqd": 1
+ },
+ {
+ "fieldname":"to_fiscal_year",
+ "label": __("End Year"),
+ "fieldtype": "Link",
+ "options": "Fiscal Year",
+ "default": frappe.defaults.get_user_default("fiscal_year"),
+ "reqd": 1
+ },
+ {
+ "fieldname":"finance_book",
+ "label": __("Finance Book"),
+ "fieldtype": "Link",
+ "options": "Finance Book"
+ },
+ {
+ "fieldname":"report",
+ "label": __("Report"),
+ "fieldtype": "Select",
+ "options": ["Profit and Loss Statement", "Balance Sheet", "Cash Flow"],
+ "default": "Balance Sheet",
+ "reqd": 1
+ },
+ {
+ "fieldname": "presentation_currency",
+ "label": __("Currency"),
+ "fieldtype": "Select",
+ "options": erpnext.get_presentation_currency_list(),
+ "default": frappe.defaults.get_user_default("Currency")
+ },
+ {
+ "fieldname":"accumulated_in_group_company",
+ "label": __("Accumulated Values in Group Company"),
+ "fieldtype": "Check",
+ "default": 0
+ },
+ {
+ "fieldname": "include_default_book_entries",
+ "label": __("Include Default Book Entries"),
+ "fieldtype": "Check",
+ "default": 1
+ }
+ ],
+ "formatter": function(value, row, column, data, default_formatter) {
+ if (data && column.fieldname=="account") {
+ value = data.account_name || value;
+
+ column.link_onclick =
+ "erpnext.financial_statements.open_general_ledger(" + JSON.stringify(data) + ")";
+ column.is_tree = true;
}
- },
- {
- "fieldname":"period_start_date",
- "label": __("Start Date"),
- "fieldtype": "Date",
- "hidden": 1,
- "reqd": 1
- },
- {
- "fieldname":"period_end_date",
- "label": __("End Date"),
- "fieldtype": "Date",
- "hidden": 1,
- "reqd": 1
- },
- {
- "fieldname":"from_fiscal_year",
- "label": __("Start Year"),
- "fieldtype": "Link",
- "options": "Fiscal Year",
- "default": frappe.defaults.get_user_default("fiscal_year"),
- "reqd": 1
- },
- {
- "fieldname":"to_fiscal_year",
- "label": __("End Year"),
- "fieldtype": "Link",
- "options": "Fiscal Year",
- "default": frappe.defaults.get_user_default("fiscal_year"),
- "reqd": 1
- },
- {
- "fieldname":"finance_book",
- "label": __("Finance Book"),
- "fieldtype": "Link",
- "options": "Finance Book"
- },
- {
- "fieldname":"report",
- "label": __("Report"),
- "fieldtype": "Select",
- "options": ["Profit and Loss Statement", "Balance Sheet", "Cash Flow"],
- "default": "Balance Sheet",
- "reqd": 1
- },
- {
- "fieldname": "presentation_currency",
- "label": __("Currency"),
- "fieldtype": "Select",
- "options": erpnext.get_presentation_currency_list(),
- "default": frappe.defaults.get_user_default("Currency")
- },
- {
- "fieldname":"accumulated_in_group_company",
- "label": __("Accumulated Values in Group Company"),
- "fieldtype": "Check",
- "default": 0
- },
- {
- "fieldname": "include_default_book_entries",
- "label": __("Include Default Book Entries"),
- "fieldtype": "Check",
- "default": 1
- }
- ],
- "formatter": function(value, row, column, data, default_formatter) {
- value = default_formatter(value, row, column, data);
- if (!data.parent_account) {
- value = $(`${value} `);
+ value = default_formatter(value, row, column, data);
- var $value = $(value).css("font-weight", "bold");
+ if (!data.parent_account) {
+ value = $(`${value} `);
- value = $value.wrap("
").parent().html();
- }
- return value;
- },
- onload: function() {
- let fiscal_year = frappe.defaults.get_user_default("fiscal_year")
+ var $value = $(value).css("font-weight", "bold");
- frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) {
- var fy = frappe.model.get_doc("Fiscal Year", fiscal_year);
- frappe.query_report.set_filter_value({
- period_start_date: fy.year_start_date,
- period_end_date: fy.year_end_date
+ value = $value.wrap("
").parent().html();
+ }
+ return value;
+ },
+ onload: function() {
+ let fiscal_year = frappe.defaults.get_user_default("fiscal_year")
+
+ frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) {
+ var fy = frappe.model.get_doc("Fiscal Year", fiscal_year);
+ frappe.query_report.set_filter_value({
+ period_start_date: fy.year_start_date,
+ period_end_date: fy.year_end_date
+ });
});
- });
+ }
}
-}
+});
\ No newline at end of file
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
index 0c4a422440..094f5db89b 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -329,8 +329,9 @@ def prepare_data(accounts, start_date, end_date, balance_must_be, companies, com
has_value = False
total = 0
row = frappe._dict({
- "account_name": _(d.account_name),
- "account": _(d.account_name),
+ "account_name": ('%s - %s' %(_(d.account_number), _(d.account_name))
+ if d.account_number else _(d.account_name)),
+ "account": _(d.name),
"parent_account": _(d.parent_account),
"indent": flt(d.indent),
"year_start_date": start_date,
From ba8dc1ffbd8d02cb6d01e3b10c0c21a9956bcca3 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Tue, 4 May 2021 15:03:10 +0530
Subject: [PATCH 023/149] fix: stock balance and batchwise balance history
report showing different closing stock
---
.../batch_wise_balance_history/batch_wise_balance_history.py | 2 +-
erpnext/stock/report/stock_balance/stock_balance.py | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
index 087c12ed2d..01927c2d10 100644
--- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
+++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
@@ -70,7 +70,7 @@ def get_stock_ledger_entries(filters):
return frappe.db.sql("""
select item_code, batch_no, warehouse, posting_date, sum(actual_qty) as actual_qty
from `tabStock Ledger Entry`
- where docstatus < 2 and ifnull(batch_no, '') != '' %s
+ where is_cancelled = 0 and docstatus < 2 and ifnull(batch_no, '') != '' %s
group by voucher_no, batch_no, item_code, warehouse
order by item_code, warehouse""" %
conditions, as_dict=1)
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index 6dfede4590..bbd73e9112 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -165,7 +165,7 @@ def get_stock_ledger_entries(filters, items):
select
sle.item_code, warehouse, sle.posting_date, sle.actual_qty, sle.valuation_rate,
sle.company, sle.voucher_type, sle.qty_after_transaction, sle.stock_value_difference,
- sle.item_code as name, sle.voucher_no, sle.stock_value
+ sle.item_code as name, sle.voucher_no, sle.stock_value, sle.batch_no
from
`tabStock Ledger Entry` sle force index (posting_sort_index)
where sle.docstatus < 2 %s %s
@@ -193,7 +193,7 @@ def get_item_warehouse_map(filters, sle):
qty_dict = iwb_map[(d.company, d.item_code, d.warehouse)]
- if d.voucher_type == "Stock Reconciliation":
+ if d.voucher_type == "Stock Reconciliation" and not d.batch_no:
qty_diff = flt(d.qty_after_transaction) - flt(qty_dict.bal_qty)
else:
qty_diff = flt(d.actual_qty)
From eebc6e9277b3d461ae4da4a92fa9cc45c27eea55 Mon Sep 17 00:00:00 2001
From: Afshan <33727827+AfshanKhan@users.noreply.github.com>
Date: Tue, 4 May 2021 17:05:12 +0530
Subject: [PATCH 024/149] refactor: Show item's full name on hover over item in
POS (#25554)
Co-authored-by: Saqib
---
.../page/point_of_sale/pos_item_selector.js | 20 ++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js
index 709fe57747..9384ae5542 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_selector.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js
@@ -81,13 +81,24 @@ erpnext.PointOfSale.ItemSelector = class {
const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom } = item;
const indicator_color = actual_qty > 10 ? "green" : actual_qty <= 0 ? "red" : "orange";
+ let qty_to_display = actual_qty;
+
+ if (Math.round(qty_to_display) > 999) {
+ qty_to_display = Math.round(qty_to_display)/1000;
+ qty_to_display = qty_to_display.toFixed(1) + 'K';
+ }
+
function get_item_image_html() {
if (!me.hide_images && item_image) {
- return `
+ return `
+ ${qty_to_display}
+
`;
} else {
- return `
${frappe.get_abbr(item.item_name)}
`;
+ return `
+ ${qty_to_display}
+
${frappe.get_abbr(item.item_name)}
`;
}
}
@@ -95,13 +106,12 @@ erpnext.PointOfSale.ItemSelector = class {
`
+ title="${item.item_name}">
${get_item_image_html()}
-
${frappe.ellipsis(item.item_name, 18)}
${format_currency(item.price_list_rate, item.currency, 0) || 0}
@@ -316,4 +326,4 @@ erpnext.PointOfSale.ItemSelector = class {
toggle_component(show) {
show ? this.$component.css('display', 'flex') : this.$component.css('display', 'none');
}
-};
\ No newline at end of file
+};
From cd8ee8ea97bcf899e23438991fed1bdfd540a490 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 4 May 2021 18:36:45 +0530
Subject: [PATCH 025/149] ci: Try Parallel tests
---
.github/helper/install.sh | 2 +-
.github/workflows/ci-tests.yml | 55 ++++++++++++++++++----------------
2 files changed, 30 insertions(+), 27 deletions(-)
diff --git a/.github/helper/install.sh b/.github/helper/install.sh
index 7b0f944c66..fd32624c2d 100644
--- a/.github/helper/install.sh
+++ b/.github/helper/install.sh
@@ -12,7 +12,7 @@ sudo apt install npm
pip install frappe-bench
-git clone https://github.com/frappe/frappe --branch "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}" --depth 1
+git clone https://github.com/surajshetty3416/frappe --branch "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}" --depth 1
bench init --skip-assets --frappe-path ~/frappe --python "$(which python)" frappe-bench
mkdir ~/frappe-bench/sites/test_site
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
index 84ecfb1457..de8d7ac503 100644
--- a/.github/workflows/ci-tests.yml
+++ b/.github/workflows/ci-tests.yml
@@ -13,7 +13,10 @@ jobs:
include:
- TYPE: "server"
JOB_NAME: "Server"
- RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-tests --app erpnext --coverage
+ RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext
+ - TYPE: "server"
+ JOB_NAME: "Server"
+ RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext
- TYPE: "patch"
JOB_NAME: "Patch"
RUN_COMMAND: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz && bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate
@@ -80,29 +83,29 @@ jobs:
env:
TYPE: ${{ matrix.TYPE }}
- - name: Coverage - Pull Request
- if: matrix.TYPE == 'server' && github.event_name == 'pull_request'
- run: |
- cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
- cd ${GITHUB_WORKSPACE}
- pip install coveralls==2.2.0
- pip install coverage==4.5.4
- coveralls --service=github
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
- COVERALLS_SERVICE_NAME: github
-
- - name: Coverage - Push
- if: matrix.TYPE == 'server' && github.event_name == 'push'
- run: |
- cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
- cd ${GITHUB_WORKSPACE}
- pip install coveralls==2.2.0
- pip install coverage==4.5.4
- coveralls --service=github-actions
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
- COVERALLS_SERVICE_NAME: github-actions
+ # - name: Coverage - Pull Request
+ # if: matrix.TYPE == 'server' && github.event_name == 'pull_request'
+ # run: |
+ # cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
+ # cd ${GITHUB_WORKSPACE}
+ # pip install coveralls==2.2.0
+ # pip install coverage==4.5.4
+ # coveralls --service=github
+ # env:
+ # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
+ # COVERALLS_SERVICE_NAME: github
+
+ # - name: Coverage - Push
+ # if: matrix.TYPE == 'server' && github.event_name == 'push'
+ # run: |
+ # cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
+ # cd ${GITHUB_WORKSPACE}
+ # pip install coveralls==2.2.0
+ # pip install coverage==4.5.4
+ # coveralls --service=github-actions
+ # env:
+ # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
+ # COVERALLS_SERVICE_NAME: github-actions
From ee35444c3fc029e3032befaebda61925248a53f7 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 4 May 2021 18:58:20 +0530
Subject: [PATCH 026/149] fix: Frappe branch
---
.github/helper/install.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/helper/install.sh b/.github/helper/install.sh
index fd32624c2d..44659f22fa 100644
--- a/.github/helper/install.sh
+++ b/.github/helper/install.sh
@@ -12,7 +12,7 @@ sudo apt install npm
pip install frappe-bench
-git clone https://github.com/surajshetty3416/frappe --branch "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}" --depth 1
+git clone https://github.com/surajshetty3416/frappe --branch "python-distributed-testing" --depth 1
bench init --skip-assets --frappe-path ~/frappe --python "$(which python)" frappe-bench
mkdir ~/frappe-bench/sites/test_site
From 18ad15ed160ce209cea7b6da7cc6fc07fb3ee152 Mon Sep 17 00:00:00 2001
From: Asharam Seervi
Date: Tue, 4 May 2021 19:28:07 +0530
Subject: [PATCH 027/149] fix: designation insufficient permission on lead
doctype. (#25331)
---
erpnext/hr/doctype/designation/designation.json | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/erpnext/hr/doctype/designation/designation.json b/erpnext/hr/doctype/designation/designation.json
index 4c3888be4a..bab6b90d1a 100644
--- a/erpnext/hr/doctype/designation/designation.json
+++ b/erpnext/hr/doctype/designation/designation.json
@@ -182,6 +182,10 @@
"share": 1,
"submit": 0,
"write": 1
+ },
+ {
+ "read": 1,
+ "role": "Sales User"
}
],
"quick_entry": 1,
@@ -191,4 +195,4 @@
"track_changes": 0,
"track_seen": 0,
"track_views": 0
-}
\ No newline at end of file
+}
From 04923d6a65637e7e6c50db826b46e92bbb491c2e Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Tue, 4 May 2021 21:01:12 +0530
Subject: [PATCH 028/149] fix: function call to update payment schedule labels
---
erpnext/public/js/controllers/transaction.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index f91b432a39..d218a5ee5f 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1384,7 +1384,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
company_currency, "payment_schedule");
this.frm.set_currency_labels(["payment_amount", "outstanding", "paid_amount"],
this.frm.doc.currency, "payment_schedule");
-
+
var schedule_grid = this.frm.fields_dict["payment_schedule"].grid;
$.each(["base_payment_amount", "base_outstanding", "base_paid_amount"], function(i, fname) {
if (frappe.meta.get_docfield(schedule_grid.doctype, fname))
@@ -2034,7 +2034,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
if(r.message && !r.exc) {
me.frm.set_value("payment_schedule", r.message);
const company_currency = me.get_company_currency();
- this.update_payment_schedule_grid_labels(company_currency);
+ me.update_payment_schedule_grid_labels(company_currency);
}
}
})
From 2a20a03c28c32944b5a5726241906010d42456af Mon Sep 17 00:00:00 2001
From: 18alantom <2.alan.tom@gmail.com>
Date: Wed, 5 May 2021 11:59:15 +0530
Subject: [PATCH 029/149] fix: check for None in item.schedule_date before
setting
---
erpnext/controllers/buying_controller.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index b686dc026c..3f2d3390c0 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -838,9 +838,10 @@ class BuyingController(StockController):
if not self.get("items"):
return
- earliest_schedule_date = min([d.schedule_date for d in self.get("items")])
- if earliest_schedule_date:
- self.schedule_date = earliest_schedule_date
+ if any(d.schedule_date for d in self.get("items")):
+ # Select earliest schedule_date.
+ self.schedule_date = min(d.schedule_date for d in self.get("items")
+ if d.schedule_date is not None)
if self.schedule_date:
for d in self.get('items'):
From 1bb7bb74adb4b07bd2efc6e2fb641ed84a262fae Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Wed, 5 May 2021 12:19:57 +0530
Subject: [PATCH 030/149] fix: Check if payment schedule exits before updating
label
---
erpnext/public/js/controllers/transaction.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index d218a5ee5f..10c802c6f0 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1379,7 +1379,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
update_payment_schedule_grid_labels: function(company_currency) {
const me = this;
- if (this.frm.fields_dict["payment_schedule"]) {
+ if (this.frm.doc.payment_schedule.length > 0) {
this.frm.set_currency_labels(["base_payment_amount", "base_outstanding", "base_paid_amount"],
company_currency, "payment_schedule");
this.frm.set_currency_labels(["payment_amount", "outstanding", "paid_amount"],
From 136eb30081b7b74d3b500acf6731696b4692da8e Mon Sep 17 00:00:00 2001
From: 18alantom <2.alan.tom@gmail.com>
Date: Wed, 5 May 2021 12:26:29 +0530
Subject: [PATCH 031/149] fix: use get_serial_nos for splitting
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 4461f29fe3..4de877353a 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1111,7 +1111,7 @@ class SalesInvoice(SellingController):
if not item.serial_no:
continue
- for serial_no in item.serial_no.split("\n"):
+ for serial_no in get_serial_nos(item.serial_no):
if serial_no and frappe.db.get_value('Serial No', serial_no, 'item_code') == item.item_code:
frappe.db.set_value('Serial No', serial_no, 'sales_invoice', invoice)
From ffea9d4126c9ab544ac7a659874b9f41254404ec Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Wed, 5 May 2021 12:28:40 +0530
Subject: [PATCH 032/149] fix: Check if payment schedule exists
---
erpnext/public/js/controllers/transaction.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 10c802c6f0..0af8da77a0 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1379,7 +1379,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
update_payment_schedule_grid_labels: function(company_currency) {
const me = this;
- if (this.frm.doc.payment_schedule.length > 0) {
+ if (this.frm.doc.payment_schedule && this.frm.doc.payment_schedule.length > 0) {
this.frm.set_currency_labels(["base_payment_amount", "base_outstanding", "base_paid_amount"],
company_currency, "payment_schedule");
this.frm.set_currency_labels(["payment_amount", "outstanding", "paid_amount"],
From 85b675a554cfcdf78cfa5255e0a12e06e7e02e44 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Wed, 5 May 2021 20:57:31 +0530
Subject: [PATCH 033/149] fix: Invoices not fetch during payment reconciliation
---
.../doctype/payment_reconciliation/payment_reconciliation.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index cf6ec18f3b..6635128f9e 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -114,7 +114,7 @@ class PaymentReconciliation(Document):
'party_type': self.party_type,
'voucher_type': voucher_type,
'account': self.receivable_payable_account
- }, as_dict=1, debug=1)
+ }, as_dict=1)
def add_payment_entries(self, entries):
self.set('payments', [])
From bb3e5d00f44869132d869fbead5046ba1d3ddfc6 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Sat, 24 Apr 2021 17:28:33 +0530
Subject: [PATCH 034/149] fix: allow to receive same serial numbers multiple
times
---
.../purchase_receipt/test_purchase_receipt.py | 83 +++++++++++++------
erpnext/stock/doctype/serial_no/serial_no.py | 18 +---
.../stock/report/serial_no_ledger/__init__.py | 0
.../serial_no_ledger/serial_no_ledger.js | 52 ++++++++++++
.../serial_no_ledger/serial_no_ledger.json | 33 ++++++++
.../serial_no_ledger/serial_no_ledger.py | 53 ++++++++++++
erpnext/stock/stock_ledger.py | 53 ++++++++++--
7 files changed, 247 insertions(+), 45 deletions(-)
create mode 100644 erpnext/stock/report/serial_no_ledger/__init__.py
create mode 100644 erpnext/stock/report/serial_no_ledger/serial_no_ledger.js
create mode 100644 erpnext/stock/report/serial_no_ledger/serial_no_ledger.json
create mode 100644 erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 16eea24f84..f9b2c1d787 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -13,8 +13,9 @@ from erpnext.stock.doctype.serial_no.serial_no import SerialNoDuplicateError
from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.stock.doctype.item.test_item import make_item
from six import iteritems
+from erpnext.stock.stock_ledger import SerialNoExistsInFutureTransaction
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
-
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
class TestPurchaseReceipt(unittest.TestCase):
def setUp(self):
@@ -144,6 +145,62 @@ class TestPurchaseReceipt(unittest.TestCase):
self.assertFalse(frappe.db.get_value('Batch', {'item': item.name, 'reference_name': pr.name}))
self.assertFalse(frappe.db.get_all('Serial No', {'batch_no': batch_no}))
+ def test_duplicate_serial_nos(self):
+ from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+
+ item = frappe.db.exists("Item", {'item_name': 'Test Serialized Item 123'})
+ if not item:
+ item = create_item("Test Serialized Item 123")
+ item.has_serial_no = 1
+ item.serial_no_series = "TSI123-.####"
+ item.save()
+ else:
+ item = frappe.get_doc("Item", {'item_name': 'Test Serialized Item 123'})
+
+ # First make purchase receipt
+ pr = make_purchase_receipt(item_code=item.name, qty=2, rate=500)
+ pr.load_from_db()
+
+ serial_nos = frappe.db.get_value('Stock Ledger Entry',
+ {'voucher_type': 'Purchase Receipt', 'voucher_no': pr.name, 'item_code': item.name}, 'serial_no')
+
+ serial_nos = get_serial_nos(serial_nos)
+
+ self.assertEquals(get_serial_nos(pr.items[0].serial_no), serial_nos)
+
+ # Then tried to receive same serial nos in difference company
+ pr_different_company = make_purchase_receipt(item_code=item.name, qty=2, rate=500,
+ serial_no='\n'.join(serial_nos), company='_Test Company 1', do_not_submit=True,
+ warehouse = 'Stores - _TC1')
+
+ self.assertRaises(SerialNoDuplicateError, pr_different_company.submit)
+
+ # Then made delivery note to remove the serial nos from stock
+ dn = create_delivery_note(item_code=item.name, qty=2, rate = 1500, serial_no='\n'.join(serial_nos))
+ dn.load_from_db()
+ self.assertEquals(get_serial_nos(dn.items[0].serial_no), serial_nos)
+
+ posting_date = add_days(today(), -3)
+
+ # Try to receive same serial nos again in the same company with backdated.
+ pr1 = make_purchase_receipt(item_code=item.name, qty=2, rate=500,
+ posting_date=posting_date, serial_no='\n'.join(serial_nos), do_not_submit=True)
+
+ self.assertRaises(SerialNoExistsInFutureTransaction, pr1.submit)
+
+ # Try to receive same serial nos with different company with backdated.
+ pr2 = make_purchase_receipt(item_code=item.name, qty=2, rate=500,
+ posting_date=posting_date, serial_no='\n'.join(serial_nos), company='_Test Company 1', do_not_submit=True,
+ warehouse = 'Stores - _TC1')
+
+ self.assertRaises(SerialNoExistsInFutureTransaction, pr2.submit)
+
+ # Receive the same serial nos after the delivery note posting date and time
+ make_purchase_receipt(item_code=item.name, qty=2, rate=500, serial_no='\n'.join(serial_nos))
+
+ # Raise the error for backdated deliver note entry cancel
+ self.assertRaises(SerialNoExistsInFutureTransaction, dn.cancel)
+
def test_purchase_receipt_gl_entry(self):
pr = make_purchase_receipt(company="_Test Company with perpetual inventory",
warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1",
@@ -562,30 +619,6 @@ class TestPurchaseReceipt(unittest.TestCase):
new_pr_doc.cancel()
- def test_not_accept_duplicate_serial_no(self):
- from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
- from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
-
- item_code = frappe.db.get_value('Item', {'has_serial_no': 1, 'is_fixed_asset': 0, "has_batch_no": 0})
- if not item_code:
- item = make_item("Test Serial Item 1", dict(has_serial_no=1, has_batch_no=0))
- item_code = item.name
-
- serial_no = random_string(5)
- pr1 = make_purchase_receipt(item_code=item_code, qty=1, serial_no=serial_no)
- dn = create_delivery_note(item_code=item_code, qty=1, serial_no=serial_no)
-
- pr2 = make_purchase_receipt(item_code=item_code, qty=1, serial_no=serial_no, do_not_submit=True)
- self.assertRaises(SerialNoDuplicateError, pr2.submit)
-
- se = make_stock_entry(item_code=item_code, target="_Test Warehouse - _TC", qty=1,
- serial_no=serial_no, basic_rate=100, do_not_submit=True)
- se.submit()
-
- se.cancel()
- dn.cancel()
- pr1.cancel()
-
def test_auto_asset_creation(self):
asset_item = "Test Asset Item"
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index c02dd2e518..5ecc9f8140 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -243,7 +243,7 @@ def validate_serial_no(sle, item_det):
if frappe.db.exists("Serial No", serial_no):
sr = frappe.db.get_value("Serial No", serial_no, ["name", "item_code", "batch_no", "sales_order",
"delivery_document_no", "delivery_document_type", "warehouse", "purchase_document_type",
- "purchase_document_no", "company"], as_dict=1)
+ "purchase_document_no", "company", "status"], as_dict=1)
if sr.item_code!=sle.item_code:
if not allow_serial_nos_with_different_item(serial_no, sle):
@@ -266,6 +266,9 @@ def validate_serial_no(sle, item_det):
frappe.throw(_("Serial No {0} does not belong to Warehouse {1}").format(serial_no,
sle.warehouse), SerialNoWarehouseError)
+ if not sr.purchase_document_no:
+ frappe.throw(_("Serial No {0} not in stock").format(serial_no), SerialNoNotExistsError)
+
if sle.voucher_type in ("Delivery Note", "Sales Invoice"):
if sr.batch_no and sr.batch_no != sle.batch_no:
@@ -382,19 +385,6 @@ def has_serial_no_exists(sn, sle):
if sn.company != sle.company:
return False
- status = False
- if sn.purchase_document_no:
- if (sle.voucher_type in ['Purchase Receipt', 'Stock Entry', "Purchase Invoice"] and
- sn.delivery_document_type not in ['Purchase Receipt', 'Stock Entry', "Purchase Invoice"]):
- status = True
-
- # If status is receipt then system will allow to in-ward the delivered serial no
- if (status and sle.voucher_type == "Stock Entry" and frappe.db.get_value("Stock Entry",
- sle.voucher_no, "purpose") in ("Material Receipt", "Material Transfer")):
- status = False
-
- return status
-
def allow_serial_nos_with_different_item(sle_serial_no, sle):
"""
Allows same serial nos for raw materials and finished goods
diff --git a/erpnext/stock/report/serial_no_ledger/__init__.py b/erpnext/stock/report/serial_no_ledger/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.js b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.js
new file mode 100644
index 0000000000..616312e311
--- /dev/null
+++ b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.js
@@ -0,0 +1,52 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Serial No Ledger"] = {
+ "filters": [
+ {
+ 'label': __('Item Code'),
+ 'fieldtype': 'Link',
+ 'fieldname': 'item_code',
+ 'reqd': 1,
+ 'options': 'Item',
+ get_query: function() {
+ return {
+ filters: {
+ 'has_serial_no': 1
+ }
+ }
+ }
+ },
+ {
+ 'label': __('Serial No'),
+ 'fieldtype': 'Link',
+ 'fieldname': 'serial_no',
+ 'options': 'Serial No',
+ 'reqd': 1
+ },
+ {
+ 'label': __('Warehouse'),
+ 'fieldtype': 'Link',
+ 'fieldname': 'warehouse',
+ 'options': 'Warehouse',
+ get_query: function() {
+ let company = frappe.query_report.get_filter_value('company');
+
+ if (company) {
+ return {
+ filters: {
+ 'company': company
+ }
+ }
+ }
+ }
+ },
+ {
+ 'label': __('As On Date'),
+ 'fieldtype': 'Date',
+ 'fieldname': 'posting_date',
+ 'default': frappe.datetime.get_today()
+ },
+ ]
+};
diff --git a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.json b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.json
new file mode 100644
index 0000000000..e20e74c78b
--- /dev/null
+++ b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.json
@@ -0,0 +1,33 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2021-04-20 13:32:41.523219",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "json": "{}",
+ "modified": "2021-04-20 13:33:19.015829",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Serial No Ledger",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Stock Ledger Entry",
+ "report_name": "Serial No Ledger",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Stock User"
+ },
+ {
+ "role": "Purchase User"
+ },
+ {
+ "role": "Sales User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
new file mode 100644
index 0000000000..c3339fd341
--- /dev/null
+++ b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
@@ -0,0 +1,53 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe import _
+from erpnext.stock.stock_ledger import get_stock_ledger_entries
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+
+def execute(filters=None):
+ columns = get_columns(filters)
+ data = get_data(filters)
+ return columns, data
+
+def get_columns(filters):
+ columns = [{
+ 'label': _('Posting Date'),
+ 'fieldtype': 'Date',
+ 'fieldname': 'posting_date'
+ }, {
+ 'label': _('Posting Time'),
+ 'fieldtype': 'Time',
+ 'fieldname': 'posting_time'
+ }, {
+ 'label': _('Voucher Type'),
+ 'fieldtype': 'Link',
+ 'fieldname': 'voucher_type',
+ 'options': 'DocType',
+ 'width': 220
+ }, {
+ 'label': _('Voucher No'),
+ 'fieldtype': 'Dynamic Link',
+ 'fieldname': 'voucher_no',
+ 'options': 'voucher_type',
+ 'width': 220
+ }, {
+ 'label': _('Company'),
+ 'fieldtype': 'Link',
+ 'fieldname': 'company',
+ 'options': 'Company',
+ 'width': 220
+ }, {
+ 'label': _('Warehouse'),
+ 'fieldtype': 'Link',
+ 'fieldname': 'warehouse',
+ 'options': 'Warehouse',
+ 'width': 220
+ }]
+
+ return columns
+
+def get_data(filters):
+ return get_stock_ledger_entries(filters, '<=', order="asc") or []
+
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index bbfcb7ad7d..9729987d2d 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+import frappe
+import erpnext
+import copy
from frappe import _
-from frappe.utils import cint, flt, cstr, now, now_datetime
+from frappe.utils import cint, flt, cstr, now, get_link_to_form
from frappe.model.meta import get_field_precision
from erpnext.stock.utils import get_valuation_method, get_incoming_outgoing_rate_for_cancel
from erpnext.stock.utils import get_bin
@@ -13,6 +15,8 @@ from six import iteritems
# future reposting
class NegativeStockError(frappe.ValidationError): pass
+class SerialNoExistsInFutureTransaction(frappe.ValidationError):
+ pass
_exceptions = frappe.local('stockledger_exceptions')
# _exceptions = []
@@ -27,6 +31,9 @@ def make_sl_entries(sl_entries, allow_negative_stock=False, via_landed_cost_vouc
set_as_cancel(sl_entries[0].get('voucher_type'), sl_entries[0].get('voucher_no'))
for sle in sl_entries:
+ if sle.serial_no:
+ validate_serial_no(sle)
+
if cancel:
sle['actual_qty'] = -flt(sle.get('actual_qty'))
@@ -46,6 +53,30 @@ def make_sl_entries(sl_entries, allow_negative_stock=False, via_landed_cost_vouc
args = sle_doc.as_dict()
update_bin(args, allow_negative_stock, via_landed_cost_voucher)
+def validate_serial_no(sle):
+ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+ for sn in get_serial_nos(sle.serial_no):
+ args = copy.deepcopy(sle)
+ args.serial_no = sn
+ args.warehouse = ''
+
+ vouchers = []
+ for row in get_stock_ledger_entries(args, '>'):
+ voucher_type = frappe.bold(row.voucher_type)
+ voucher_no = frappe.bold(get_link_to_form(row.voucher_type, row.voucher_no))
+ vouchers.append(f'{voucher_type} {voucher_no}')
+
+ if vouchers:
+ serial_no = frappe.bold(sn)
+ msg = (f'''The serial no {serial_no} has been used in the future transactions so you need to cancel them first.
+ The list of the transactions are as below.''' + '')
+
+ msg += ' '.join(vouchers)
+ msg += ' '
+
+ title = 'Cannot Submit' if not sle.get('is_cancelled') else 'Cannot Cancel'
+ frappe.throw(_(msg), title=_(title), exc=SerialNoExistsInFutureTransaction)
+
def validate_cancellation(args):
if args[0].get("is_cancelled"):
repost_entry = frappe.db.get_value("Repost Item Valuation", {
@@ -718,7 +749,17 @@ def get_stock_ledger_entries(previous_sle, operator=None,
conditions += " and " + previous_sle.get("warehouse_condition")
if check_serial_no and previous_sle.get("serial_no"):
- conditions += " and serial_no like {}".format(frappe.db.escape('%{0}%'.format(previous_sle.get("serial_no"))))
+ # conditions += " and serial_no like {}".format(frappe.db.escape('%{0}%'.format(previous_sle.get("serial_no"))))
+ serial_no = previous_sle.get("serial_no")
+ conditions += (""" and
+ (
+ serial_no = {0}
+ or serial_no like {1}
+ or serial_no like {2}
+ or serial_no like {3}
+ )
+ """).format(frappe.db.escape(serial_no), frappe.db.escape('{}\n%'.format(serial_no)),
+ frappe.db.escape('%\n{}'.format(serial_no)), frappe.db.escape('%\n{}\n%'.format(serial_no)))
if not previous_sle.get("posting_date"):
previous_sle["posting_date"] = "1900-01-01"
@@ -793,12 +834,12 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
if not allow_zero_rate and not valuation_rate and raise_error_if_no_rate \
and cint(erpnext.is_perpetual_inventory_enabled(company)):
frappe.local.message_log = []
- form_link = frappe.utils.get_link_to_form("Item", item_code)
+ form_link = get_link_to_form("Item", item_code)
message = _("Valuation Rate for the Item {0}, is required to do accounting entries for {1} {2}.").format(form_link, voucher_type, voucher_no)
- message += " " + _(" Here are the options to proceed:")
+ message += " " + _("Here are the options to proceed:")
solutions = "" + _("If the item is transacting as a Zero Valuation Rate item in this entry, please enable 'Allow Zero Valuation Rate' in the {0} Item table.").format(voucher_type) + " "
- solutions += "" + _("If not, you can Cancel / Submit this entry ") + _("{0}").format(frappe.bold("after")) + _(" performing either one below:") + " "
+ solutions += "" + _("If not, you can Cancel / Submit this entry") + " {0} ".format(frappe.bold("after")) + _("performing either one below:") + " "
sub_solutions = "" + _("Create an incoming stock transaction for the Item.") + " "
sub_solutions += "" + _("Mention Valuation Rate in the Item master.") + " "
msg = message + solutions + sub_solutions + ""
From c981969446d82b7aa67fdc8a80b630b8c8ef5f49 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 6 May 2021 13:04:12 +0530
Subject: [PATCH 035/149] test: Fix dependency
---
erpnext/tests/__init__.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/tests/__init__.py b/erpnext/tests/__init__.py
index e69de29bb2..dcc4f5336d 100644
--- a/erpnext/tests/__init__.py
+++ b/erpnext/tests/__init__.py
@@ -0,0 +1 @@
+global_test_dependencies = ['User', 'Company']
From af4af7737f7bd3d227487a5ac9a34da03e840e28 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 6 May 2021 13:05:03 +0530
Subject: [PATCH 036/149] chore: Debug
---
.github/workflows/ci-tests.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
index de8d7ac503..7373c1efa6 100644
--- a/.github/workflows/ci-tests.yml
+++ b/.github/workflows/ci-tests.yml
@@ -1,6 +1,6 @@
name: CI
-on: [pull_request, workflow_dispatch, push]
+on: [pull_request, workflow_dispatch]
jobs:
test:
From 5f7546d876e778c4b0c700a2be78c0f7b4badf68 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 6 May 2021 15:13:09 +0530
Subject: [PATCH 037/149] chore: Debug
---
.github/workflows/ci-tests.yml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
index 7373c1efa6..b03aad794b 100644
--- a/.github/workflows/ci-tests.yml
+++ b/.github/workflows/ci-tests.yml
@@ -17,6 +17,9 @@ jobs:
- TYPE: "server"
JOB_NAME: "Server"
RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext
+ - TYPE: "server"
+ JOB_NAME: "Server"
+ RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext
- TYPE: "patch"
JOB_NAME: "Patch"
RUN_COMMAND: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz && bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate
From d502f763197b9d3891c4c2e498c132a87d35ee19 Mon Sep 17 00:00:00 2001
From: Saqib
Date: Thu, 6 May 2021 16:10:55 +0530
Subject: [PATCH 038/149] feat(e-invoicing): e-way bill validity field (#25555)
---
erpnext/patches.txt | 1 +
.../patches/v12_0/add_ewaybill_validity_field.py | 16 ++++++++++++++++
erpnext/regional/india/e_invoice/utils.py | 12 ++++++++----
erpnext/regional/india/setup.py | 3 +++
4 files changed, 28 insertions(+), 4 deletions(-)
create mode 100644 erpnext/patches/v12_0/add_ewaybill_validity_field.py
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 23f9fd8ecb..7faaf26158 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -774,5 +774,6 @@ erpnext.patches.v12_0.add_document_type_field_for_italy_einvoicing
erpnext.patches.v13_0.make_non_standard_user_type #13-04-2021
erpnext.patches.v13_0.update_shipment_status
erpnext.patches.v13_0.remove_attribute_field_from_item_variant_setting
+erpnext.patches.v12_0.add_ewaybill_validity_field
erpnext.patches.v13_0.germany_make_custom_fields
erpnext.patches.v13_0.germany_fill_debtor_creditor_number
diff --git a/erpnext/patches/v12_0/add_ewaybill_validity_field.py b/erpnext/patches/v12_0/add_ewaybill_validity_field.py
new file mode 100644
index 0000000000..87d98f1a56
--- /dev/null
+++ b/erpnext/patches/v12_0/add_ewaybill_validity_field.py
@@ -0,0 +1,16 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
+def execute():
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if not company:
+ return
+
+ custom_fields = {
+ 'Sales Invoice': [
+ dict(fieldname='eway_bill_validity', label='E-Way Bill Validity', fieldtype='Data', no_copy=1, print_hide=1,
+ depends_on='ewaybill', read_only=1, allow_on_submit=1, insert_after='ewaybill')
+ ]
+ }
+ create_custom_fields(custom_fields, update=True)
\ No newline at end of file
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index 699441be7e..b4e7a8889e 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -71,13 +71,14 @@ def validate_einvoice_fields(doc):
def raise_document_name_too_long_error():
title = _('Document ID Too Long')
- msg = _('As you have E-Invoicing enabled, to be able to generate IRN for this invoice, ')
- msg += _('document id {} exceed 16 letters. ').format(bold(_('should not')))
+ msg = _('As you have E-Invoicing enabled, to be able to generate IRN for this invoice')
+ msg += ', '
+ msg += _('document id {} exceed 16 letters.').format(bold(_('should not')))
msg += ' '
- msg += _('You must {} your {} in order to have document id of {} length 16. ').format(
+ msg += _('You must {} your {} in order to have document id of {} length 16.').format(
bold(_('modify')), bold(_('naming series')), bold(_('maximum'))
)
- msg += _('Please account for ammended documents too. ')
+ msg += _('Please account for ammended documents too.')
frappe.throw(msg, title=title)
def read_json(name):
@@ -847,6 +848,7 @@ class GSPConnector():
res = self.make_request('post', self.generate_ewaybill_url, headers, data)
if res.get('success'):
self.invoice.ewaybill = res.get('result').get('EwbNo')
+ self.invoice.eway_bill_validity = res.get('result').get('EwbValidTill')
self.invoice.eway_bill_cancelled = 0
self.invoice.update(args)
self.invoice.flags.updater_reference = {
@@ -944,6 +946,7 @@ class GSPConnector():
self.invoice.irn = res.get('Irn')
self.invoice.ewaybill = res.get('EwbNo')
+ self.invoice.eway_bill_validity = res.get('EwbValidTill')
self.invoice.ack_no = res.get('AckNo')
self.invoice.ack_date = res.get('AckDt')
self.invoice.signed_einvoice = dec_signed_invoice
@@ -960,6 +963,7 @@ class GSPConnector():
'label': _('IRN Generated')
}
self.update_invoice()
+
def attach_qrcode_image(self):
qrcode = self.invoice.signed_qr_code
doctype = self.invoice.doctype
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 9ded8dab5b..b12e152b14 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -422,6 +422,9 @@ def make_custom_fields(update=True):
dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
depends_on='eval:(doc.irn_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
+ dict(fieldname='eway_bill_validity', label='E-Way Bill Validity', fieldtype='Data', no_copy=1, print_hide=1,
+ depends_on='ewaybill', read_only=1, allow_on_submit=1, insert_after='ewaybill'),
+
dict(fieldname='eway_bill_cancelled', label='E-Way Bill Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
depends_on='eval:(doc.eway_bill_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
From f43a86d90ffb4029dcaee6768c6974f4e90e3026 Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Thu, 6 May 2021 16:40:06 +0530
Subject: [PATCH 039/149] perf: significant reduction in time taken to save a
delivery note (#25475)
---
erpnext/selling/doctype/customer/customer.py | 32 +++++++++++++++-----
1 file changed, 24 insertions(+), 8 deletions(-)
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 49ca9423e8..51d86ff0bf 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -490,7 +490,7 @@ def get_customer_outstanding(customer, company, ignore_outstanding_sales_order=F
outstanding_based_on_gle = flt(outstanding_based_on_gle[0][0]) if outstanding_based_on_gle else 0
# Outstanding based on Sales Order
- outstanding_based_on_so = 0.0
+ outstanding_based_on_so = 0
# if credit limit check is bypassed at sales order level,
# we should not consider outstanding Sales Orders, when customer credit balance report is run
@@ -501,9 +501,11 @@ def get_customer_outstanding(customer, company, ignore_outstanding_sales_order=F
where customer=%s and docstatus = 1 and company=%s
and per_billed < 100 and status != 'Closed'""", (customer, company))
- outstanding_based_on_so = flt(outstanding_based_on_so[0][0]) if outstanding_based_on_so else 0.0
+ outstanding_based_on_so = flt(outstanding_based_on_so[0][0]) if outstanding_based_on_so else 0
# Outstanding based on Delivery Note, which are not created against Sales Order
+ outstanding_based_on_dn = 0
+
unmarked_delivery_note_items = frappe.db.sql("""select
dn_item.name, dn_item.amount, dn.base_net_total, dn.base_grand_total
from `tabDelivery Note` dn, `tabDelivery Note Item` dn_item
@@ -515,15 +517,29 @@ def get_customer_outstanding(customer, company, ignore_outstanding_sales_order=F
and ifnull(dn_item.against_sales_invoice, '') = ''
""", (customer, company), as_dict=True)
- outstanding_based_on_dn = 0.0
+ if not unmarked_delivery_note_items:
+ return outstanding_based_on_gle + outstanding_based_on_so
+
+ si_amounts = frappe.db.sql("""
+ SELECT
+ dn_detail, sum(amount) from `tabSales Invoice Item`
+ WHERE
+ docstatus = 1
+ and dn_detail in ({})
+ GROUP BY dn_detail""".format(", ".join(
+ frappe.db.escape(dn_item.name)
+ for dn_item in unmarked_delivery_note_items
+ ))
+ )
+
+ si_amounts = {si_item[0]: si_item[1] for si_item in si_amounts}
for dn_item in unmarked_delivery_note_items:
- si_amount = frappe.db.sql("""select sum(amount)
- from `tabSales Invoice Item`
- where dn_detail = %s and docstatus = 1""", dn_item.name)[0][0]
+ dn_amount = flt(dn_item.amount)
+ si_amount = flt(si_amounts.get(dn_item.name))
- if flt(dn_item.amount) > flt(si_amount) and dn_item.base_net_total:
- outstanding_based_on_dn += ((flt(dn_item.amount) - flt(si_amount)) \
+ if dn_amount > si_amount and dn_item.base_net_total:
+ outstanding_based_on_dn += ((dn_amount - si_amount)
/ dn_item.base_net_total) * dn_item.base_grand_total
return outstanding_based_on_gle + outstanding_based_on_so + outstanding_based_on_dn
From 900a8fb21a9a22d4f683912035777c33341730d6 Mon Sep 17 00:00:00 2001
From: Saqib
Date: Thu, 6 May 2021 17:02:47 +0530
Subject: [PATCH 040/149] feat(pos): ability to retry on pos closing failure
(#25595)
* feat(pos): ability to retry on pos closing failure
* fix: sider issues
* fix: sider issues
* fix: mark all queued closing entry as failed
* feat: add headline message
---
.../pos_closing_entry/pos_closing_entry.js | 104 ++++++++++--------
.../pos_closing_entry/pos_closing_entry.json | 21 +++-
.../pos_closing_entry/pos_closing_entry.py | 4 +
.../pos_closing_entry_list.js | 1 +
.../pos_invoice_merge_log.py | 87 +++++++++++----
erpnext/controllers/status_updater.py | 1 +
erpnext/patches.txt | 1 +
.../v13_0/set_pos_closing_as_failed.py | 7 ++
8 files changed, 158 insertions(+), 68 deletions(-)
create mode 100644 erpnext/patches/v13_0/set_pos_closing_as_failed.py
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
index 9ea616f8e7..aa0c53e228 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
@@ -22,7 +22,43 @@ frappe.ui.form.on('POS Closing Entry', {
});
if (frm.doc.docstatus === 0 && !frm.doc.amended_from) frm.set_value("period_end_date", frappe.datetime.now_datetime());
- if (frm.doc.docstatus === 1) set_html_data(frm);
+
+ frappe.realtime.on('closing_process_complete', async function(data) {
+ await frm.reload_doc();
+ if (frm.doc.status == 'Failed' && frm.doc.error_message && data.user == frappe.session.user) {
+ frappe.msgprint({
+ title: __('POS Closing Failed'),
+ message: frm.doc.error_message,
+ indicator: 'orange',
+ clear: true
+ });
+ }
+ });
+
+ set_html_data(frm);
+ },
+
+ refresh: function(frm) {
+ if (frm.doc.docstatus == 1 && frm.doc.status == 'Failed') {
+ const issue = 'issue ';
+ frm.dashboard.set_headline(
+ __('POS Closing failed while running in a background process. You can resolve the {0} and retry the process again.', [issue]));
+
+ $('#jump_to_error').on('click', (e) => {
+ e.preventDefault();
+ frappe.utils.scroll_to(
+ cur_frm.get_field("error_message").$wrapper,
+ true,
+ 30
+ );
+ });
+
+ frm.add_custom_button(__('Retry'), function () {
+ frm.call('retry', {}, () => {
+ frm.reload_doc();
+ });
+ });
+ }
},
pos_opening_entry(frm) {
@@ -61,44 +97,24 @@ frappe.ui.form.on('POS Closing Entry', {
refresh_fields(frm);
set_html_data(frm);
}
- })
+ });
+ },
+
+ before_save: function(frm) {
+ for (let row of frm.doc.pos_transactions) {
+ frappe.db.get_doc("POS Invoice", row.pos_invoice).then(doc => {
+ cur_frm.doc.grand_total -= flt(doc.grand_total);
+ cur_frm.doc.net_total -= flt(doc.net_total);
+ cur_frm.doc.total_quantity -= flt(doc.total_qty);
+ refresh_payments(doc, cur_frm, 1);
+ refresh_taxes(doc, cur_frm, 1);
+ refresh_fields(cur_frm);
+ set_html_data(cur_frm);
+ });
+ }
}
});
-cur_frm.cscript.before_pos_transactions_remove = function(doc, cdt, cdn) {
- const removed_row = locals[cdt][cdn];
-
- if (!removed_row.pos_invoice) return;
-
- frappe.db.get_doc("POS Invoice", removed_row.pos_invoice).then(doc => {
- cur_frm.doc.grand_total -= flt(doc.grand_total);
- cur_frm.doc.net_total -= flt(doc.net_total);
- cur_frm.doc.total_quantity -= flt(doc.total_qty);
- refresh_payments(doc, cur_frm, 1);
- refresh_taxes(doc, cur_frm, 1);
- refresh_fields(cur_frm);
- set_html_data(cur_frm);
- });
-}
-
-frappe.ui.form.on('POS Invoice Reference', {
- pos_invoice(frm, cdt, cdn) {
- const added_row = locals[cdt][cdn];
-
- if (!added_row.pos_invoice) return;
-
- frappe.db.get_doc("POS Invoice", added_row.pos_invoice).then(doc => {
- frm.doc.grand_total += flt(doc.grand_total);
- frm.doc.net_total += flt(doc.net_total);
- frm.doc.total_quantity += flt(doc.total_qty);
- refresh_payments(doc, frm);
- refresh_taxes(doc, frm);
- refresh_fields(frm);
- set_html_data(frm);
- });
- }
-})
-
frappe.ui.form.on('POS Closing Entry Detail', {
closing_amount: (frm, cdt, cdn) => {
const row = locals[cdt][cdn];
@@ -177,11 +193,13 @@ function refresh_fields(frm) {
}
function set_html_data(frm) {
- frappe.call({
- method: "get_payment_reconciliation_details",
- doc: frm.doc,
- callback: (r) => {
- frm.get_field("payment_reconciliation_details").$wrapper.html(r.message);
- }
- })
+ if (frm.doc.docstatus === 1 && frm.doc.status == 'Submitted') {
+ frappe.call({
+ method: "get_payment_reconciliation_details",
+ doc: frm.doc,
+ callback: (r) => {
+ frm.get_field("payment_reconciliation_details").$wrapper.html(r.message);
+ }
+ });
+ }
}
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
index a9b91e02a9..4d6e4a2ba0 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
@@ -30,6 +30,8 @@
"total_quantity",
"column_break_16",
"taxes",
+ "failure_description_section",
+ "error_message",
"section_break_14",
"amended_from"
],
@@ -195,7 +197,7 @@
"fieldtype": "Select",
"hidden": 1,
"label": "Status",
- "options": "Draft\nSubmitted\nQueued\nCancelled",
+ "options": "Draft\nSubmitted\nQueued\nFailed\nCancelled",
"print_hide": 1,
"read_only": 1
},
@@ -203,6 +205,21 @@
"fieldname": "period_details_section",
"fieldtype": "Section Break",
"label": "Period Details"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "error_message",
+ "depends_on": "error_message",
+ "fieldname": "failure_description_section",
+ "fieldtype": "Section Break",
+ "label": "Failure Description"
+ },
+ {
+ "depends_on": "error_message",
+ "fieldname": "error_message",
+ "fieldtype": "Small Text",
+ "label": "Error",
+ "read_only": 1
}
],
"is_submittable": 1,
@@ -212,7 +229,7 @@
"link_fieldname": "pos_closing_entry"
}
],
- "modified": "2021-02-01 13:47:20.722104",
+ "modified": "2021-05-05 16:59:49.723261",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Closing Entry",
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
index 1065168a50..82528728dd 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
@@ -60,6 +60,10 @@ class POSClosingEntry(StatusUpdater):
def on_cancel(self):
unconsolidate_pos_invoices(closing_entry=self)
+ @frappe.whitelist()
+ def retry(self):
+ consolidate_pos_invoices(closing_entry=self)
+
def update_opening_entry(self, for_cancel=False):
opening_entry = frappe.get_doc("POS Opening Entry", self.pos_opening_entry)
opening_entry.pos_closing_entry = self.name if not for_cancel else None
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry_list.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry_list.js
index 20fd610899..cffeb4d535 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry_list.js
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry_list.js
@@ -8,6 +8,7 @@ frappe.listview_settings['POS Closing Entry'] = {
"Draft": "red",
"Submitted": "blue",
"Queued": "orange",
+ "Failed": "red",
"Cancelled": "red"
};
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
index 4d5472df4b..bc7874305c 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
@@ -13,8 +13,7 @@ from frappe.model.mapper import map_doc, map_child_doc
from frappe.utils.scheduler import is_scheduler_inactive
from frappe.core.page.background_jobs.background_jobs import get_info
import json
-
-from six import iteritems
+import six
class POSInvoiceMergeLog(Document):
def validate(self):
@@ -239,7 +238,7 @@ def consolidate_pos_invoices(pos_invoices=None, closing_entry=None):
invoices = pos_invoices or (closing_entry and closing_entry.get('pos_transactions')) or get_all_unconsolidated_invoices()
invoice_by_customer = get_invoice_customer_map(invoices)
- if len(invoices) >= 1 and closing_entry:
+ if len(invoices) >= 10 and closing_entry:
closing_entry.set_status(update=True, status='Queued')
enqueue_job(create_merge_logs, invoice_by_customer=invoice_by_customer, closing_entry=closing_entry)
else:
@@ -252,36 +251,68 @@ def unconsolidate_pos_invoices(closing_entry):
pluck='name'
)
- if len(merge_logs) >= 1:
+ if len(merge_logs) >= 10:
closing_entry.set_status(update=True, status='Queued')
enqueue_job(cancel_merge_logs, merge_logs=merge_logs, closing_entry=closing_entry)
else:
cancel_merge_logs(merge_logs, closing_entry)
def create_merge_logs(invoice_by_customer, closing_entry=None):
- for customer, invoices in iteritems(invoice_by_customer):
- merge_log = frappe.new_doc('POS Invoice Merge Log')
- merge_log.posting_date = getdate(closing_entry.get('posting_date')) if closing_entry else nowdate()
- merge_log.customer = customer
- merge_log.pos_closing_entry = closing_entry.get('name') if closing_entry else None
+ try:
+ for customer, invoices in six.iteritems(invoice_by_customer):
+ merge_log = frappe.new_doc('POS Invoice Merge Log')
+ merge_log.posting_date = getdate(closing_entry.get('posting_date')) if closing_entry else nowdate()
+ merge_log.customer = customer
+ merge_log.pos_closing_entry = closing_entry.get('name') if closing_entry else None
- merge_log.set('pos_invoices', invoices)
- merge_log.save(ignore_permissions=True)
- merge_log.submit()
+ merge_log.set('pos_invoices', invoices)
+ merge_log.save(ignore_permissions=True)
+ merge_log.submit()
- if closing_entry:
- closing_entry.set_status(update=True, status='Submitted')
- closing_entry.update_opening_entry()
+ if closing_entry:
+ closing_entry.set_status(update=True, status='Submitted')
+ closing_entry.db_set('error_message', '')
+ closing_entry.update_opening_entry()
+
+ except Exception:
+ frappe.db.rollback()
+ message_log = frappe.message_log.pop()
+ error_message = safe_load_json(message_log)
+
+ if closing_entry:
+ closing_entry.set_status(update=True, status='Failed')
+ closing_entry.db_set('error_message', error_message)
+ raise
+
+ finally:
+ frappe.db.commit()
+ frappe.publish_realtime('closing_process_complete', {'user': frappe.session.user})
def cancel_merge_logs(merge_logs, closing_entry=None):
- for log in merge_logs:
- merge_log = frappe.get_doc('POS Invoice Merge Log', log)
- merge_log.flags.ignore_permissions = True
- merge_log.cancel()
+ try:
+ for log in merge_logs:
+ merge_log = frappe.get_doc('POS Invoice Merge Log', log)
+ merge_log.flags.ignore_permissions = True
+ merge_log.cancel()
- if closing_entry:
- closing_entry.set_status(update=True, status='Cancelled')
- closing_entry.update_opening_entry(for_cancel=True)
+ if closing_entry:
+ closing_entry.set_status(update=True, status='Cancelled')
+ closing_entry.db_set('error_message', '')
+ closing_entry.update_opening_entry(for_cancel=True)
+
+ except Exception:
+ frappe.db.rollback()
+ message_log = frappe.message_log.pop()
+ error_message = safe_load_json(message_log)
+
+ if closing_entry:
+ closing_entry.set_status(update=True, status='Submitted')
+ closing_entry.db_set('error_message', error_message)
+ raise
+
+ finally:
+ frappe.db.commit()
+ frappe.publish_realtime('closing_process_complete', {'user': frappe.session.user})
def enqueue_job(job, **kwargs):
check_scheduler_status()
@@ -314,4 +345,14 @@ def check_scheduler_status():
def job_already_enqueued(job_name):
enqueued_jobs = [d.get("job_name") for d in get_info()]
if job_name in enqueued_jobs:
- return True
\ No newline at end of file
+ return True
+
+def safe_load_json(message):
+ JSONDecodeError = ValueError if six.PY2 else json.JSONDecodeError
+
+ try:
+ json_message = json.loads(message).get('message')
+ except JSONDecodeError:
+ json_message = message
+
+ return json_message
\ No newline at end of file
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index 5276da9720..4bb6138e5d 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -98,6 +98,7 @@ status_map = {
["Draft", None],
["Submitted", "eval:self.docstatus == 1"],
["Queued", "eval:self.status == 'Queued'"],
+ ["Failed", "eval:self.status == 'Failed'"],
["Cancelled", "eval:self.docstatus == 2"],
]
}
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 7faaf26158..82d223cada 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -777,3 +777,4 @@ erpnext.patches.v13_0.remove_attribute_field_from_item_variant_setting
erpnext.patches.v12_0.add_ewaybill_validity_field
erpnext.patches.v13_0.germany_make_custom_fields
erpnext.patches.v13_0.germany_fill_debtor_creditor_number
+erpnext.patches.v13_0.set_pos_closing_as_failed
diff --git a/erpnext/patches/v13_0/set_pos_closing_as_failed.py b/erpnext/patches/v13_0/set_pos_closing_as_failed.py
new file mode 100644
index 0000000000..1c576db1c7
--- /dev/null
+++ b/erpnext/patches/v13_0/set_pos_closing_as_failed.py
@@ -0,0 +1,7 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc('accounts', 'doctype', 'pos_closing_entry')
+
+ frappe.db.sql("update `tabPOS Closing Entry` set `status` = 'Failed' where `status` = 'Queued'")
\ No newline at end of file
From c5430afe2d77e30544460f555611b92df3de4fca Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 6 May 2021 17:44:26 +0530
Subject: [PATCH 041/149] test: Fix test_dependencies
---
erpnext/accounts/doctype/budget/test_budget.py | 2 ++
erpnext/education/doctype/fees/test_fees.py | 3 +--
erpnext/tests/__init__.py | 2 +-
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py
index c5ec23c829..603e21ea24 100644
--- a/erpnext/accounts/doctype/budget/test_budget.py
+++ b/erpnext/accounts/doctype/budget/test_budget.py
@@ -11,6 +11,8 @@ from erpnext.buying.doctype.purchase_order.test_purchase_order import create_pur
from erpnext.accounts.doctype.budget.budget import get_actual_expense, BudgetError
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
+test_dependencies = ['Monthly Distribution']
+
class TestBudget(unittest.TestCase):
def test_monthly_budget_crossed_ignore(self):
set_total_expense_zero(nowdate(), "cost_center")
diff --git a/erpnext/education/doctype/fees/test_fees.py b/erpnext/education/doctype/fees/test_fees.py
index eedc2ae730..c6bb704b41 100644
--- a/erpnext/education/doctype/fees/test_fees.py
+++ b/erpnext/education/doctype/fees/test_fees.py
@@ -9,8 +9,7 @@ from frappe.utils import nowdate
from frappe.utils.make_random import get_random
from erpnext.education.doctype.program.test_program import make_program_and_linked_courses
-# test_records = frappe.get_test_records('Fees')
-
+test_dependencies = ['Company']
class TestFees(unittest.TestCase):
def test_fees(self):
diff --git a/erpnext/tests/__init__.py b/erpnext/tests/__init__.py
index dcc4f5336d..593bc7c71b 100644
--- a/erpnext/tests/__init__.py
+++ b/erpnext/tests/__init__.py
@@ -1 +1 @@
-global_test_dependencies = ['User', 'Company']
+global_test_dependencies = ['User', 'Company', 'Cost Center', 'Account', 'Warehouse', 'Item']
From 695becdd0569aac2bb57e0c87b9d4234b3ca9647 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Thu, 6 May 2021 18:03:32 +0530
Subject: [PATCH 042/149] fix: added validation in stock entry to check
duplicate serial nos
---
.../stock/doctype/stock_entry/stock_entry.py | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 48cfa51041..2f76bc7d56 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -76,6 +76,7 @@ class StockEntry(StockController):
self.validate_difference_account()
self.set_job_card_data()
self.set_purpose_for_stock_entry()
+ self.validate_duplicate_serial_no()
if not self.from_bom:
self.fg_completed_qty = 0.0
@@ -587,6 +588,22 @@ class StockEntry(StockController):
self.purpose = frappe.get_cached_value('Stock Entry Type',
self.stock_entry_type, 'purpose')
+ def validate_duplicate_serial_no(self):
+ warehouse_wise_serial_nos = {}
+
+ # In case of repack the source and target serial nos could be same
+ for warehouse in ['s_warehouse', 't_warehouse']:
+ serial_nos = []
+ for row in self.items:
+ if not (row.serial_no and row.get(warehouse)): continue
+
+ for sn in get_serial_nos(row.serial_no):
+ if sn in serial_nos:
+ frappe.throw(_('The serial no {0} has added multiple times in the stock entry {1}')
+ .format(frappe.bold(sn), self.name))
+
+ serial_nos.append(sn)
+
def validate_purchase_order(self):
"""Throw exception if more raw material is transferred against Purchase Order than in
the raw materials supplied table"""
From bdf8c528f17a57fc3a46eab5e26bb0bf040d8c7e Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 6 May 2021 18:37:14 +0530
Subject: [PATCH 043/149] test: Fix dependencies
---
.../doctype/accounting_dimension/test_accounting_dimension.py | 3 ++-
.../test_accounting_dimension_filter.py | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
index fc1d7e344a..6fb661eb54 100644
--- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
@@ -7,7 +7,8 @@ import frappe
import unittest
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
-from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import delete_accounting_dimension
+
+test_dependencies = ['Location']
class TestAccountingDimension(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py
index 7877abd026..78a88eb48c 100644
--- a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py
+++ b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py
@@ -9,6 +9,8 @@ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sal
from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import create_dimension, disable_dimension
from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
+test_dependencies = ['Location']
+
class TestAccountingDimensionFilter(unittest.TestCase):
def setUp(self):
create_dimension()
From c702408f9939da15ede122531d86e0a7d479b40b Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 6 May 2021 18:37:45 +0530
Subject: [PATCH 044/149] chore: Remove unnecessary print statements
---
erpnext/controllers/accounts_controller.py | 1 -
erpnext/setup/doctype/email_digest/email_digest.py | 3 +--
erpnext/stock/stock_balance.py | 5 +----
erpnext/utilities/__init__.py | 1 -
4 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index c409850734..913458fa35 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1006,7 +1006,6 @@ class AccountsController(TransactionBase):
else:
grand_total -= self.get("total_advance")
base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total"))
- print(grand_total, base_grand_total)
if total != flt(grand_total, self.precision("grand_total")) or \
base_total != flt(base_grand_total, self.precision("base_grand_total")):
frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total"))
diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index 8c97322a71..5db54eeee1 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -808,7 +808,6 @@ def get_incomes_expenses_for_period(account, from_date, to_date):
val = balance_on_to_date - balance_before_from_date
else:
last_year_closing_balance = get_balance_on(account, date=fy_start_date - timedelta(days=1))
- print(fy_start_date - timedelta(days=1), last_year_closing_balance)
val = balance_on_to_date + (last_year_closing_balance - balance_before_from_date)
return val
@@ -837,4 +836,4 @@ def get_future_date_for_calendaer_event(frequency):
elif frequency == "Monthly":
to_date = add_to_date(from_date, months=1)
- return from_date, to_date
\ No newline at end of file
+ return from_date, to_date
diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py
index 8ba1f1ca5c..8917bfeae4 100644
--- a/erpnext/stock/stock_balance.py
+++ b/erpnext/stock/stock_balance.py
@@ -194,9 +194,6 @@ def set_stock_balance_as_per_serial_no(item_code=None, posting_date=None, postin
serial_nos = frappe.db.sql("""select count(name) from `tabSerial No`
where item_code=%s and warehouse=%s and docstatus < 2""", (d[0], d[1]))
- if serial_nos and flt(serial_nos[0][0]) != flt(d[2]):
- print(d[0], d[1], d[2], serial_nos[0][0])
-
sle = frappe.db.sql("""select valuation_rate, company from `tabStock Ledger Entry`
where item_code = %s and warehouse = %s and is_cancelled = 0
order by posting_date desc limit 1""", (d[0], d[1]))
@@ -230,7 +227,7 @@ def set_stock_balance_as_per_serial_no(item_code=None, posting_date=None, postin
})
update_bin(args)
-
+
create_repost_item_valuation_entry({
"item_code": d[0],
"warehouse": d[1],
diff --git a/erpnext/utilities/__init__.py b/erpnext/utilities/__init__.py
index 618cc985ae..0a5aa3c49b 100644
--- a/erpnext/utilities/__init__.py
+++ b/erpnext/utilities/__init__.py
@@ -12,7 +12,6 @@ def update_doctypes():
for f in dt.fields:
if f.fieldname == d.fieldname and f.fieldtype in ("Text", "Small Text"):
- print(f.parent, f.fieldname)
f.fieldtype = "Text Editor"
dt.save()
break
From 134eaa5786745fc9930a795b74f0461e353363ac Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Thu, 6 May 2021 19:13:54 +0530
Subject: [PATCH 045/149] perf: Performance enhancement on setup wizard
(#25605)
* perf: Performance enhancement on setup wizard
* fix: create departments without updating nsm
---
erpnext/accounts/doctype/account/account.py | 2 +-
.../chart_of_accounts/chart_of_accounts.py | 4 +-
.../accounts_settings/accounts_settings.py | 4 +-
.../education_settings/education_settings.py | 4 +-
erpnext/hr/doctype/department/department.py | 3 +-
.../payroll_settings/payroll_settings.py | 4 +-
.../selling_settings/selling_settings.py | 4 +-
.../global_defaults/global_defaults.py | 12 +-
.../doctype/naming_series/naming_series.py | 16 +--
.../operations/install_fixtures.py | 134 ++++++++++--------
erpnext/setup/setup_wizard/setup_wizard.py | 9 --
.../doctype/stock_settings/stock_settings.py | 10 +-
12 files changed, 105 insertions(+), 101 deletions(-)
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 0606823821..1be2fbf5c8 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -13,7 +13,7 @@ class BalanceMismatchError(frappe.ValidationError): pass
class Account(NestedSet):
nsm_parent_field = 'parent_account'
def on_update(self):
- if frappe.local.flags.ignore_on_update:
+ if frappe.local.flags.ignore_update_nsm:
return
else:
super(Account, self).on_update()
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
index 0e3b24cda3..927adc7086 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
@@ -57,10 +57,10 @@ def create_charts(company, chart_template=None, existing_company=None, custom_ch
# Rebuild NestedSet HSM tree for Account Doctype
# after all accounts are already inserted.
- frappe.local.flags.ignore_on_update = True
+ frappe.local.flags.ignore_update_nsm = True
_import_accounts(chart, None, None, root_account=True)
rebuild_tree("Account", "parent_account")
- frappe.local.flags.ignore_on_update = False
+ frappe.local.flags.ignore_update_nsm = False
def add_suffix_if_duplicate(account_name, account_number, accounts):
if account_number:
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
index 5593466fc2..4d3388090d 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
@@ -30,5 +30,5 @@ class AccountsSettings(Document):
def enable_payment_schedule_in_print(self):
show_in_print = cint(self.show_payment_schedule_in_print)
for doctype in ("Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"):
- make_property_setter(doctype, "due_date", "print_hide", show_in_print, "Check")
- make_property_setter(doctype, "payment_schedule", "print_hide", 0 if show_in_print else 1, "Check")
+ make_property_setter(doctype, "due_date", "print_hide", show_in_print, "Check", validate_fields_for_doctype=False)
+ make_property_setter(doctype, "payment_schedule", "print_hide", 0 if show_in_print else 1, "Check", validate_fields_for_doctype=False)
diff --git a/erpnext/education/doctype/education_settings/education_settings.py b/erpnext/education/doctype/education_settings/education_settings.py
index a85d3e70f3..658380ea42 100644
--- a/erpnext/education/doctype/education_settings/education_settings.py
+++ b/erpnext/education/doctype/education_settings/education_settings.py
@@ -31,9 +31,9 @@ class EducationSettings(Document):
def validate(self):
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
if self.get('instructor_created_by')=='Naming Series':
- make_property_setter('Instructor', "naming_series", "hidden", 0, "Check")
+ make_property_setter('Instructor', "naming_series", "hidden", 0, "Check", validate_fields_for_doctype=False)
else:
- make_property_setter('Instructor', "naming_series", "hidden", 1, "Check")
+ make_property_setter('Instructor', "naming_series", "hidden", 1, "Check", validate_fields_for_doctype=False)
def update_website_context(context):
context["lms_enabled"] = frappe.get_doc("Education Settings").enable_lms
\ No newline at end of file
diff --git a/erpnext/hr/doctype/department/department.py b/erpnext/hr/doctype/department/department.py
index 2cef509276..539a360269 100644
--- a/erpnext/hr/doctype/department/department.py
+++ b/erpnext/hr/doctype/department/department.py
@@ -31,7 +31,8 @@ class Department(NestedSet):
return new
def on_update(self):
- NestedSet.on_update(self)
+ if not frappe.local.flags.ignore_update_nsm:
+ super(Department, self).on_update()
def on_trash(self):
super(Department, self).on_trash()
diff --git a/erpnext/payroll/doctype/payroll_settings/payroll_settings.py b/erpnext/payroll/doctype/payroll_settings/payroll_settings.py
index 5efa41db1f..459b7eacb4 100644
--- a/erpnext/payroll/doctype/payroll_settings/payroll_settings.py
+++ b/erpnext/payroll/doctype/payroll_settings/payroll_settings.py
@@ -28,5 +28,5 @@ class PayrollSettings(Document):
def toggle_rounded_total(self):
self.disable_rounded_total = cint(self.disable_rounded_total)
- make_property_setter("Salary Slip", "rounded_total", "hidden", self.disable_rounded_total, "Check")
- make_property_setter("Salary Slip", "rounded_total", "print_hide", self.disable_rounded_total, "Check")
+ make_property_setter("Salary Slip", "rounded_total", "hidden", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
+ make_property_setter("Salary Slip", "rounded_total", "print_hide", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.py b/erpnext/selling/doctype/selling_settings/selling_settings.py
index d297883876..b219e7ecce 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.py
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.py
@@ -30,8 +30,8 @@ class SellingSettings(Document):
# Make property setters to hide tax_id fields
for doctype in ("Sales Order", "Sales Invoice", "Delivery Note"):
- make_property_setter(doctype, "tax_id", "hidden", self.hide_tax_id, "Check")
- make_property_setter(doctype, "tax_id", "print_hide", self.hide_tax_id, "Check")
+ make_property_setter(doctype, "tax_id", "hidden", self.hide_tax_id, "Check", validate_fields_for_doctype=False)
+ make_property_setter(doctype, "tax_id", "print_hide", self.hide_tax_id, "Check", validate_fields_for_doctype=False)
def set_default_customer_group_and_territory(self):
if not self.customer_group:
diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.py b/erpnext/setup/doctype/global_defaults/global_defaults.py
index 76a8450829..e587217181 100644
--- a/erpnext/setup/doctype/global_defaults/global_defaults.py
+++ b/erpnext/setup/doctype/global_defaults/global_defaults.py
@@ -60,11 +60,11 @@ class GlobalDefaults(Document):
# Make property setters to hide rounded total fields
for doctype in ("Quotation", "Sales Order", "Sales Invoice", "Delivery Note",
"Supplier Quotation", "Purchase Order", "Purchase Invoice"):
- make_property_setter(doctype, "base_rounded_total", "hidden", self.disable_rounded_total, "Check")
- make_property_setter(doctype, "base_rounded_total", "print_hide", 1, "Check")
+ make_property_setter(doctype, "base_rounded_total", "hidden", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
+ make_property_setter(doctype, "base_rounded_total", "print_hide", 1, "Check", validate_fields_for_doctype=False)
- make_property_setter(doctype, "rounded_total", "hidden", self.disable_rounded_total, "Check")
- make_property_setter(doctype, "rounded_total", "print_hide", self.disable_rounded_total, "Check")
+ make_property_setter(doctype, "rounded_total", "hidden", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
+ make_property_setter(doctype, "rounded_total", "print_hide", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
def toggle_in_words(self):
self.disable_in_words = cint(self.disable_in_words)
@@ -72,5 +72,5 @@ class GlobalDefaults(Document):
# Make property setters to hide in words fields
for doctype in ("Quotation", "Sales Order", "Sales Invoice", "Delivery Note",
"Supplier Quotation", "Purchase Order", "Purchase Invoice", "Purchase Receipt"):
- make_property_setter(doctype, "in_words", "hidden", self.disable_in_words, "Check")
- make_property_setter(doctype, "in_words", "print_hide", self.disable_in_words, "Check")
+ make_property_setter(doctype, "in_words", "hidden", self.disable_in_words, "Check", validate_fields_for_doctype=False)
+ make_property_setter(doctype, "in_words", "print_hide", self.disable_in_words, "Check", validate_fields_for_doctype=False)
diff --git a/erpnext/setup/doctype/naming_series/naming_series.py b/erpnext/setup/doctype/naming_series/naming_series.py
index 373b0a58c9..c1f9433b41 100644
--- a/erpnext/setup/doctype/naming_series/naming_series.py
+++ b/erpnext/setup/doctype/naming_series/naming_series.py
@@ -183,8 +183,8 @@ class NamingSeries(Document):
def set_by_naming_series(doctype, fieldname, naming_series, hide_name_field=True):
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
if naming_series:
- make_property_setter(doctype, "naming_series", "hidden", 0, "Check")
- make_property_setter(doctype, "naming_series", "reqd", 1, "Check")
+ make_property_setter(doctype, "naming_series", "hidden", 0, "Check", validate_fields_for_doctype=False)
+ make_property_setter(doctype, "naming_series", "reqd", 1, "Check", validate_fields_for_doctype=False)
# set values for mandatory
try:
@@ -195,15 +195,15 @@ def set_by_naming_series(doctype, fieldname, naming_series, hide_name_field=True
pass
if hide_name_field:
- make_property_setter(doctype, fieldname, "reqd", 0, "Check")
- make_property_setter(doctype, fieldname, "hidden", 1, "Check")
+ make_property_setter(doctype, fieldname, "reqd", 0, "Check", validate_fields_for_doctype=False)
+ make_property_setter(doctype, fieldname, "hidden", 1, "Check", validate_fields_for_doctype=False)
else:
- make_property_setter(doctype, "naming_series", "reqd", 0, "Check")
- make_property_setter(doctype, "naming_series", "hidden", 1, "Check")
+ make_property_setter(doctype, "naming_series", "reqd", 0, "Check", validate_fields_for_doctype=False)
+ make_property_setter(doctype, "naming_series", "hidden", 1, "Check", validate_fields_for_doctype=False)
if hide_name_field:
- make_property_setter(doctype, fieldname, "hidden", 0, "Check")
- make_property_setter(doctype, fieldname, "reqd", 1, "Check")
+ make_property_setter(doctype, fieldname, "hidden", 0, "Check", validate_fields_for_doctype=False)
+ make_property_setter(doctype, fieldname, "reqd", 1, "Check", validate_fields_for_doctype=False)
# set values for mandatory
frappe.db.sql("""update `tab{doctype}` set `{fieldname}`=`name` where
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 5053c6a512..5c725d332d 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -12,6 +12,7 @@ from frappe.desk.doctype.global_search_settings.global_search_settings import up
from erpnext.accounts.doctype.account.account import RootNotEditable
from erpnext.regional.address_template.setup import set_up_address_templates
+from frappe.utils.nestedset import rebuild_tree
default_lead_sources = ["Existing Customer", "Reference", "Advertisement",
"Cold Calling", "Exhibition", "Supplier Reference", "Mass Mailing",
@@ -280,13 +281,15 @@ def install(country=None):
set_more_defaults()
update_global_search_doctypes()
- # path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(country))
- # if os.path.exists(path.encode("utf-8")):
- # frappe.get_attr("erpnext.regional.{0}.setup.setup_company_independent_fixtures".format(frappe.scrub(country)))()
-
-
def set_more_defaults():
# Do more setup stuff that can be done here with no dependencies
+ update_selling_defaults()
+ update_buying_defaults()
+ update_hr_defaults()
+ add_uom_data()
+ update_item_variant_settings()
+
+def update_selling_defaults():
selling_settings = frappe.get_doc("Selling Settings")
selling_settings.set_default_customer_group_and_territory()
selling_settings.cust_master_name = "Customer Name"
@@ -296,13 +299,7 @@ def set_more_defaults():
selling_settings.sales_update_frequency = "Each Transaction"
selling_settings.save()
- add_uom_data()
-
- # set no copy fields of an item doctype to item variant settings
- doc = frappe.get_doc('Item Variant Settings')
- doc.set_default_fields()
- doc.save()
-
+def update_buying_defaults():
buying_settings = frappe.get_doc("Buying Settings")
buying_settings.supp_master_name = "Supplier Name"
buying_settings.po_required = "No"
@@ -311,12 +308,19 @@ def set_more_defaults():
buying_settings.allow_multiple_items = 1
buying_settings.save()
+def update_hr_defaults():
hr_settings = frappe.get_doc("HR Settings")
hr_settings.emp_created_by = "Naming Series"
hr_settings.leave_approval_notification_template = _("Leave Approval Notification")
hr_settings.leave_status_notification_template = _("Leave Status Notification")
hr_settings.save()
+def update_item_variant_settings():
+ # set no copy fields of an item doctype to item variant settings
+ doc = frappe.get_doc('Item Variant Settings')
+ doc.set_default_fields()
+ doc.save()
+
def add_uom_data():
# add UOMs
uoms = json.loads(open(frappe.get_app_path("erpnext", "setup", "setup_wizard", "data", "uom_data.json")).read())
@@ -327,7 +331,7 @@ def add_uom_data():
"uom_name": _(d.get("uom_name")),
"name": _(d.get("uom_name")),
"must_be_whole_number": d.get("must_be_whole_number")
- }).insert(ignore_permissions=True)
+ }).db_insert()
# bootstrap uom conversion factors
uom_conversions = json.loads(open(frappe.get_app_path("erpnext", "setup", "setup_wizard", "data", "uom_conversion_data.json")).read())
@@ -336,7 +340,7 @@ def add_uom_data():
frappe.get_doc({
"doctype": "UOM Category",
"category_name": _(d.get("category"))
- }).insert(ignore_permissions=True)
+ }).db_insert()
if not frappe.db.exists("UOM Conversion Factor", {"from_uom": _(d.get("from_uom")), "to_uom": _(d.get("to_uom"))}):
uom_conversion = frappe.get_doc({
@@ -369,8 +373,8 @@ def add_sale_stages():
{"doctype": "Sales Stage", "stage_name": _("Proposal/Price Quote")},
{"doctype": "Sales Stage", "stage_name": _("Negotiation/Review")}
]
-
- make_records(records)
+ for sales_stage in records:
+ frappe.get_doc(sales_stage).db_insert()
def install_company(args):
records = [
@@ -418,7 +422,14 @@ def install_post_company_fixtures(args=None):
{'doctype': 'Department', 'department_name': _('Legal'), 'parent_department': _('All Departments'), 'company': args.company_name},
]
- make_records(records)
+ # Make root department with NSM updation
+ make_records(records[:1])
+
+ frappe.local.flags.ignore_update_nsm = True
+ make_records(records[1:])
+ frappe.local.flags.ignore_update_nsm = False
+
+ rebuild_tree("Department", "parent_department")
def install_defaults(args=None):
@@ -432,7 +443,15 @@ def install_defaults(args=None):
# enable default currency
frappe.db.set_value("Currency", args.get("currency"), "enabled", 1)
+ frappe.db.set_value("Stock Settings", None, "email_footer_address", args.get("company_name"))
+ set_global_defaults(args)
+ set_active_domains(args)
+ update_stock_settings()
+ update_shopping_cart_settings(args)
+ create_bank_account(args)
+
+def set_global_defaults(args):
global_defaults = frappe.get_doc("Global Defaults", "Global Defaults")
current_fiscal_year = frappe.get_all("Fiscal Year")[0]
@@ -445,13 +464,10 @@ def install_defaults(args=None):
global_defaults.save()
- system_settings = frappe.get_doc("System Settings")
- system_settings.email_footer_address = args.get("company_name")
- system_settings.save()
-
- domain_settings = frappe.get_single('Domain Settings')
- domain_settings.set_active_domains(args.get('domains'))
+def set_active_domains(args):
+ frappe.get_single('Domain Settings').set_active_domains(args.get('domains'))
+def update_stock_settings():
stock_settings = frappe.get_doc("Stock Settings")
stock_settings.item_naming_by = "Item Code"
stock_settings.valuation_method = "FIFO"
@@ -463,48 +479,44 @@ def install_defaults(args=None):
stock_settings.set_qty_in_transactions_based_on_serial_no_input = 1
stock_settings.save()
- if args.bank_account:
- company_name = args.company_name
- bank_account_group = frappe.db.get_value("Account",
- {"account_type": "Bank", "is_group": 1, "root_type": "Asset",
- "company": company_name})
- if bank_account_group:
- bank_account = frappe.get_doc({
- "doctype": "Account",
- 'account_name': args.bank_account,
- 'parent_account': bank_account_group,
- 'is_group':0,
- 'company': company_name,
- "account_type": "Bank",
- })
- try:
- doc = bank_account.insert()
+def create_bank_account(args):
+ if not args.bank_account:
+ return
- frappe.db.set_value("Company", args.company_name, "default_bank_account", bank_account.name, update_modified=False)
+ company_name = args.company_name
+ bank_account_group = frappe.db.get_value("Account",
+ {"account_type": "Bank", "is_group": 1, "root_type": "Asset",
+ "company": company_name})
+ if bank_account_group:
+ bank_account = frappe.get_doc({
+ "doctype": "Account",
+ 'account_name': args.bank_account,
+ 'parent_account': bank_account_group,
+ 'is_group':0,
+ 'company': company_name,
+ "account_type": "Bank",
+ })
+ try:
+ doc = bank_account.insert()
- except RootNotEditable:
- frappe.throw(_("Bank account cannot be named as {0}").format(args.bank_account))
- except frappe.DuplicateEntryError:
- # bank account same as a CoA entry
- pass
+ frappe.db.set_value("Company", args.company_name, "default_bank_account", bank_account.name, update_modified=False)
- # Now, with fixtures out of the way, onto concrete stuff
- records = [
-
- # Shopping cart: needs price lists
- {
- "doctype": "Shopping Cart Settings",
- "enabled": 1,
- 'company': args.company_name,
- # uh oh
- 'price_list': frappe.db.get_value("Price List", {"selling": 1}),
- 'default_customer_group': _("Individual"),
- 'quotation_series': "QTN-",
- },
- ]
-
- make_records(records)
+ except RootNotEditable:
+ frappe.throw(_("Bank account cannot be named as {0}").format(args.bank_account))
+ except frappe.DuplicateEntryError:
+ # bank account same as a CoA entry
+ pass
+def update_shopping_cart_settings(args):
+ shopping_cart = frappe.get_doc("Shopping Cart Settings")
+ shopping_cart.update({
+ "enabled": 1,
+ 'company': args.company_name,
+ 'price_list': frappe.db.get_value("Price List", {"selling": 1}),
+ 'default_customer_group': _("Individual"),
+ 'quotation_series': "QTN-",
+ })
+ shopping_cart.update_single(shopping_cart.get_valid_dict())
def get_fy_details(fy_start_date, fy_end_date):
start_year = getdate(fy_start_date).year
diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py
index e74d837ef5..f63d2695aa 100644
--- a/erpnext/setup/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/setup_wizard/setup_wizard.py
@@ -51,11 +51,6 @@ def get_setup_stages(args=None):
'status': _('Setting defaults'),
'fail_msg': 'Failed to set defaults',
'tasks': [
- {
- 'fn': setup_post_company_fixtures,
- 'args': args,
- 'fail_msg': _("Failed to setup post company fixtures")
- },
{
'fn': setup_defaults,
'args': args,
@@ -94,9 +89,6 @@ def stage_fixtures(args):
def setup_company(args):
fixtures.install_company(args)
-def setup_post_company_fixtures(args):
- fixtures.install_post_company_fixtures(args)
-
def setup_defaults(args):
fixtures.install_defaults(frappe._dict(args))
@@ -129,7 +121,6 @@ def login_as_first_user(args):
def setup_complete(args=None):
stage_fixtures(args)
setup_company(args)
- setup_post_company_fixtures(args)
setup_defaults(args)
stage_four(args)
fin(args)
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py
index 3b9608b805..2dd7c6f35b 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.py
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.py
@@ -30,7 +30,7 @@ class StockSettings(Document):
# show/hide barcode field
for name in ["barcode", "barcodes", "scan_barcode"]:
frappe.make_property_setter({'fieldname': name, 'property': 'hidden',
- 'value': 0 if self.show_barcode_field else 1})
+ 'value': 0 if self.show_barcode_field else 1}, validate_fields_for_doctype=False)
self.validate_warehouses()
self.cant_change_valuation_method()
@@ -67,10 +67,10 @@ class StockSettings(Document):
self.toggle_warehouse_field_for_inter_warehouse_transfer()
def toggle_warehouse_field_for_inter_warehouse_transfer(self):
- make_property_setter("Sales Invoice Item", "target_warehouse", "hidden", 1 - cint(self.allow_from_dn), "Check")
- make_property_setter("Delivery Note Item", "target_warehouse", "hidden", 1 - cint(self.allow_from_dn), "Check")
- make_property_setter("Purchase Invoice Item", "from_warehouse", "hidden", 1 - cint(self.allow_from_pr), "Check")
- make_property_setter("Purchase Receipt Item", "from_warehouse", "hidden", 1 - cint(self.allow_from_pr), "Check")
+ make_property_setter("Sales Invoice Item", "target_warehouse", "hidden", 1 - cint(self.allow_from_dn), "Check", validate_fields_for_doctype=False)
+ make_property_setter("Delivery Note Item", "target_warehouse", "hidden", 1 - cint(self.allow_from_dn), "Check", validate_fields_for_doctype=False)
+ make_property_setter("Purchase Invoice Item", "from_warehouse", "hidden", 1 - cint(self.allow_from_pr), "Check", validate_fields_for_doctype=False)
+ make_property_setter("Purchase Receipt Item", "from_warehouse", "hidden", 1 - cint(self.allow_from_pr), "Check", validate_fields_for_doctype=False)
def clean_all_descriptions():
From 4ecae62194d00f455dd757ce45bb80148d750977 Mon Sep 17 00:00:00 2001
From: Noah Jacob
Date: Thu, 6 May 2021 19:42:01 +0530
Subject: [PATCH 046/149] fix: added is_stock_item filter (#25530)
---
erpnext/manufacturing/doctype/bom/bom.js | 5 ++++-
erpnext/manufacturing/doctype/bom/bom.py | 3 +++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index fbfd801a11..a09a5e3430 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -29,7 +29,10 @@ frappe.ui.form.on("BOM", {
frm.set_query("item", function() {
return {
- query: "erpnext.manufacturing.doctype.bom.bom.item_query"
+ query: "erpnext.manufacturing.doctype.bom.bom.item_query",
+ filters: {
+ "is_stock_item": 1
+ }
};
});
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 979f7ca312..d1f63854c7 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -973,6 +973,9 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
if not has_variants:
query_filters["has_variants"] = 0
+ if filters and filters.get("is_stock_item"):
+ query_filters["is_stock_item"] = 1
+
return frappe.get_all("Item",
fields = fields, filters=query_filters,
or_filters = or_cond_filters, order_by=order_by,
From 5117cbc08ce86a911f10feee742c63ab39e78aba Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 7 May 2021 00:32:00 +0530
Subject: [PATCH 047/149] ci: Enable coveralls
---
.github/workflows/ci-tests.yml | 62 +++++++++++++++++++---------------
1 file changed, 35 insertions(+), 27 deletions(-)
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
index b03aad794b..4d955190be 100644
--- a/.github/workflows/ci-tests.yml
+++ b/.github/workflows/ci-tests.yml
@@ -12,13 +12,13 @@ jobs:
matrix:
include:
- TYPE: "server"
- JOB_NAME: "Server"
+ JOB_NAME: "Server.1"
RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext
- TYPE: "server"
- JOB_NAME: "Server"
+ JOB_NAME: "Server.2"
RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext
- TYPE: "server"
- JOB_NAME: "Server"
+ JOB_NAME: "Server.3"
RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext
- TYPE: "patch"
JOB_NAME: "Patch"
@@ -86,29 +86,37 @@ jobs:
env:
TYPE: ${{ matrix.TYPE }}
- # - name: Coverage - Pull Request
- # if: matrix.TYPE == 'server' && github.event_name == 'pull_request'
- # run: |
- # cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
- # cd ${GITHUB_WORKSPACE}
- # pip install coveralls==2.2.0
- # pip install coverage==4.5.4
- # coveralls --service=github
- # env:
- # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
- # COVERALLS_SERVICE_NAME: github
+ - name: Upload Coverage Data
+ if: matrix.TYPE == 'server'
+ run: |
+ cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
+ cd ${GITHUB_WORKSPACE}
+ pip3 install coverage==5.5
+ pip3 install coveralls==3.0.1
+ coveralls --service=github-actions
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
+ COVERALLS_FLAG_NAME: run-${{ matrix.container }}
+ COVERALLS_SERVICE_NAME: github-actions
+ COVERALLS_PARALLEL: true
- # - name: Coverage - Push
- # if: matrix.TYPE == 'server' && github.event_name == 'push'
- # run: |
- # cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
- # cd ${GITHUB_WORKSPACE}
- # pip install coveralls==2.2.0
- # pip install coverage==4.5.4
- # coveralls --service=github-actions
- # env:
- # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
- # COVERALLS_SERVICE_NAME: github-actions
+ coveralls:
+ name: Coverage Wrap Up
+ needs: test
+ container: python:3-slim
+ runs-on: ubuntu-18.04
+ steps:
+ - name: Clone
+ uses: actions/checkout@v2
+
+ - name: Coveralls Finished
+ run: |
+ cd ${GITHUB_WORKSPACE}
+ ls -al
+ pip3 install coverage==5.5
+ pip3 install coveralls==3.0.1
+ coveralls --finish
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
From 0e0de6baa14683b10b18e43d1b2dab03c9a94f37 Mon Sep 17 00:00:00 2001
From: Alan <2.alan.tom@gmail.com>
Date: Fri, 7 May 2021 11:40:02 +0530
Subject: [PATCH 048/149] fix: prevent spurious defaults for items when making
prec from dnote (#25559)
* fix: prevent spurious defaults for items when making prec from dnote
* refactor: make concise, use dict comp
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 4de877353a..bb74a02606 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1755,15 +1755,10 @@ def update_pr_items(doc, sales_item_map, purchase_item_map, parent_child_map, wa
item.purchase_order = parent_child_map.get(sales_item_map.get(item.delivery_note_item))
def get_delivery_note_details(internal_reference):
- so_item_map = {}
-
si_item_details = frappe.get_all('Delivery Note Item', fields=['name', 'so_detail'],
filters={'parent': internal_reference})
- for d in si_item_details:
- so_item_map.setdefault(d.name, d.so_detail)
-
- return so_item_map
+ return {d.name: d.so_detail for d in si_item_details if d.so_detail}
def get_sales_invoice_details(internal_reference):
dn_item_map = {}
From f132ed4335996a7848a386d017ed6cfbc93c8197 Mon Sep 17 00:00:00 2001
From: Anuja Pawar <60467153+Anuja-pawar@users.noreply.github.com>
Date: Fri, 7 May 2021 12:11:09 +0530
Subject: [PATCH 049/149] fix: update item level cost center from POS (#25609)
---
erpnext/stock/get_item_details.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 3832415db6..d1dcdc21c8 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -79,7 +79,7 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru
get_price_list_rate(args, item, out)
if args.customer and cint(args.is_pos):
- out.update(get_pos_profile_item_details(args.company, args))
+ out.update(get_pos_profile_item_details(args.company, args, update_data=True))
if (args.get("doctype") == "Material Request" and
args.get("material_request_type") == "Material Transfer"):
@@ -935,8 +935,8 @@ def get_bin_details(item_code, warehouse, company=None):
return bin_details
def get_company_total_stock(item_code, company):
- return frappe.db.sql("""SELECT sum(actual_qty) from
- (`tabBin` INNER JOIN `tabWarehouse` ON `tabBin`.warehouse = `tabWarehouse`.name)
+ return frappe.db.sql("""SELECT sum(actual_qty) from
+ (`tabBin` INNER JOIN `tabWarehouse` ON `tabBin`.warehouse = `tabWarehouse`.name)
WHERE `tabWarehouse`.company = %s and `tabBin`.item_code = %s""",
(company, item_code))[0][0]
From 996f7e53a19e2ab741f9709f09f774d04498cc81 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Fri, 7 May 2021 12:14:14 +0530
Subject: [PATCH 050/149] fix: update shopify api version (#25600)
---
.../erpnext_integrations/connectors/shopify_connection.py | 6 +++---
.../doctype/shopify_settings/shopify_settings.py | 4 ++--
.../doctype/shopify_settings/sync_product.py | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/erpnext/erpnext_integrations/connectors/shopify_connection.py b/erpnext/erpnext_integrations/connectors/shopify_connection.py
index f0a05ed192..5d5b2e19ce 100644
--- a/erpnext/erpnext_integrations/connectors/shopify_connection.py
+++ b/erpnext/erpnext_integrations/connectors/shopify_connection.py
@@ -335,13 +335,13 @@ def get_url(shopify_settings):
if not last_order_id:
if shopify_settings.sync_based_on == 'Date':
- url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&created_at_min={0}&since_id=0".format(
+ url = get_shopify_url("admin/api/2021-04/orders.json?limit=250&created_at_min={0}&since_id=0".format(
get_datetime(shopify_settings.from_date)), shopify_settings)
else:
- url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(
+ url = get_shopify_url("admin/api/2021-04/orders.json?limit=250&since_id={0}".format(
shopify_settings.from_order_id), shopify_settings)
else:
- url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(last_order_id), shopify_settings)
+ url = get_shopify_url("admin/api/2021-04/orders.json?limit=250&since_id={0}".format(last_order_id), shopify_settings)
return url
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
index cbdf90681d..7634fd0caf 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
@@ -30,7 +30,7 @@ class ShopifySettings(Document):
webhooks = ["orders/create", "orders/paid", "orders/fulfilled"]
# url = get_shopify_url('admin/webhooks.json', self)
created_webhooks = [d.method for d in self.webhooks]
- url = get_shopify_url('admin/api/2020-04/webhooks.json', self)
+ url = get_shopify_url('admin/api/2021-04/webhooks.json', self)
for method in webhooks:
session = get_request_session()
try:
@@ -56,7 +56,7 @@ class ShopifySettings(Document):
deleted_webhooks = []
for d in self.webhooks:
- url = get_shopify_url('admin/api/2020-04/webhooks/{0}.json'.format(d.webhook_id), self)
+ url = get_shopify_url('admin/api/2021-04/webhooks/{0}.json'.format(d.webhook_id), self)
try:
res = session.delete(url, headers=get_header(self))
res.raise_for_status()
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py
index f9f0bb3cec..16efb6caee 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py
@@ -8,7 +8,7 @@ from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings impo
shopify_variants_attr_list = ["option1", "option2", "option3"]
def sync_item_from_shopify(shopify_settings, item):
- url = get_shopify_url("admin/api/2020-04/products/{0}.json".format(item.get("product_id")), shopify_settings)
+ url = get_shopify_url("admin/api/2021-04/products/{0}.json".format(item.get("product_id")), shopify_settings)
session = get_request_session()
try:
From f648d2d7c4a23061f4b0a03afa060d0d061eea95 Mon Sep 17 00:00:00 2001
From: Shadrak Gurupnor <30501401+shadrak98@users.noreply.github.com>
Date: Fri, 7 May 2021 12:15:19 +0530
Subject: [PATCH 051/149] fix: added tax_types list (#25587)
---
.../v12_0/move_item_tax_to_item_tax_template.py | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
index 06331d7ff7..a6471eb53c 100644
--- a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
+++ b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
@@ -44,9 +44,11 @@ def execute():
# make current item's tax map
item_tax_map = {}
for d in old_item_taxes[item_code]:
- item_tax_map[d.tax_type] = d.tax_rate
+ if d.tax_type not in item_tax_map:
+ item_tax_map[d.tax_type] = d.tax_rate
- item_tax_template_name = get_item_tax_template(item_tax_templates, item_tax_map, item_code)
+ tax_types = []
+ item_tax_template_name = get_item_tax_template(item_tax_templates, item_tax_map, item_code, tax_types=tax_types)
# update the item tax table
frappe.db.sql("delete from `tabItem Tax` where parent=%s and parenttype='Item'", item_code)
@@ -68,7 +70,7 @@ def execute():
and item_tax_template is NULL""".format(dt), as_dict=1):
item_tax_map = json.loads(d.item_tax_rate)
item_tax_template_name = get_item_tax_template(item_tax_templates,
- item_tax_map, d.item_code, d.parenttype, d.parent)
+ item_tax_map, d.item_code, d.parenttype, d.parent, tax_types=tax_types)
frappe.db.set_value(dt + " Item", d.name, "item_tax_template", item_tax_template_name)
frappe.db.auto_commit_on_many_writes = False
@@ -78,7 +80,7 @@ def execute():
settings.determine_address_tax_category_from = "Billing Address"
settings.save()
-def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttype=None, parent=None):
+def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttype=None, parent=None, tax_types=None):
# search for previously created item tax template by comparing tax maps
for template, item_tax_template_map in iteritems(item_tax_templates):
if item_tax_map == item_tax_template_map:
@@ -126,7 +128,9 @@ def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttyp
account_type = frappe.get_cached_value("Account", tax_type, "account_type")
if tax_type and account_type in ('Tax', 'Chargeable', 'Income Account', 'Expense Account', 'Expenses Included In Valuation'):
- item_tax_template.append("taxes", {"tax_type": tax_type, "tax_rate": tax_rate})
+ if tax_type not in tax_types:
+ item_tax_template.append("taxes", {"tax_type": tax_type, "tax_rate": tax_rate})
+ tax_types.append(tax_type)
item_tax_templates.setdefault(item_tax_template.title, {})
item_tax_templates[item_tax_template.title][tax_type] = tax_rate
if item_tax_template.get("taxes"):
From 00e00e4e903ac9f6e37520903b0e7ca97e1c388b Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Fri, 7 May 2021 12:16:44 +0530
Subject: [PATCH 052/149] fix: Report summary showing inflated values when
values are accumulated in Group Company (#25577)
* fix: Report summary showing inflated values when values are accumullated in Group Company
* fix: Remove extra space
* fix: Translate strings
* fix: Remove unintended changes
---
.../report/balance_sheet/balance_sheet.py | 7 ++++++-
erpnext/accounts/report/cash_flow/cash_flow.py | 17 ++++++++++++-----
.../consolidated_financial_statement.py | 6 +++---
erpnext/accounts/report/financial_statements.py | 14 +++++++++++---
.../profit_and_loss_statement.py | 11 ++++++++---
5 files changed, 40 insertions(+), 15 deletions(-)
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py
index 1729abce9e..287b8a7484 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.py
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py
@@ -5,7 +5,8 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt, cint
-from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
+from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data,
+ get_filtered_list_for_consolidated_report)
def execute(filters=None):
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
@@ -132,6 +133,10 @@ def get_report_summary(period_list, asset, liability, equity, provisional_profit
if filters.get('accumulated_values'):
period_list = [period_list[-1]]
+ # from consolidated financial statement
+ if filters.get('accumulated_in_group_company'):
+ period_list = get_filtered_list_for_consolidated_report(period_list)
+
for period in period_list:
key = period if consolidated else period.key
if asset:
diff --git a/erpnext/accounts/report/cash_flow/cash_flow.py b/erpnext/accounts/report/cash_flow/cash_flow.py
index cf0946beab..3577457c98 100644
--- a/erpnext/accounts/report/cash_flow/cash_flow.py
+++ b/erpnext/accounts/report/cash_flow/cash_flow.py
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cint, cstr
-from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
+from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data, get_filtered_list_for_consolidated_report)
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss
from erpnext.accounts.utils import get_fiscal_year
from six import iteritems
@@ -67,9 +67,9 @@ def execute(filters=None):
section_data.append(account_data)
add_total_row_account(data, section_data, cash_flow_account['section_footer'],
- period_list, company_currency, summary_data)
+ period_list, company_currency, summary_data, filters)
- add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency, summary_data)
+ add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency, summary_data, filters)
columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company)
chart = get_chart_data(columns, data)
@@ -162,18 +162,26 @@ def get_start_date(period, accumulated_values, company):
return start_date
-def add_total_row_account(out, data, label, period_list, currency, summary_data, consolidated = False):
+def add_total_row_account(out, data, label, period_list, currency, summary_data, filters, consolidated=False):
total_row = {
"account_name": "'" + _("{0}").format(label) + "'",
"account": "'" + _("{0}").format(label) + "'",
"currency": currency
}
+
+ summary_data[label] = 0
+
+ # from consolidated financial statement
+ if filters.get('accumulated_in_group_company'):
+ period_list = get_filtered_list_for_consolidated_report(filters, period_list)
+
for row in data:
if row.get("parent_account"):
for period in period_list:
key = period if consolidated else period['key']
total_row.setdefault(key, 0.0)
total_row[key] += row.get(key, 0.0)
+ summary_data[label] += row.get(key)
total_row.setdefault("total", 0.0)
total_row["total"] += row["total"]
@@ -181,7 +189,6 @@ def add_total_row_account(out, data, label, period_list, currency, summary_data,
out.append(total_row)
out.append({})
- summary_data[label] = total_row["total"]
def get_report_summary(summary_data, currency):
report_summary = []
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
index 094f5db89b..7793af737f 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -94,7 +94,7 @@ def get_profit_loss_data(fiscal_year, companies, columns, filters):
chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss)
- report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, company_currency, True)
+ report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, company_currency, filters, True)
return data, None, chart, report_summary
@@ -149,9 +149,9 @@ def get_cash_flow_data(fiscal_year, companies, filters):
section_data.append(account_data)
add_total_row_account(data, section_data, cash_flow_account['section_footer'],
- companies, company_currency, summary_data, True)
+ companies, company_currency, summary_data, filters, True)
- add_total_row_account(data, data, _("Net Change in Cash"), companies, company_currency, summary_data, True)
+ add_total_row_account(data, data, _("Net Change in Cash"), companies, company_currency, summary_data, filters, True)
report_summary = get_cash_flow_summary(summary_data, company_currency)
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 14efa1f8fc..d20ddbde5c 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -119,10 +119,10 @@ def validate_fiscal_year(fiscal_year, from_fiscal_year, to_fiscal_year):
def validate_dates(from_date, to_date):
if not from_date or not to_date:
- frappe.throw("From Date and To Date are mandatory")
+ frappe.throw(_("From Date and To Date are mandatory"))
if to_date < from_date:
- frappe.throw("To Date cannot be less than From Date")
+ frappe.throw(_("To Date cannot be less than From Date"))
def get_months(start_date, end_date):
diff = (12 * end_date.year + end_date.month) - (12 * start_date.year + start_date.month)
@@ -522,4 +522,12 @@ def get_columns(periodicity, period_list, accumulated_values=1, company=None):
"width": 150
})
- return columns
\ No newline at end of file
+ return columns
+
+def get_filtered_list_for_consolidated_report(filters, period_list):
+ filtered_summary_list = []
+ for period in period_list:
+ if period == filters.get('company'):
+ filtered_summary_list.append(period)
+
+ return filtered_summary_list
diff --git a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py
index fe261b30b4..5d04824b57 100644
--- a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py
+++ b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py
@@ -5,7 +5,8 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt
-from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
+from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data,
+ get_filtered_list_for_consolidated_report)
def execute(filters=None):
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
@@ -33,13 +34,17 @@ def execute(filters=None):
chart = get_chart_data(filters, columns, income, expense, net_profit_loss)
currency = filters.presentation_currency or frappe.get_cached_value('Company', filters.company, "default_currency")
- report_summary = get_report_summary(period_list, filters.periodicity, income, expense, net_profit_loss, currency)
+ report_summary = get_report_summary(period_list, filters.periodicity, income, expense, net_profit_loss, currency, filters)
return columns, data, None, chart, report_summary
-def get_report_summary(period_list, periodicity, income, expense, net_profit_loss, currency, consolidated=False):
+def get_report_summary(period_list, periodicity, income, expense, net_profit_loss, currency, filters, consolidated=False):
net_income, net_expense, net_profit = 0.0, 0.0, 0.0
+ # from consolidated financial statement
+ if filters.get('accumulated_in_group_company'):
+ period_list = get_filtered_list_for_consolidated_report(filters, period_list)
+
for period in period_list:
key = period if consolidated else period.key
if income:
From 735fbdc350d0449720db36e684c85ca56161442f Mon Sep 17 00:00:00 2001
From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com>
Date: Fri, 7 May 2021 12:26:32 +0530
Subject: [PATCH 053/149] fix: Updating Standard Notification's channel field
(#25564)
---
.../notification_for_new_fiscal_year.json | 1 +
erpnext/hr/notification/training_feedback/training_feedback.json | 1 +
.../payroll/notification/retention_bonus/retention_bonus.json | 1 +
3 files changed, 3 insertions(+)
diff --git a/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.json b/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.json
index bd7a126517..4c7faf4f65 100644
--- a/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.json
+++ b/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.json
@@ -1,5 +1,6 @@
{
"attach_print": 0,
+ "channel": "Email",
"condition": "doc.auto_created",
"creation": "2018-04-25 14:19:05.440361",
"days_in_advance": 0,
diff --git a/erpnext/hr/notification/training_feedback/training_feedback.json b/erpnext/hr/notification/training_feedback/training_feedback.json
index 2cc064f34a..92b68a98a9 100644
--- a/erpnext/hr/notification/training_feedback/training_feedback.json
+++ b/erpnext/hr/notification/training_feedback/training_feedback.json
@@ -1,5 +1,6 @@
{
"attach_print": 0,
+ "channel": "Email",
"creation": "2017-08-11 03:17:11.769210",
"days_in_advance": 0,
"docstatus": 0,
diff --git a/erpnext/payroll/notification/retention_bonus/retention_bonus.json b/erpnext/payroll/notification/retention_bonus/retention_bonus.json
index 50db0338c4..37381fa942 100644
--- a/erpnext/payroll/notification/retention_bonus/retention_bonus.json
+++ b/erpnext/payroll/notification/retention_bonus/retention_bonus.json
@@ -1,5 +1,6 @@
{
"attach_print": 0,
+ "channel": "Email",
"condition": "doc.docstatus==1",
"creation": "2018-05-15 18:52:36.362838",
"date_changed": "bonus_payment_date",
From 7f79d463f69237189f9393c820e1bae58054493a Mon Sep 17 00:00:00 2001
From: Umair Sayed
Date: Fri, 7 May 2021 12:28:57 +0530
Subject: [PATCH 054/149] fix: Stock and Accounts Settings form refactor
(#25534)
* stock and accounts settings page
* fix: Stock and accounts settings page cleanup
Co-authored-by: Umair Sayed
---
.../accounts_settings/accounts_settings.json | 61 ++++++++++------
.../stock_settings/stock_settings.json | 70 ++++++++++++-------
2 files changed, 86 insertions(+), 45 deletions(-)
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
index e1276e7da3..781f94e203 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -7,26 +7,30 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "auto_accounting_for_stock",
- "acc_frozen_upto",
- "frozen_accounts_modifier",
- "determine_address_tax_category_from",
+ "accounts_transactions_settings_section",
"over_billing_allowance",
"role_allowed_to_over_bill",
- "column_break_4",
- "credit_controller",
- "check_supplier_invoice_uniqueness",
"make_payment_via_journal_entry",
+ "column_break_11",
+ "check_supplier_invoice_uniqueness",
"unlink_payment_on_cancellation_of_invoice",
- "unlink_advance_payment_on_cancelation_of_order",
- "book_asset_depreciation_entry_automatically",
- "add_taxes_from_item_tax_template",
"automatically_fetch_payment_terms",
"delete_linked_ledger_entries",
+ "book_asset_depreciation_entry_automatically",
+ "unlink_advance_payment_on_cancelation_of_order",
+ "tax_settings_section",
+ "determine_address_tax_category_from",
+ "column_break_19",
+ "add_taxes_from_item_tax_template",
+ "period_closing_settings_section",
+ "acc_frozen_upto",
+ "frozen_accounts_modifier",
+ "column_break_4",
+ "credit_controller",
"deferred_accounting_settings_section",
- "automatically_process_deferred_accounting_entry",
"book_deferred_entries_based_on",
"column_break_18",
+ "automatically_process_deferred_accounting_entry",
"book_deferred_entries_via_journal_entry",
"submit_journal_entries",
"print_settings",
@@ -40,15 +44,6 @@
"use_custom_cash_flow"
],
"fields": [
- {
- "default": "1",
- "description": "If enabled, the system will post accounting entries for inventory automatically",
- "fieldname": "auto_accounting_for_stock",
- "fieldtype": "Check",
- "hidden": 1,
- "in_list_view": 1,
- "label": "Make Accounting Entry For Every Stock Movement"
- },
{
"description": "Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below",
"fieldname": "acc_frozen_upto",
@@ -94,6 +89,7 @@
"default": "0",
"fieldname": "make_payment_via_journal_entry",
"fieldtype": "Check",
+ "hidden": 1,
"label": "Make Payment via Journal Entry"
},
{
@@ -234,6 +230,29 @@
"fieldtype": "Link",
"label": "Role Allowed to Over Bill ",
"options": "Role"
+ },
+ {
+ "fieldname": "period_closing_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Period Closing Settings"
+ },
+ {
+ "fieldname": "accounts_transactions_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Transactions Settings"
+ },
+ {
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "tax_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Tax Settings"
+ },
+ {
+ "fieldname": "column_break_19",
+ "fieldtype": "Column Break"
}
],
"icon": "icon-cog",
@@ -241,7 +260,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-03-11 18:52:05.601996",
+ "modified": "2021-04-30 15:25:10.381008",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json
index f18eabc84b..cf5d98d092 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.json
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.json
@@ -5,40 +5,44 @@
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
+ "item_defaults_section",
"item_naming_by",
"item_group",
"stock_uom",
"default_warehouse",
- "sample_retention_warehouse",
"column_break_4",
"valuation_method",
+ "sample_retention_warehouse",
+ "use_naming_series",
+ "naming_series_prefix",
+ "section_break_9",
"over_delivery_receipt_allowance",
"role_allowed_to_over_deliver_receive",
- "action_if_quality_inspection_is_not_submitted",
- "show_barcode_field",
- "clean_description_html",
- "disable_serial_no_and_batch_selector",
- "section_break_7",
+ "column_break_12",
"auto_insert_price_list_rate_if_missing",
"allow_negative_stock",
- "column_break_10",
+ "show_barcode_field",
+ "clean_description_html",
+ "action_if_quality_inspection_is_not_submitted",
+ "section_break_7",
"automatically_set_serial_nos_based_on_fifo",
"set_qty_in_transactions_based_on_serial_no_input",
+ "column_break_10",
+ "disable_serial_no_and_batch_selector",
"auto_material_request",
"auto_indent",
+ "column_break_27",
"reorder_email_notify",
"inter_warehouse_transfer_settings_section",
"allow_from_dn",
+ "column_break_31",
"allow_from_pr",
"control_historical_stock_transactions_section",
- "role_allowed_to_create_edit_back_dated_transactions",
- "column_break_26",
"stock_frozen_upto",
"stock_frozen_upto_days",
- "stock_auth_role",
- "batch_id_sb",
- "use_naming_series",
- "naming_series_prefix"
+ "column_break_26",
+ "role_allowed_to_create_edit_back_dated_transactions",
+ "stock_auth_role"
],
"fields": [
{
@@ -102,23 +106,24 @@
"default": "1",
"fieldname": "show_barcode_field",
"fieldtype": "Check",
- "label": "Show Barcode Field"
+ "label": "Show Barcode Field in Stock Transactions"
},
{
"default": "1",
"fieldname": "clean_description_html",
"fieldtype": "Check",
- "label": "Convert Item Description to Clean HTML"
+ "label": "Convert Item Description to Clean HTML in Transactions"
},
{
"fieldname": "section_break_7",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Serialised and Batch Setting"
},
{
"default": "0",
"fieldname": "auto_insert_price_list_rate_if_missing",
"fieldtype": "Check",
- "label": "Auto Insert Price List Rate If Missing"
+ "label": "Auto Insert Item Price If Missing"
},
{
"default": "0",
@@ -179,16 +184,11 @@
"label": "Role Allowed to Edit Frozen Stock",
"options": "Role"
},
- {
- "fieldname": "batch_id_sb",
- "fieldtype": "Section Break",
- "label": "Batch Identification"
- },
{
"default": "0",
"fieldname": "use_naming_series",
"fieldtype": "Check",
- "label": "Use Naming Series"
+ "label": "Have Default Naming Series for Batch ID?"
},
{
"default": "BATCH-",
@@ -242,6 +242,28 @@
"fieldtype": "Link",
"label": "Role Allowed to Over Deliver/Receive",
"options": "Role"
+ },
+ {
+ "fieldname": "item_defaults_section",
+ "fieldtype": "Section Break",
+ "label": "Item Defaults"
+ },
+ {
+ "fieldname": "section_break_9",
+ "fieldtype": "Section Break",
+ "label": "Stock Transactions Settings"
+ },
+ {
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_27",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_31",
+ "fieldtype": "Column Break"
}
],
"icon": "icon-cog",
@@ -249,7 +271,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-03-11 18:48:14.513055",
+ "modified": "2021-04-30 17:27:42.709231",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Settings",
From 062d30146f967a28672a76f9f8d286c0d28470ca Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Fri, 7 May 2021 13:31:14 +0530
Subject: [PATCH 055/149] fix: Include search fields in Project Link field
query (#25505)
* fix: Include search fields in Project Link field query
* fix: add project_name to Project search fields
---
erpnext/controllers/queries.py | 10 +++++++---
erpnext/projects/doctype/project/project.json | 6 +++---
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index bc1ac5ea06..b31724fa48 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -292,11 +292,14 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters):
cond = """(`tabProject`.customer = %s or
ifnull(`tabProject`.customer,"")="") and""" %(frappe.db.escape(filters.get("customer")))
- fields = get_fields("Project", ["name"])
+ fields = get_fields("Project", ["name", "project_name"])
+ searchfields = frappe.get_meta("Project").get_search_fields()
+ searchfields = " or ".join([field + " like %(txt)s" for field in searchfields])
return frappe.db.sql("""select {fields} from `tabProject`
- where `tabProject`.status not in ("Completed", "Cancelled")
- and {cond} `tabProject`.name like %(txt)s {match_cond}
+ where
+ `tabProject`.status not in ("Completed", "Cancelled")
+ and {cond} {match_cond} {scond}
order by
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
idx desc,
@@ -304,6 +307,7 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters):
limit {start}, {page_len}""".format(
fields=", ".join(['`tabProject`.{0}'.format(f) for f in fields]),
cond=cond,
+ scond=searchfields,
match_cond=get_match_cond(doctype),
start=start,
page_len=page_len), {
diff --git a/erpnext/projects/doctype/project/project.json b/erpnext/projects/doctype/project/project.json
index 3cdfcb212f..2570df7026 100644
--- a/erpnext/projects/doctype/project/project.json
+++ b/erpnext/projects/doctype/project/project.json
@@ -458,7 +458,7 @@
"index_web_pages_for_search": 1,
"links": [],
"max_attachments": 4,
- "modified": "2020-09-02 11:54:01.223620",
+ "modified": "2021-04-28 16:36:11.654632",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project",
@@ -495,11 +495,11 @@
}
],
"quick_entry": 1,
- "search_fields": "customer, status, priority, is_active",
+ "search_fields": "project_name,customer, status, priority, is_active",
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"timeline_field": "customer",
"title_field": "project_name",
"track_seen": 1
-}
+}
\ No newline at end of file
From 5618ce3852e0dbad1460d31dae834cf19d61a197 Mon Sep 17 00:00:00 2001
From: Ganga Manoj
Date: Fri, 7 May 2021 13:35:09 +0530
Subject: [PATCH 056/149] fix(Material Request): Add 'Partially Received' to
Status drop-down list (#24857)
Co-authored-by: Ganga Manoj
Co-authored-by: Nabin Hait
---
erpnext/stock/doctype/material_request/material_request.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json
index 8d7b238c17..4e2d9e6170 100644
--- a/erpnext/stock/doctype/material_request/material_request.json
+++ b/erpnext/stock/doctype/material_request/material_request.json
@@ -181,7 +181,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nDraft\nSubmitted\nStopped\nCancelled\nPending\nPartially Ordered\nOrdered\nIssued\nTransferred\nReceived",
+ "options": "\nDraft\nSubmitted\nStopped\nCancelled\nPending\nPartially Ordered\nPartially Received\nOrdered\nIssued\nTransferred\nReceived",
"print_hide": 1,
"print_width": "100px",
"read_only": 1,
From 27cf19a19f09169a0f5fc08d537555471cc466e2 Mon Sep 17 00:00:00 2001
From: Saqib
Date: Fri, 7 May 2021 13:37:42 +0530
Subject: [PATCH 057/149] feat(pos): show POS reserved stock in stock projected
qty report (#25593)
* feat(pos): consider POS reserved stock in stock projected qty report
* chore: remove unwanted string formats
---
.../doctype/pos_invoice/pos_invoice.py | 22 +++++++++++--------
.../report/pos_register/pos_register.py | 13 +++++------
.../stock_projected_qty.js | 9 +++++++-
.../stock_projected_qty.py | 13 ++++++++---
4 files changed, 36 insertions(+), 21 deletions(-)
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index 1e6a3d1b3b..473db565fa 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -461,7 +461,17 @@ def get_stock_availability(item_code, warehouse):
order by posting_date desc, posting_time desc
limit 1""", (item_code, warehouse), as_dict=1)
- pos_sales_qty = frappe.db.sql("""select sum(p_item.qty) as qty
+ pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
+
+ sle_qty = latest_sle[0].qty_after_transaction or 0 if latest_sle else 0
+
+ if sle_qty and pos_sales_qty:
+ return sle_qty - pos_sales_qty
+ else:
+ return sle_qty
+
+def get_pos_reserved_qty(item_code, warehouse):
+ reserved_qty = frappe.db.sql("""select sum(p_item.qty) as qty
from `tabPOS Invoice` p, `tabPOS Invoice Item` p_item
where p.name = p_item.parent
and p.consolidated_invoice is NULL
@@ -470,14 +480,8 @@ def get_stock_availability(item_code, warehouse):
and p_item.item_code = %s
and p_item.warehouse = %s
""", (item_code, warehouse), as_dict=1)
-
- sle_qty = latest_sle[0].qty_after_transaction or 0 if latest_sle else 0
- pos_sales_qty = pos_sales_qty[0].qty or 0 if pos_sales_qty else 0
-
- if sle_qty and pos_sales_qty:
- return sle_qty - pos_sales_qty
- else:
- return sle_qty
+
+ return reserved_qty[0].qty or 0 if reserved_qty else 0
@frappe.whitelist()
def make_sales_return(source_name, target_doc=None):
diff --git a/erpnext/accounts/report/pos_register/pos_register.py b/erpnext/accounts/report/pos_register/pos_register.py
index 52f7fe238e..cfbd7fd0c8 100644
--- a/erpnext/accounts/report/pos_register/pos_register.py
+++ b/erpnext/accounts/report/pos_register/pos_register.py
@@ -116,22 +116,19 @@ def validate_filters(filters):
frappe.throw(_("Can not filter based on Payment Method, if grouped by Payment Method"))
def get_conditions(filters):
- conditions = "company = %(company)s AND posting_date >= %(from_date)s AND posting_date <= %(to_date)s".format(
- company=filters.get("company"),
- from_date=filters.get("from_date"),
- to_date=filters.get("to_date"))
+ conditions = "company = %(company)s AND posting_date >= %(from_date)s AND posting_date <= %(to_date)s"
if filters.get("pos_profile"):
- conditions += " AND pos_profile = %(pos_profile)s".format(pos_profile=filters.get("pos_profile"))
+ conditions += " AND pos_profile = %(pos_profile)s"
if filters.get("owner"):
- conditions += " AND owner = %(owner)s".format(owner=filters.get("owner"))
+ conditions += " AND owner = %(owner)s"
if filters.get("customer"):
- conditions += " AND customer = %(customer)s".format(customer=filters.get("customer"))
+ conditions += " AND customer = %(customer)s"
if filters.get("is_return"):
- conditions += " AND is_return = %(is_return)s".format(is_return=filters.get("is_return"))
+ conditions += " AND is_return = %(is_return)s"
if filters.get("mode_of_payment"):
conditions += """
diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.js b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.js
index babc6dc960..cb109f8050 100644
--- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.js
+++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.js
@@ -14,7 +14,14 @@ frappe.query_reports["Stock Projected Qty"] = {
"fieldname":"warehouse",
"label": __("Warehouse"),
"fieldtype": "Link",
- "options": "Warehouse"
+ "options": "Warehouse",
+ "get_query": () => {
+ return {
+ filters: {
+ company: frappe.query_report.get_filter_value('company')
+ }
+ }
+ }
},
{
"fieldname":"item_code",
diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
index 1183e41d04..808d279170 100644
--- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
+++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
@@ -6,6 +6,7 @@ import frappe
from frappe import _
from frappe.utils import flt, today
from erpnext.stock.utils import update_included_uom_in_report, is_reposting_item_valuation_in_progress
+from erpnext.accounts.doctype.pos_invoice.pos_invoice import get_pos_reserved_qty
def execute(filters=None):
is_reposting_item_valuation_in_progress()
@@ -49,9 +50,13 @@ def execute(filters=None):
if (re_order_level or re_order_qty) and re_order_level > bin.projected_qty:
shortage_qty = re_order_level - flt(bin.projected_qty)
+ reserved_qty_for_pos = get_pos_reserved_qty(bin.item_code, bin.warehouse)
+ if reserved_qty_for_pos:
+ bin.projected_qty -= reserved_qty_for_pos
+
data.append([item.name, item.item_name, item.description, item.item_group, item.brand, bin.warehouse,
item.stock_uom, bin.actual_qty, bin.planned_qty, bin.indented_qty, bin.ordered_qty,
- bin.reserved_qty, bin.reserved_qty_for_production, bin.reserved_qty_for_sub_contract,
+ bin.reserved_qty, bin.reserved_qty_for_production, bin.reserved_qty_for_sub_contract, reserved_qty_for_pos,
bin.projected_qty, re_order_level, re_order_qty, shortage_qty])
if include_uom:
@@ -74,9 +79,11 @@ def get_columns():
{"label": _("Requested Qty"), "fieldname": "indented_qty", "fieldtype": "Float", "width": 110, "convertible": "qty"},
{"label": _("Ordered Qty"), "fieldname": "ordered_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
{"label": _("Reserved Qty"), "fieldname": "reserved_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
- {"label": _("Reserved Qty for Production"), "fieldname": "reserved_qty_for_production", "fieldtype": "Float",
+ {"label": _("Reserved for Production"), "fieldname": "reserved_qty_for_production", "fieldtype": "Float",
"width": 100, "convertible": "qty"},
- {"label": _("Reserved for sub contracting"), "fieldname": "reserved_qty_for_sub_contract", "fieldtype": "Float",
+ {"label": _("Reserved for Sub Contracting"), "fieldname": "reserved_qty_for_sub_contract", "fieldtype": "Float",
+ "width": 100, "convertible": "qty"},
+ {"label": _("Reserved for POS Transactions"), "fieldname": "reserved_qty_for_pos", "fieldtype": "Float",
"width": 100, "convertible": "qty"},
{"label": _("Projected Qty"), "fieldname": "projected_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
{"label": _("Reorder Level"), "fieldname": "re_order_level", "fieldtype": "Float", "width": 100, "convertible": "qty"},
From f75173826707e10815cfd91bc167c00434a0a6c8 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Fri, 7 May 2021 14:51:05 +0530
Subject: [PATCH 058/149] fix: Make js bundles
---
.../js/bank-reconciliation-tool.bundle.js | 3 +++
erpnext/public/js/erpnext-web.bundle.js | 2 ++
erpnext/public/js/erpnext.bundle.js | 27 +++++++++++++++++++
.../{marketplace.js => marketplace.bundle.js} | 0
erpnext/public/js/item-dashboard.bundle.js | 5 ++++
erpnext/public/js/point-of-sale.bundle.js | 8 ++++++
6 files changed, 45 insertions(+)
create mode 100644 erpnext/public/js/bank-reconciliation-tool.bundle.js
create mode 100644 erpnext/public/js/erpnext-web.bundle.js
create mode 100644 erpnext/public/js/erpnext.bundle.js
rename erpnext/public/js/hub/{marketplace.js => marketplace.bundle.js} (100%)
create mode 100644 erpnext/public/js/item-dashboard.bundle.js
create mode 100644 erpnext/public/js/point-of-sale.bundle.js
diff --git a/erpnext/public/js/bank-reconciliation-tool.bundle.js b/erpnext/public/js/bank-reconciliation-tool.bundle.js
new file mode 100644
index 0000000000..636ef18a51
--- /dev/null
+++ b/erpnext/public/js/bank-reconciliation-tool.bundle.js
@@ -0,0 +1,3 @@
+import "./bank_reconciliation_tool/data_table_manager";
+import "./bank_reconciliation_tool/number_card";
+import "./bank_reconciliation_tool/dialog_manager";
diff --git a/erpnext/public/js/erpnext-web.bundle.js b/erpnext/public/js/erpnext-web.bundle.js
new file mode 100644
index 0000000000..7db6967923
--- /dev/null
+++ b/erpnext/public/js/erpnext-web.bundle.js
@@ -0,0 +1,2 @@
+import "./website_utils";
+import "./shopping_cart";
diff --git a/erpnext/public/js/erpnext.bundle.js b/erpnext/public/js/erpnext.bundle.js
new file mode 100644
index 0000000000..519cfcac72
--- /dev/null
+++ b/erpnext/public/js/erpnext.bundle.js
@@ -0,0 +1,27 @@
+import "./conf";
+import "./utils";
+import "./queries";
+import "./sms_manager";
+import "./utils/party";
+import "./controllers/stock_controller";
+import "./payment/payments";
+import "./controllers/taxes_and_totals";
+import "./controllers/transaction";
+import "./templates/item_selector.html";
+import "./templates/employees_to_mark_attendance.html";
+import "./utils/item_selector";
+import "./help_links";
+import "./agriculture/ternary_plot";
+import "./templates/item_quick_entry.html";
+import "./utils/item_quick_entry";
+import "./utils/customer_quick_entry";
+import "./education/student_button.html";
+import "./education/assessment_result_tool.html";
+import "./hub/hub_factory";
+import "./call_popup/call_popup";
+import "./utils/dimension_tree_filter";
+import "./telephony";
+import "./templates/call_link.html";
+
+// import { sum } from 'frappe/public/utils/util.js'
+
diff --git a/erpnext/public/js/hub/marketplace.js b/erpnext/public/js/hub/marketplace.bundle.js
similarity index 100%
rename from erpnext/public/js/hub/marketplace.js
rename to erpnext/public/js/hub/marketplace.bundle.js
diff --git a/erpnext/public/js/item-dashboard.bundle.js b/erpnext/public/js/item-dashboard.bundle.js
new file mode 100644
index 0000000000..2d329e26aa
--- /dev/null
+++ b/erpnext/public/js/item-dashboard.bundle.js
@@ -0,0 +1,5 @@
+import "../../stock/dashboard/item_dashboard.html";
+import "../../stock/dashboard/item_dashboard_list.html";
+import "../../stock/dashboard/item_dashboard.js";
+import "../../stock/page/warehouse_capacity_summary/warehouse_capacity_summary.html";
+import "../../stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html";
diff --git a/erpnext/public/js/point-of-sale.bundle.js b/erpnext/public/js/point-of-sale.bundle.js
new file mode 100644
index 0000000000..fbc4bbbbb3
--- /dev/null
+++ b/erpnext/public/js/point-of-sale.bundle.js
@@ -0,0 +1,8 @@
+import "../../selling/page/point_of_sale/pos_item_selector.js";
+import "../../selling/page/point_of_sale/pos_item_cart.js";
+import "../../selling/page/point_of_sale/pos_item_details.js";
+import "../../selling/page/point_of_sale/pos_number_pad.js";
+import "../../selling/page/point_of_sale/pos_payment.js";
+import "../../selling/page/point_of_sale/pos_past_order_list.js";
+import "../../selling/page/point_of_sale/pos_past_order_summary.js";
+import "../../selling/page/point_of_sale/pos_controller.js";
From ff3b71d2e7ad0897ca1a641febf88cba7c212fbb Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Fri, 7 May 2021 14:52:13 +0530
Subject: [PATCH 059/149] fix: Make css bundles
---
erpnext/public/css/email.css | 29 -
erpnext/public/css/erpnext.css | 408 ------------
erpnext/public/css/leaflet/leaflet.css | 611 ------------------
erpnext/public/css/leaflet/leaflet.draw.css | 316 ---------
erpnext/public/less/hub.less | 375 -----------
erpnext/public/less/pos.less | 229 -------
erpnext/public/less/products.less | 71 --
erpnext/public/less/website.less | 388 -----------
.../email.less => scss/email.bundle.scss} | 16 +-
erpnext/public/scss/erpnext-web.bundle.scss | 2 +
erpnext/public/scss/erpnext.bundle.scss | 3 +
.../{less/erpnext.less => scss/erpnext.scss} | 62 +-
12 files changed, 44 insertions(+), 2466 deletions(-)
delete mode 100644 erpnext/public/css/email.css
delete mode 100644 erpnext/public/css/erpnext.css
delete mode 100755 erpnext/public/css/leaflet/leaflet.css
delete mode 100755 erpnext/public/css/leaflet/leaflet.draw.css
delete mode 100644 erpnext/public/less/hub.less
delete mode 100644 erpnext/public/less/pos.less
delete mode 100644 erpnext/public/less/products.less
delete mode 100644 erpnext/public/less/website.less
rename erpnext/public/{less/email.less => scss/email.bundle.scss} (60%)
create mode 100644 erpnext/public/scss/erpnext-web.bundle.scss
create mode 100644 erpnext/public/scss/erpnext.bundle.scss
rename erpnext/public/{less/erpnext.less => scss/erpnext.scss} (82%)
diff --git a/erpnext/public/css/email.css b/erpnext/public/css/email.css
deleted file mode 100644
index 8cf1a31ad6..0000000000
--- a/erpnext/public/css/email.css
+++ /dev/null
@@ -1,29 +0,0 @@
-.panel-header {
- background-color: #fafbfc;
- border: 1px solid #d1d8dd;
- border-radius: 3px 3px 0 0;
-}
-.panel-body {
- background-color: #fff;
- border: 1px solid #d1d8dd;
- border-top: none;
- border-radius: 0 0 3px 3px;
- overflow-wrap: break-word;
-}
-.sender-avatar {
- width: 24px;
- height: 24px;
- border-radius: 3px;
- vertical-align: middle;
-}
-.sender-avatar-placeholder {
- width: 24px;
- height: 24px;
- border-radius: 3px;
- vertical-align: middle;
- line-height: 24px;
- text-align: center;
- color: #d1d8dd;
- border: 1px solid #d1d8dd;
- background-color: #fff;
-}
diff --git a/erpnext/public/css/erpnext.css b/erpnext/public/css/erpnext.css
deleted file mode 100644
index 6e4efcb668..0000000000
--- a/erpnext/public/css/erpnext.css
+++ /dev/null
@@ -1,408 +0,0 @@
-.erpnext-footer {
- margin: 11px auto;
- text-align: center;
-}
-.show-all-reports {
- margin-top: 5px;
- font-size: 11px;
-}
-/* toolbar */
-.toolbar-splash {
- width: 32px;
- height: 32px;
- margin: -10px auto;
-}
-.erpnext-icon {
- width: 24px;
- margin-right: 0px;
- margin-top: -3px;
-}
-.dashboard-list-item {
- background-color: inherit;
- padding: 5px 0px;
- border-bottom: 1px solid #d1d8dd;
-}
-#page-stock-balance .dashboard-list-item {
- padding: 5px 15px;
-}
-.dashboard-list-item:last-child {
- border-bottom: none;
-}
-.frappe-control[data-fieldname='result_html'] {
- overflow: scroll;
-}
-.assessment-result-tool {
- table-layout: fixed;
-}
-.assessment-result-tool input {
- width: 100%;
- border: 0;
- outline: none;
- text-align: right;
-}
-.assessment-result-tool th {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-.assessment-result-tool .total-score,
-.assessment-result-tool .grade,
-.assessment-result-tool .score {
- text-align: right;
-}
-/* pos */
-body[data-route="pos"] .pos-bill-toolbar {
- padding: 10px 0px;
- height: 51px;
-}
-body[data-route="pos"] .pos-bill-item:hover,
-body[data-route="pos"] .list-customers-table > .pos-list-row:hover {
- background-color: #f5f7fa;
- cursor: pointer;
-}
-body[data-route="pos"] .pos-item-qty {
- display: inline-block;
-}
-body[data-route="pos"] .pos-qty-row > div {
- padding: 5px 0px;
-}
-body[data-route="pos"] .pos-qty-btn {
- margin-top: 3px;
- cursor: pointer;
- font-size: 120%;
-}
-body[data-route="pos"] .search-area .form-group {
- max-width: 100% !important;
-}
-body[data-route="pos"] .tax-table {
- margin-bottom: 10px;
-}
-body[data-route="pos"] .discount-field-col {
- padding-left: 24px;
-}
-body[data-route="pos"] .discount-amount-area .input-group:first-child {
- margin-bottom: 2px;
-}
-body[data-route="pos"] .payment-toolbar .row {
- width: 323px;
- margin: 0 auto;
-}
-body[data-route="pos"] .payment-mode {
- cursor: pointer;
- font-family: sans-serif;
- font-size: 15px;
-}
-body[data-route="pos"] .pos-payment-row .col-xs-6 {
- padding: 15px;
-}
-body[data-route="pos"] .pos-payment-row {
- border-bottom: 1px solid #d1d8dd;
- margin: 2px 0px 5px 0px;
- height: 60px;
- margin-top: 0px;
- margin-bottom: 0px;
-}
-body[data-route="pos"] .pos-payment-row:hover,
-body[data-route="pos"] .pos-keyboard-key:hover {
- background-color: #fafbfc;
- cursor: pointer;
-}
-body[data-route="pos"] .pos-keyboard-key,
-body[data-route="pos"] .delete-btn {
- border: 1px solid #d1d8dd;
- height: 85px;
- width: 85px;
- margin: 10px 10px;
- font-size: 24px;
- font-weight: 200;
- background-color: #FDFDFD;
- border-color: #e8e8e8;
-}
-body[data-route="pos"] .numeric-keypad {
- border: 1px solid #d1d8dd;
- height: 69px;
- width: 69px;
- font-size: 20px;
- font-weight: 200;
- background-color: #FDFDFD;
- border-color: #e8e8e8;
- margin-left: -4px;
-}
-body[data-route="pos"] .pos-pay {
- height: 69px;
- width: 69px;
- font-size: 17px;
- font-weight: 200;
- margin-left: -4px;
-}
-body[data-route="pos"] .numeric-keypad {
- height: 60px;
- width: 60px;
- font-size: 20px;
- font-weight: 200;
- border-radius: 0;
- background-color: #fff;
- margin-left: -4px;
-}
-@media (max-width: 1199px) {
- body[data-route="pos"] .numeric-keypad {
- height: 45px;
- width: 45px;
- font-size: 14px;
- }
-}
-@media (max-width: 991px) {
- body[data-route="pos"] .numeric-keypad {
- height: 40px;
- width: 40px;
- }
-}
-body[data-route="pos"] .numeric_keypad {
- margin-left: -15px;
-}
-body[data-route="pos"] .numeric_keypad > .row > button {
- border: none;
- border-right: 1px solid #d1d8dd;
- border-bottom: 1px solid #d1d8dd;
-}
-body[data-route="pos"] .numeric_keypad > .row > button:first-child {
- border-left: 1px solid #d1d8dd;
-}
-body[data-route="pos"] .numeric_keypad > .row:first-child > button {
- border-top: 1px solid #d1d8dd;
-}
-body[data-route="pos"] .pos-pay {
- background-color: #5E64FF;
- border: none;
-}
-body[data-route="pos"] .multimode-payments {
- padding-left: 30px;
-}
-body[data-route="pos"] .payment-toolbar {
- padding-right: 30px;
-}
-body[data-route="pos"] .list-row-head.pos-invoice-list {
- border-top: 1px solid #d1d8dd;
-}
-body[data-route="pos"] .modal-dialog {
- width: 750px;
-}
-@media (max-width: 767px) {
- body[data-route="pos"] .modal-dialog {
- width: auto;
- }
- body[data-route="pos"] .modal-dialog .modal-content {
- height: auto;
- }
-}
-@media (max-width: 767px) {
- body[data-route="pos"] .amount-row h3 {
- font-size: 15px;
- }
- body[data-route="pos"] .pos-keyboard-key,
- body[data-route="pos"] .delete-btn {
- height: 50px;
- }
- body[data-route="pos"] .multimode-payments {
- padding-left: 15px;
- }
- body[data-route="pos"] .payment-toolbar {
- padding-right: 15px;
- }
-}
-body[data-route="pos"] .amount-label {
- font-size: 16px;
-}
-body[data-route="pos"] .selected-payment-mode {
- background-color: #fafbfc;
- cursor: pointer;
-}
-body[data-route="pos"] .pos-invoice-list {
- padding: 15px 10px;
-}
-body[data-route="pos"] .write_off_amount,
-body[data-route="pos"] .change_amount {
- margin: 15px;
- width: 130px;
-}
-body[data-route="pos"] .pos-list-row {
- display: table;
- table-layout: fixed;
- width: 100%;
- padding: 9px 15px;
- font-size: 12px;
- margin: 0px;
- border-bottom: 1px solid #d1d8dd;
-}
-body[data-route="pos"] .pos-list-row .cell {
- display: table-cell;
- vertical-align: middle;
-}
-body[data-route="pos"] .pos-list-row .cell.price-cell {
- width: 50%;
-}
-body[data-route="pos"] .pos-list-row .subject {
- width: 40%;
-}
-body[data-route="pos"] .pos-list-row .list-row-checkbox,
-body[data-route="pos"] .pos-list-row .list-select-all {
- margin-right: 7px;
-}
-body[data-route="pos"] .pos-bill-header {
- background-color: #f5f7fa;
- border: 1px solid #d1d8dd;
- padding: 13px 15px;
-}
-body[data-route="pos"] .pos-list-row.active {
- background-color: #fffce7;
-}
-body[data-route="pos"] .totals-area {
- border-right: 1px solid #d1d8dd;
- border-left: 1px solid #d1d8dd;
- margin-bottom: 15px;
-}
-body[data-route="pos"] .tax-area .pos-list-row {
- border: none;
-}
-body[data-route="pos"] .item-cart-items {
- height: calc(100vh - 526px);
- overflow: auto;
- border: 1px solid #d1d8dd;
- border-top: none;
-}
-@media (max-width: 767px) {
- body[data-route="pos"] .item-cart-items {
- height: 30vh;
- }
-}
-body[data-route="pos"] .no-items-message {
- min-height: 200px;
- display: flex;
- align-items: center;
- justify-content: center;
- height: 100%;
-}
-body[data-route="pos"] .pos-list-row:last-child {
- border-bottom: none;
-}
-body[data-route="pos"] .form-section-heading {
- padding: 0;
-}
-body[data-route="pos"] .item-list {
- border: 1px solid #d1d8dd;
- border-top: none;
- max-height: calc(100vh - 190px);
- overflow: auto;
-}
-@media (max-width: 767px) {
- body[data-route="pos"] .item-list {
- max-height: initial;
- }
-}
-body[data-route="pos"] .item-list .image-field {
- height: 140px;
-}
-body[data-route="pos"] .item-list .image-field .placeholder-text {
- font-size: 50px;
-}
-body[data-route="pos"] .item-list .pos-item-wrapper {
- position: relative;
-}
-body[data-route="pos"] .pos-bill-toolbar {
- margin-top: 10px;
-}
-body[data-route="pos"] .search-item .form-group {
- margin: 0;
-}
-body[data-route="pos"] .item-list-area .pos-bill-header {
- padding: 5px;
- padding-left: 15px;
-}
-body[data-route="pos"] .pos-selected-item-action .pos-list-row:first-child {
- padding-top: 0;
-}
-body[data-route="pos"] .pos-selected-item-action > .pos-list-row {
- border: none;
-}
-@media (max-width: 1199px) {
- body[data-route="pos"] .pos-selected-item-action > .pos-list-row {
- padding: 5px 15px;
- }
-}
-body[data-route="pos"] .edit-customer-btn {
- position: absolute;
- right: 57px;
- top: 15px;
- z-index: 100;
-}
-body[data-route="pos"] .btn-more {
- display: flex;
- justify-content: center;
- align-items: center;
- cursor: pointer;
- background-color: #fafbfc;
- min-height: 200px;
-}
-body[data-route="pos"] .collapse-btn {
- cursor: pointer;
-}
-@media (max-width: 767px) {
- body[data-route="pos"] .page-actions {
- max-width: 110px;
- }
-}
-.price-info {
- position: absolute;
- left: 0;
- bottom: 0;
- margin: 0 0 15px 15px;
- background-color: rgba(141, 153, 166, 0.6);
- padding: 5px 9px;
- border-radius: 3px;
- color: #fff;
-}
-.leaderboard .result {
- border-top: 1px solid #d1d8dd;
-}
-.leaderboard .list-item {
- padding-left: 45px;
-}
-.leaderboard .list-item_content {
- padding-right: 45px;
-}
-.exercise-card {
- box-shadow: 0 1px 3px rgba(0,0,0,0.30);
- border-radius: 2px;
- padding: 6px 6px 6px 8px;
- margin-top: 10px;
- height: 100% !important;
-}
-.exercise-card .card-img-top {
- width: 100%;
- height: 15vw;
- object-fit: cover;
-}
-.exercise-card .btn-edit {
- position: absolute;
- bottom: 10px;
- left: 20px;
-}
-.exercise-card .btn-del {
- position: absolute;
- bottom: 10px;
- left: 50px;
-}
-.exercise-card .card-body {
- margin-bottom: 10px;
-}
-.exercise-card .card-footer {
- padding: 10px;
-}
-.exercise-row {
- height: 100% !important;
- display: flex;
- flex-wrap: wrap;
-}
-.exercise-col {
- padding: 10px;
-}
diff --git a/erpnext/public/css/leaflet/leaflet.css b/erpnext/public/css/leaflet/leaflet.css
deleted file mode 100755
index 979a8bd712..0000000000
--- a/erpnext/public/css/leaflet/leaflet.css
+++ /dev/null
@@ -1,611 +0,0 @@
-/* required styles */
-
-.leaflet-pane,
-.leaflet-tile,
-.leaflet-marker-icon,
-.leaflet-marker-shadow,
-.leaflet-tile-container,
-.leaflet-map-pane svg,
-.leaflet-map-pane canvas,
-.leaflet-zoom-box,
-.leaflet-image-layer,
-.leaflet-layer {
- position: absolute;
- left: 0;
- top: 0;
-}
-
-.leaflet-container {
- overflow: hidden;
- -ms-touch-action: none;
- touch-action: none;
-}
-
-.leaflet-tile,
-.leaflet-marker-icon,
-.leaflet-marker-shadow {
- -webkit-user-select: none;
- -moz-user-select: none;
- user-select: none;
- -webkit-user-drag: none;
-}
-
-
-/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
-
-.leaflet-safari .leaflet-tile {
- image-rendering: -webkit-optimize-contrast;
-}
-
-
-/* hack that prevents hw layers "stretching" when loading new tiles */
-
-.leaflet-safari .leaflet-tile-container {
- width: 1600px;
- height: 1600px;
- -webkit-transform-origin: 0 0;
-}
-
-.leaflet-marker-icon,
-.leaflet-marker-shadow {
- display: block;
-}
-
-
-/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
-
-
-/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
-
-.leaflet-container .leaflet-overlay-pane svg,
-.leaflet-container .leaflet-marker-pane img,
-.leaflet-container .leaflet-tile-pane img,
-.leaflet-container img.leaflet-image-layer {
- max-width: none !important;
-}
-
-.leaflet-tile {
- filter: inherit;
- visibility: hidden;
-}
-
-.leaflet-tile-loaded {
- visibility: inherit;
-}
-
-.leaflet-zoom-box {
- width: 0;
- height: 0;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- z-index: 800;
-}
-
-
-/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
-
-.leaflet-overlay-pane svg {
- -moz-user-select: none;
-}
-
-.leaflet-pane {
- z-index: 400;
-}
-
-.leaflet-tile-pane {
- z-index: 200;
-}
-
-.leaflet-overlay-pane {
- z-index: 400;
-}
-
-.leaflet-shadow-pane {
- z-index: 500;
-}
-
-.leaflet-marker-pane {
- z-index: 600;
-}
-
-.leaflet-popup-pane {
- z-index: 700;
-}
-
-.leaflet-map-pane canvas {
- z-index: 100;
-}
-
-.leaflet-map-pane svg {
- z-index: 200;
-}
-
-.leaflet-vml-shape {
- width: 1px;
- height: 1px;
-}
-
-.lvml {
- behavior: url(#default#VML);
- display: inline-block;
- position: absolute;
-}
-
-
-/* control positioning */
-
-.leaflet-control {
- position: relative;
- z-index: 800;
- pointer-events: auto;
-}
-
-.leaflet-top,
-.leaflet-bottom {
- position: absolute;
- z-index: 1000;
- pointer-events: none;
-}
-
-.leaflet-top {
- top: 0;
-}
-
-.leaflet-right {
- right: 0;
-}
-
-.leaflet-bottom {
- bottom: 0;
-}
-
-.leaflet-left {
- left: 0;
-}
-
-.leaflet-control {
- float: left;
- clear: both;
-}
-
-.leaflet-right .leaflet-control {
- float: right;
-}
-
-.leaflet-top .leaflet-control {
- margin-top: 10px;
-}
-
-.leaflet-bottom .leaflet-control {
- margin-bottom: 10px;
-}
-
-.leaflet-left .leaflet-control {
- margin-left: 10px;
-}
-
-.leaflet-right .leaflet-control {
- margin-right: 10px;
-}
-
-
-/* zoom and fade animations */
-
-.leaflet-fade-anim .leaflet-tile {
- will-change: opacity;
-}
-
-.leaflet-fade-anim .leaflet-popup {
- opacity: 0;
- -webkit-transition: opacity 0.2s linear;
- -moz-transition: opacity 0.2s linear;
- -o-transition: opacity 0.2s linear;
- transition: opacity 0.2s linear;
-}
-
-.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
- opacity: 1;
-}
-
-.leaflet-zoom-animated {
- -webkit-transform-origin: 0 0;
- -ms-transform-origin: 0 0;
- transform-origin: 0 0;
-}
-
-.leaflet-zoom-anim .leaflet-zoom-animated {
- will-change: transform;
-}
-
-.leaflet-zoom-anim .leaflet-zoom-animated {
- -webkit-transition: -webkit-transform 0.25s cubic-bezier(0, 0, 0.25, 1);
- -moz-transition: -moz-transform 0.25s cubic-bezier(0, 0, 0.25, 1);
- -o-transition: -o-transform 0.25s cubic-bezier(0, 0, 0.25, 1);
- transition: transform 0.25s cubic-bezier(0, 0, 0.25, 1);
-}
-
-.leaflet-zoom-anim .leaflet-tile,
-.leaflet-pan-anim .leaflet-tile {
- -webkit-transition: none;
- -moz-transition: none;
- -o-transition: none;
- transition: none;
-}
-
-.leaflet-zoom-anim .leaflet-zoom-hide {
- visibility: hidden;
-}
-
-
-/* cursors */
-
-.leaflet-interactive {
- cursor: pointer;
-}
-
-.leaflet-grab {
- cursor: -webkit-grab;
- cursor: -moz-grab;
-}
-
-.leaflet-crosshair,
-.leaflet-crosshair .leaflet-interactive {
- cursor: crosshair;
-}
-
-.leaflet-popup-pane,
-.leaflet-control {
- cursor: auto;
-}
-
-.leaflet-dragging .leaflet-grab,
-.leaflet-dragging .leaflet-grab .leaflet-interactive,
-.leaflet-dragging .leaflet-marker-draggable {
- cursor: move;
- cursor: -webkit-grabbing;
- cursor: -moz-grabbing;
-}
-
-
-/* visual tweaks */
-
-.leaflet-container {
- background: #ddd;
- outline: 0;
-}
-
-.leaflet-container a {
- color: #0078A8;
-}
-
-.leaflet-container a.leaflet-active {
- outline: 2px solid orange;
-}
-
-.leaflet-zoom-box {
- border: 2px dotted #38f;
- background: rgba(255, 255, 255, 0.5);
-}
-
-
-/* general typography */
-
-.leaflet-container {
- font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
-}
-
-
-/* general toolbar styles */
-
-.leaflet-bar {
- box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);
- border-radius: 4px;
-}
-
-.leaflet-bar a,
-.leaflet-bar a:hover {
- background-color: #fff;
- border-bottom: 1px solid #ccc;
- width: 26px;
- height: 26px;
- line-height: 26px;
- display: block;
- text-align: center;
- text-decoration: none;
- color: black;
-}
-
-.leaflet-bar a,
-.leaflet-control-layers-toggle {
- background-position: 50% 50%;
- background-repeat: no-repeat;
- display: block;
-}
-
-.leaflet-bar a:hover {
- background-color: #f4f4f4;
-}
-
-.leaflet-bar a:first-child {
- border-top-left-radius: 4px;
- border-top-right-radius: 4px;
-}
-
-.leaflet-bar a:last-child {
- border-bottom-left-radius: 4px;
- border-bottom-right-radius: 4px;
- border-bottom: none;
-}
-
-.leaflet-bar a.leaflet-disabled {
- cursor: default;
- background-color: #f4f4f4;
- color: #bbb;
-}
-
-.leaflet-touch .leaflet-bar a {
- width: 30px;
- height: 30px;
- line-height: 30px;
-}
-
-
-/* zoom control */
-
-.leaflet-control-zoom-in,
-.leaflet-control-zoom-out {
- font: bold 18px 'Lucida Console', Monaco, monospace;
- text-indent: 1px;
-}
-
-.leaflet-control-zoom-out {
- font-size: 20px;
-}
-
-.leaflet-touch .leaflet-control-zoom-in {
- font-size: 22px;
-}
-
-.leaflet-touch .leaflet-control-zoom-out {
- font-size: 24px;
-}
-
-
-/* layers control */
-
-.leaflet-control-layers {
- box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4);
- background: #fff;
- border-radius: 5px;
-}
-
-.leaflet-control-layers-toggle {
- background-image: url('assets/erpnext/images/leaflet/layers.png');
- width: 36px;
- height: 36px;
-}
-
-.leaflet-retina .leaflet-control-layers-toggle {
- background-image: url('assets/erpnext/images/leaflet/layers-2x.png');
- background-size: 26px 26px;
-}
-
-.leaflet-touch .leaflet-control-layers-toggle {
- width: 44px;
- height: 44px;
-}
-
-.leaflet-control-layers .leaflet-control-layers-list,
-.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
- display: none;
-}
-
-.leaflet-control-layers-expanded .leaflet-control-layers-list {
- display: block;
- position: relative;
-}
-
-.leaflet-control-layers-expanded {
- padding: 6px 10px 6px 6px;
- color: #333;
- background: #fff;
-}
-
-.leaflet-control-layers-scrollbar {
- overflow-y: scroll;
- padding-right: 5px;
-}
-
-.leaflet-control-layers-selector {
- margin-top: 2px;
- position: relative;
- top: 1px;
-}
-
-.leaflet-control-layers label {
- display: block;
-}
-
-.leaflet-control-layers-separator {
- height: 0;
- border-top: 1px solid #ddd;
- margin: 5px -10px 5px -6px;
-}
-
-
-/* attribution and scale controls */
-
-.leaflet-container .leaflet-control-attribution {
- background: #fff;
- background: rgba(255, 255, 255, 0.7);
- margin: 0;
-}
-
-.leaflet-control-attribution,
-.leaflet-control-scale-line {
- padding: 0 5px;
- color: #333;
-}
-
-.leaflet-control-attribution a {
- text-decoration: none;
-}
-
-.leaflet-control-attribution a:hover {
- text-decoration: underline;
-}
-
-.leaflet-container .leaflet-control-attribution,
-.leaflet-container .leaflet-control-scale {
- font-size: 11px;
-}
-
-.leaflet-left .leaflet-control-scale {
- margin-left: 5px;
-}
-
-.leaflet-bottom .leaflet-control-scale {
- margin-bottom: 5px;
-}
-
-.leaflet-control-scale-line {
- border: 2px solid #777;
- border-top: none;
- line-height: 1.1;
- padding: 2px 5px 1px;
- font-size: 11px;
- white-space: nowrap;
- overflow: hidden;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- background: #fff;
- background: rgba(255, 255, 255, 0.5);
-}
-
-.leaflet-control-scale-line:not(:first-child) {
- border-top: 2px solid #777;
- border-bottom: none;
- margin-top: -2px;
-}
-
-.leaflet-control-scale-line:not(:first-child):not(:last-child) {
- border-bottom: 2px solid #777;
-}
-
-.leaflet-touch .leaflet-control-attribution,
-.leaflet-touch .leaflet-control-layers,
-.leaflet-touch .leaflet-bar {
- box-shadow: none;
-}
-
-.leaflet-touch .leaflet-control-layers,
-.leaflet-touch .leaflet-bar {
- border: 2px solid rgba(0, 0, 0, 0.2);
- background-clip: padding-box;
-}
-
-
-/* popup */
-
-.leaflet-popup {
- position: absolute;
- text-align: center;
-}
-
-.leaflet-popup-content-wrapper {
- padding: 1px;
- text-align: left;
- border-radius: 12px;
-}
-
-.leaflet-popup-content {
- margin: 13px 19px;
- line-height: 1.4;
-}
-
-.leaflet-popup-content p {
- margin: 18px 0;
-}
-
-.leaflet-popup-tip-container {
- margin: 0 auto;
- width: 40px;
- height: 20px;
- position: relative;
- overflow: hidden;
-}
-
-.leaflet-popup-tip {
- width: 17px;
- height: 17px;
- padding: 1px;
- margin: -10px auto 0;
- -webkit-transform: rotate(45deg);
- -moz-transform: rotate(45deg);
- -ms-transform: rotate(45deg);
- -o-transform: rotate(45deg);
- transform: rotate(45deg);
-}
-
-.leaflet-popup-content-wrapper,
-.leaflet-popup-tip {
- background: white;
- color: #333;
- box-shadow: 0 3px 14px rgba(0, 0, 0, 0.4);
-}
-
-.leaflet-container a.leaflet-popup-close-button {
- position: absolute;
- top: 0;
- right: 0;
- padding: 4px 4px 0 0;
- border: none;
- text-align: center;
- width: 18px;
- height: 14px;
- font: 16px/14px Tahoma, Verdana, sans-serif;
- color: #c3c3c3;
- text-decoration: none;
- font-weight: bold;
- background: transparent;
-}
-
-.leaflet-container a.leaflet-popup-close-button:hover {
- color: #999;
-}
-
-.leaflet-popup-scrolled {
- overflow: auto;
- border-bottom: 1px solid #ddd;
- border-top: 1px solid #ddd;
-}
-
-.leaflet-oldie .leaflet-popup-content-wrapper {
- zoom: 1;
-}
-
-.leaflet-oldie .leaflet-popup-tip {
- width: 24px;
- margin: 0 auto;
- -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
- filter: progid: DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
-}
-
-.leaflet-oldie .leaflet-popup-tip-container {
- margin-top: -1px;
-}
-
-.leaflet-oldie .leaflet-control-zoom,
-.leaflet-oldie .leaflet-control-layers,
-.leaflet-oldie .leaflet-popup-content-wrapper,
-.leaflet-oldie .leaflet-popup-tip {
- border: 1px solid #999;
-}
-
-
-/* div icon */
-
-.leaflet-div-icon {
- background: #fff;
- border: 1px solid #666;
-}
\ No newline at end of file
diff --git a/erpnext/public/css/leaflet/leaflet.draw.css b/erpnext/public/css/leaflet/leaflet.draw.css
deleted file mode 100755
index 6fb7db0e64..0000000000
--- a/erpnext/public/css/leaflet/leaflet.draw.css
+++ /dev/null
@@ -1,316 +0,0 @@
-/* ================================================================== */
-
-
-/* Toolbars
-/* ================================================================== */
-
-.leaflet-draw-section {
- position: relative;
-}
-
-.leaflet-draw-toolbar {
- margin-top: 12px;
-}
-
-.leaflet-draw-toolbar-top {
- margin-top: 0;
-}
-
-.leaflet-draw-toolbar-notop a:first-child {
- border-top-right-radius: 0;
-}
-
-.leaflet-draw-toolbar-nobottom a:last-child {
- border-bottom-right-radius: 0;
-}
-
-.leaflet-draw-toolbar a {
- background-image: url('assets/erpnext/images/leaflet/spritesheet.png');
- background-repeat: no-repeat;
-}
-
-.leaflet-retina .leaflet-draw-toolbar a {
- background-image: url('assets/erpnext/images/leaflet/spritesheet-2x.png');
- background-size: 270px 30px;
-}
-
-.leaflet-draw a {
- display: block;
- text-align: center;
- text-decoration: none;
-}
-
-
-/* ================================================================== */
-
-
-/* Toolbar actions menu
-/* ================================================================== */
-
-.leaflet-draw-actions {
- display: none;
- list-style: none;
- margin: 0;
- padding: 0;
- position: absolute;
- left: 26px;
- /* leaflet-draw-toolbar.left + leaflet-draw-toolbar.width */
- top: 0;
- white-space: nowrap;
-}
-
-.leaflet-right .leaflet-draw-actions {
- right: 26px;
- left: auto;
-}
-
-.leaflet-draw-actions li {
- display: inline-block;
-}
-
-.leaflet-draw-actions li:first-child a {
- border-left: none;
-}
-
-.leaflet-draw-actions li:last-child a {
- -webkit-border-radius: 0 4px 4px 0;
- border-radius: 0 4px 4px 0;
-}
-
-.leaflet-right .leaflet-draw-actions li:last-child a {
- -webkit-border-radius: 0;
- border-radius: 0;
-}
-
-.leaflet-right .leaflet-draw-actions li:first-child a {
- -webkit-border-radius: 4px 0 0 4px;
- border-radius: 4px 0 0 4px;
-}
-
-.leaflet-draw-actions a {
- background-color: #919187;
- border-left: 1px solid #AAA;
- color: #FFF;
- font: 11px/19px "Helvetica Neue", Arial, Helvetica, sans-serif;
- line-height: 28px;
- text-decoration: none;
- padding-left: 10px;
- padding-right: 10px;
- height: 28px;
-}
-
-.leaflet-draw-actions-bottom {
- margin-top: 0;
-}
-
-.leaflet-draw-actions-top {
- margin-top: 1px;
-}
-
-.leaflet-draw-actions-top a,
-.leaflet-draw-actions-bottom a {
- height: 27px;
- line-height: 27px;
-}
-
-.leaflet-draw-actions a:hover {
- background-color: #A0A098;
-}
-
-.leaflet-draw-actions-top.leaflet-draw-actions-bottom a {
- height: 26px;
- line-height: 26px;
-}
-
-
-/* ================================================================== */
-
-
-/* Draw toolbar
-/* ================================================================== */
-
-.leaflet-draw-toolbar .leaflet-draw-draw-polyline {
- background-position: -2px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-draw-polygon {
- background-position: -31px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-draw-rectangle {
- background-position: -62px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-draw-circle {
- background-position: -92px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-draw-marker {
- background-position: -122px -2px;
-}
-
-
-/* ================================================================== */
-
-
-/* Edit toolbar
-/* ================================================================== */
-
-.leaflet-draw-toolbar .leaflet-draw-edit-edit {
- background-position: -152px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-edit-remove {
- background-position: -182px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled {
- background-position: -212px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled {
- background-position: -242px -2px;
-}
-
-
-/* ================================================================== */
-
-
-/* Drawing styles
-/* ================================================================== */
-
-.leaflet-mouse-marker {
- background-color: #fff;
- cursor: crosshair;
-}
-
-.leaflet-draw-tooltip {
- background: rgb(54, 54, 54);
- background: rgba(0, 0, 0, 0.5);
- border: 1px solid transparent;
- -webkit-border-radius: 4px;
- border-radius: 4px;
- color: #fff;
- font: 12px/18px "Helvetica Neue", Arial, Helvetica, sans-serif;
- margin-left: 20px;
- margin-top: -21px;
- padding: 4px 8px;
- position: absolute;
- visibility: hidden;
- white-space: nowrap;
- z-index: 6;
-}
-
-.leaflet-draw-tooltip:before {
- border-right: 6px solid black;
- border-right-color: rgba(0, 0, 0, 0.5);
- border-top: 6px solid transparent;
- border-bottom: 6px solid transparent;
- content: "";
- position: absolute;
- top: 7px;
- left: -7px;
-}
-
-.leaflet-error-draw-tooltip {
- background-color: #F2DEDE;
- border: 1px solid #E6B6BD;
- color: #B94A48;
-}
-
-.leaflet-error-draw-tooltip:before {
- border-right-color: #E6B6BD;
-}
-
-.leaflet-draw-tooltip-single {
- margin-top: -12px
-}
-
-.leaflet-draw-tooltip-subtext {
- color: #f8d5e4;
-}
-
-.leaflet-draw-guide-dash {
- font-size: 1%;
- opacity: 0.6;
- position: absolute;
- width: 5px;
- height: 5px;
-}
-
-
-/* ================================================================== */
-
-
-/* Edit styles
-/* ================================================================== */
-
-.leaflet-edit-marker-selected {
- background: rgba(254, 87, 161, 0.1);
- border: 4px dashed rgba(254, 87, 161, 0.6);
- -webkit-border-radius: 4px;
- border-radius: 4px;
-}
-
-.leaflet-edit-move {
- cursor: move;
-}
-
-.leaflet-edit-resize {
- cursor: pointer;
-}
-
-
-/* ================================================================== */
-
-
-/* Old IE styles
-/* ================================================================== */
-
-.leaflet-oldie .leaflet-draw-toolbar {
- border: 3px solid #999;
-}
-
-.leaflet-oldie .leaflet-draw-toolbar a {
- background-color: #eee;
-}
-
-.leaflet-oldie .leaflet-draw-toolbar a:hover {
- background-color: #fff;
-}
-
-.leaflet-oldie .leaflet-draw-actions {
- left: 32px;
- margin-top: 3px;
-}
-
-.leaflet-oldie .leaflet-draw-actions li {
- display: inline;
- zoom: 1;
-}
-
-.leaflet-oldie .leaflet-edit-marker-selected {
- border: 4px dashed #fe93c2;
-}
-
-.leaflet-oldie .leaflet-draw-actions a {
- background-color: #999;
-}
-
-.leaflet-oldie .leaflet-draw-actions a:hover {
- background-color: #a5a5a5;
-}
-
-.leaflet-oldie .leaflet-draw-actions-top a {
- margin-top: 1px;
-}
-
-.leaflet-oldie .leaflet-draw-actions-bottom a {
- height: 28px;
- line-height: 28px;
-}
-
-.leaflet-oldie .leaflet-draw-actions-top.leaflet-draw-actions-bottom a {
- height: 27px;
- line-height: 27px;
-}
\ No newline at end of file
diff --git a/erpnext/public/less/hub.less b/erpnext/public/less/hub.less
deleted file mode 100644
index 29deada8a4..0000000000
--- a/erpnext/public/less/hub.less
+++ /dev/null
@@ -1,375 +0,0 @@
-@import "variables.less";
-@import (reference) "desk.less";
-
-body[data-route*="marketplace"] {
- .layout-side-section {
- padding-top: 25px;
- padding-left: 5px;
- padding-right: 25px;
- }
-
- [data-route], [data-action] {
- cursor: pointer;
- }
-
- .layout-main-section {
- border: none;
- font-size: @text-medium;
- padding-top: 25px;
-
- @media (max-width: @screen-xs) {
- padding-left: 20px;
- padding-right: 20px;
- }
- }
-
- input, textarea {
- font-size: @text-medium;
- }
-
- .hub-image {
- height: 200px;
- }
-
- .hub-image-loading, .hub-image-broken {
- content: " ";
- position: absolute;
- left: 0;
- height: 100%;
- width: 100%;
- background-color: var(--bg-light-gray);
- display: flex;
- align-items: center;
- justify-content: center;
-
- span {
- font-size: 32px;
- color: @text-extra-muted;
- }
- }
-
- .progress-bar {
- background-color: #89da28;
- }
-
- .subpage-title.flex {
- align-items: flex-start;
- justify-content: space-between;
- }
-
- .hub-card {
- margin-bottom: 25px;
- position: relative;
- border: 1px solid @border-color;
- border-radius: 4px;
- overflow: hidden;
-
- &:hover .hub-card-overlay {
- display: block;
- }
- }
-
- .hub-card.is-local {
- &.active {
- .hub-card-header {
- background-color: #f4ffe5;
- }
-
- .octicon-check {
- display: inline;
- }
- }
-
- .octicon-check {
- display: none;
- position: absolute;
- font-size: 20px;
- right: 15px;
- top: 50%;
- transform: translateY(-50%);
- }
- }
-
- .hub-card-header {
- position: relative;
- padding: 12px 15px;
- height: 60px;
- border-bottom: 1px solid @border-color;
- }
-
- .hub-card-body {
- position: relative;
- height: 200px;
- }
-
- .hub-card-overlay {
- display: none;
- position: absolute;
- top: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.05);
- }
-
- .hub-card-overlay-body {
- position: relative;
- height: 100%;
- }
-
- .hub-card-overlay-button {
- position: absolute;
- right: 15px;
- bottom: 15px;
- }
-
- .hub-card-image {
- position: relative;
- width: 100%;
- height: 100%;
- object-fit: contain;
- }
-
- .hub-search-container {
- margin-bottom: 20px;
-
- input {
- height: 32px;
- }
- }
-
- .hub-sidebar {
- padding-top: 25px;
- padding-right: 15px;
- }
-
- .hub-sidebar-group {
- margin-bottom: 10px;
- }
-
- .hub-sidebar-item {
- padding: 5px 8px;
- margin-bottom: 3px;
- border-radius: 4px;
- border: 1px solid transparent;
-
- &.active, &:hover:not(.is-title) {
- border-color: @border-color;
- }
- }
-
- .hub-item-image {
- position: relative;
- border: 1px solid @border-color;
- border-radius: 4px;
- overflow: hidden;
- height: 200px;
- width: 200px;
- display: flex;
- align-items: center;
- }
-
- .hub-item-skeleton-image {
- border-radius: 4px;
- background-color: @light-bg;
- overflow: hidden;
- height: 200px;
- width: 200px;
- }
-
- .hub-skeleton {
- background-color: @light-bg;
- color: @light-bg;
- max-width: 500px;
- }
-
- .hub-item-seller img {
- width: 50px;
- height: 50px;
- border-radius: 4px;
- border: 1px solid @border-color;
- }
-
- .register-title {
- font-size: @text-regular;
- }
-
- .register-form {
- border: 1px solid @border-color;
- border-radius: 4px;
- padding: 15px 25px;
- }
-
- .publish-area.filled {
- .empty-items-container {
- display: none;
- }
- }
-
- .publish-area.empty {
- .hub-items-container {
- display: none;
- }
- }
-
- .publish-area-head {
- display: flex;
- justify-content: space-between;
- margin-bottom: 20px;
- }
-
- .hub-list-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- border: 1px solid @border-color;
- margin-bottom: -1px;
- overflow: hidden;
- }
-
- .hub-list-item:first-child {
- border-top-left-radius: 4px;
- border-top-right-radius: 4px;
- }
- .hub-list-item:last-child {
- border-bottom-left-radius: 4px;
- border-bottom-right-radius: 4px;
- }
-
- .hub-list-left {
- display: flex;
- align-items: center;
- max-width: 90%;
- }
-
- .hub-list-right {
- padding-right: 15px;
- }
-
- .hub-list-image {
- position: relative;
- width: 58px;
- height: 58px;
- border-right: 1px solid @border-color;
-
- &::after {
- font-size: 12px;
- }
- }
-
- .hub-list-body {
- padding: 12px 15px;
- }
-
- .hub-list-title {
- font-weight: bold;
- }
-
- .hub-list-subtitle {
- color: @text-muted;
- }
-
- .selling-item-message-card {
- max-width: 500px;
- margin-bottom: 15px;
- border-radius: 3px;
- border: 1px solid @border-color;
- .selling-item-detail {
- overflow: auto;
- .item-image {
- float: left;
- height: 80px;
- width: 80px;
- object-fit: contain;
- margin: 5px;
- }
- .item-name {
- margin-left: 10px;
- }
- }
- .received-message-container {
- clear: left;
- background-color: @light-bg;
- .received-message {
- border-top: 1px solid @border-color;
- padding: 10px;
- }
- .frappe-timestamp {
- float: right;
- }
- }
- }
-
- .form-container {
- .frappe-control {
- max-width: 100% !important;
- }
- }
-
- .form-message {
- padding-top: 0;
- padding-bottom: 0;
- border-bottom: none;
- }
-
- .hub-items-container {
- .hub-items-header {
- justify-content: space-between;
- align-items: baseline;
- }
- }
-
- .hub-item-container {
- overflow: hidden;
- }
-
- .hub-item-review-container {
- margin-top: calc(30vh);
- }
-
- .hub-item-dropdown {
- margin-top: 20px;
- }
-
- /* messages page */
-
- .message-list-item {
- display: flex;
- align-items: center;
- padding: 8px 12px;
-
- &:not(.active) {
- filter: grayscale(1);
- color: @text-muted;
- }
-
- &:hover {
- background-color: @light-bg;
- }
-
- .list-item-left {
- width: 30px;
- border-radius: 4px;
- overflow: hidden;
- margin-right: 15px;
- }
-
- .list-item-body {
- font-weight: bold;
- padding-bottom: 1px;
- }
- }
-
- .message-container {
- display: flex;
- flex-direction: column;
- border: 1px solid @border-color;
- border-radius: 3px;
- height: calc(100vh - 300px);
- justify-content: space-between;
- padding: 15px;
- }
-
- .message-list {
- overflow: scroll;
- }
-}
diff --git a/erpnext/public/less/pos.less b/erpnext/public/less/pos.less
deleted file mode 100644
index b081ed4414..0000000000
--- a/erpnext/public/less/pos.less
+++ /dev/null
@@ -1,229 +0,0 @@
-@import "../../../../frappe/frappe/public/less/variables.less";
-
-[data-route="point-of-sale"] {
- .layout-main-section-wrapper {
- margin-bottom: 0;
- }
-
- .pos-items-wrapper {
- max-height: ~"calc(100vh - 210px)";
- }
-}
-
-.pos {
- // display: flex;
- padding: 15px;
-}
-
-.list-item {
- min-height: 40px;
- height: auto;
-}
-
-.cart-container {
- padding: 0 15px;
- // flex: 2;
- display: inline-block;
- width: 39%;
- vertical-align: top;
-}
-
-.item-container {
- padding: 0 15px;
- // flex: 3;
- display: inline-block;
- width: 60%;
- vertical-align: top;
-}
-
-.search-field {
- width: 60%;
-
- input::placeholder {
- font-size: @text-medium;
- }
-}
-
-.item-group-field {
- width: 40%;
- margin-left: 15px;
-}
-
-.cart-wrapper {
- margin-bottom: 12px;
- .list-item__content:not(:first-child) {
- justify-content: flex-end;
- }
-
- .list-item--head .list-item__content:nth-child(2) {
- flex: 1.5;
- }
-}
-
-.cart-items {
- height: 150px;
- overflow: auto;
-
- .list-item.current-item {
- background-color: @light-yellow;
- }
-
- .list-item.current-item.qty input {
- border: 1px solid @brand-primary;
- font-weight: bold;
- }
-
- .list-item.current-item.disc .discount {
- font-weight: bold;
- }
-
- .list-item.current-item.rate .rate {
- font-weight: bold;
- }
-
- .list-item .quantity {
- flex: 1.5;
- }
-
- input {
- text-align: right;
- height: 22px;
- font-size: @text-medium;
- }
-}
-
-.fields {
- display: flex;
-}
-
-.pos-items-wrapper {
- max-height: 480px;
- overflow-y: auto;
-}
-
-.pos-items {
- overflow: hidden;
-}
-
-.pos-item-wrapper {
- display: flex;
- flex-direction: column;
- position: relative;
- width: 25%;
-}
-
-.image-view-container {
- display: block;
-}
-
-.image-view-container .image-field {
- height: auto;
-}
-
-.empty-state {
- height: 100%;
- position: relative;
-
- span {
- position: absolute;
- color: @text-muted;
- font-size: @text-medium;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- }
-}
-
-@keyframes yellow-fade {
- 0% {background-color: @light-yellow;}
- 100% {background-color: transparent;}
-}
-
-.highlight {
- animation: yellow-fade 1s ease-in 1;
-}
-
-input[type=number]::-webkit-inner-spin-button,
-input[type=number]::-webkit-outer-spin-button {
- -webkit-appearance: none;
- margin: 0;
-}
-
-// number pad
-
-.number-pad {
- border-collapse: collapse;
- cursor: pointer;
- display: table;
-}
-.num-row {
- display: table-row;
-}
-.num-col {
- display: table-cell;
- border: 1px solid @border-color;
-
- & > div {
- width: 50px;
- height: 50px;
- text-align: center;
- line-height: 50px;
- }
-
- &.active {
- background-color: @light-yellow;
- }
-
- &.brand-primary {
- background-color: @brand-primary;
- color: #ffffff;
- }
-}
-
-// taxes, totals and discount area
-.discount-amount {
- .discount-inputs {
- display: flex;
- flex-direction: column;
- padding: 15px 0;
- }
-
- input:first-child {
- margin-bottom: 10px;
- }
-}
-
-.taxes-and-totals {
- border-top: 1px solid @border-color;
-
- .taxes {
- display: flex;
- flex-direction: column;
- padding: 15px 0;
- align-items: flex-end;
-
- & > div:first-child {
- margin-bottom: 10px;
- }
- }
-}
-
-.grand-total {
- border-top: 1px solid @border-color;
-
- .list-item {
- height: 60px;
- }
-
- .grand-total-value {
- font-size: 18px;
- }
-}
-
-.rounded-total-value {
- font-size: 18px;
-}
-
-.quantity-total {
- font-size: 18px;
-}
\ No newline at end of file
diff --git a/erpnext/public/less/products.less b/erpnext/public/less/products.less
deleted file mode 100644
index 5e744ceac5..0000000000
--- a/erpnext/public/less/products.less
+++ /dev/null
@@ -1,71 +0,0 @@
-@import "variables.less";
-
-.products-list .product-image {
- display: inline-block;
- width: 160px;
- height: 160px;
- object-fit: contain;
- margin-right: 1rem;
-}
-
-.product-image.no-image {
- display: flex;
- justify-content: center;
- align-items: center;
- font-size: 3rem;
- color: var(--gray);
- background: var(--light);
-}
-
-.product-image a {
- text-decoration: none;
-}
-
-.filter-options {
- margin-left: -5px;
- padding-left: 5px;
- max-height: 300px;
- overflow: auto;
-}
-
-.item-slideshow-image {
- height: 3rem;
- width: 3rem;
- object-fit: contain;
- padding: 0.5rem;
- border: 1px solid @border-color;
- border-radius: 4px;
- cursor: pointer;
-
- &:hover, &.active {
- border-color: var(--primary);
- }
-}
-
-.address-card {
- cursor: pointer;
- position: relative;
-
- .check {
- display: none;
- }
-
- &.active {
- border-color: var(--primary);
-
- .check {
- display: inline-flex;
- }
- }
-}
-
-.check {
- display: inline-flex;
- padding: 0.25rem;
- background: var(--primary);
- color: white;
- border-radius: 50%;
- font-size: 12px;
- width: 24px;
- height: 24px;
-}
\ No newline at end of file
diff --git a/erpnext/public/less/website.less b/erpnext/public/less/website.less
deleted file mode 100644
index ac878de105..0000000000
--- a/erpnext/public/less/website.less
+++ /dev/null
@@ -1,388 +0,0 @@
-@import "variables.less";
-
-.web-long-description {
- font-size: 18px;
- line-height: 200%;
-}
-
-.web-page-content {
- margin-bottom: 30px;
-}
-
-.item-stock {
- margin-bottom: 10px !important;
-}
-
-.product-link {
- display: block;
- text-align: center;
-}
-
-
-.product-image img {
- max-height: 500px;
- margin: 0 auto;
-}
-
-@media (max-width: 767px) {
- .product-image {
- height: 0px;
- padding: 0px 0px 100%;
- overflow: hidden;
- }
-}
-
-.product-image-square {
- width: 100%;
- height: 0;
- padding: 50% 0px;
- background-size: cover;
- background-repeat: no-repeat;
- background-position: center top;
-}
-
-.product-image.missing-image {
- .product-image-square;
- position: relative;
- background-color: @light-border-color;
-}
-
-.product-image.missing-image .octicon {
- font-size: 32px;
- color: @border-color;
-}
-
-.product-search {
- margin-bottom: 15px;
-}
-
-
-@media (max-width: 767px) {
- .product-search {
- width: 100%;
- }
-}
-
-.borderless td, .borderless th {
- border-bottom: 1px solid @light-border-color;
- padding-left:0px !important;
- line-height: 1.8em !important;
-}
-
-.item-desc {
- border-top: 2px solid @light-border-color;
- padding-top:10px;
-}
-
-.featured-products {
- border-top: 1px solid @light-border-color;
-}
-
-.transaction-list-item {
- .indicator {
- font-weight: inherit;
- color: @text-muted;
- }
-
- .transaction-time {
- margin-top: 5px;
- }
-
-}
-
-// order.html
-.transaction-subheading {
- .indicator {
- font-weight: inherit;
- color: @text-muted;
- }
-}
-
-.order-container {
- margin: 50px 0px;
-
- .order-item-header .h6 {
- padding: 7px 15px;
- }
-
- .order-items {
- margin: 30px 0px 0px;
- }
-
- .order-item-table {
- margin: 0px -15px;
- }
-
- .order-item-header {
- border-bottom: 1px solid #d1d8dd;
- }
-
- .order-image-col {
- padding-right: 0px;
- }
-
- .order-image {
- max-width: 55px;
- max-height: 55px;
- margin-top: -5px;
- }
-
- .order-taxes {
- margin-top: 30px;
-
- .row {
- margin-top: 15px;
- }
- }
-
- .tax-grand-total-row {
- padding-top: 15px;
- padding-bottom: 30px;
- }
-
- .tax-grand-total {
- display: inline-block;
- font-size: 16px;
- font-weight: bold;
- margin-top: 5px;
- }
-}
-
-.cart-container {
- margin: 50px 0px;
-
- .checkout {
- margin-bottom:15px;
- }
-
- .cart-item-header .h6 {
- padding: 7px 15px;
- }
-
- .cart-items {
- margin: 30px 0px 0px;
- }
-
- .cart-item-table {
- margin: 0px -15px;
- }
-
- .cart-item-header {
- border-bottom: 1px solid #d1d8dd;
- }
-
- .cart-image-col {
- padding-right: 0px;
- }
-
- .cart-image {
- max-width: 55px;
- max-height: 55px;
- margin-top: -5px;
- }
-
- .cart-taxes {
- margin-top: 30px;
-
- .row {
- margin-top: 15px;
- }
- }
-
- .tax-grand-total-row {
- border-top: 1px solid @border-color;
- padding-top: 15px;
- }
-
- .cart-addresses {
- margin-top: 50px;
- }
-}
-
-.cart-items-dropdown .cart-dropdown,
-.item_name_dropdown {
- display: none;
-
-}
-
-.cart-dropdown-container {
- width: 400px;
- padding: 15px;
-
- .item-price {
- display: block !important;
- padding-bottom: 10px;
- }
-
- .cart-item-header {
- border-bottom: 1px solid #d1d8dd;
- }
-
- .cart-items-dropdown {
- max-height: 350px;
- }
-
- .cart-items-dropdown .cart-dropdown {
- display:block;
- margin-top:15px;
- }
-
- .item_name_dropdown {
- display:block;
- }
-
- .item-description,
- .cart-items .checkout,
- .item_name_and_description {
- display: none;
- }
-
- .checkout-btn {
- padding-bottom:25px;
- }
- .col-name-description {
- margin-bottom:8px;
- }
-}
-
-// .number-spinner {
-// width:100px;
-// margin-top:5px;
-// }
-
-.cart-btn {
- border-color: #ccc;
-}
-.cart-qty {
- text-align:center;
-}
-
-.product-list-link {
- .row {
- border-bottom: 1px solid @light-border-color;
- }
-
- .row:hover {
- background-color: @light-bg;
- }
-
- .row > div {
- padding-top: 15px;
- padding-bottom: 15px;
- }
-}
-
-.product-list-link:first-child .row {
- border-top: 1px solid @light-border-color;
-}
-
-.item-group-nav-buttons {
- margin-top: 15px;
-}
-
-.footer-subscribe {
- .btn-default {
- background-color: transparent;
- border: 1px solid @border-color;
- }
-}
-
-@media (min-width: 992px) {
- .footer-subscribe {
- max-width: 350px;
- }
-}
-
-.item-group-content {
- margin-top: 30px;
-}
-
-.item-group-slideshow {
- margin-bottom: 1rem;
-}
-
-.product-image-img {
- border: 1px solid @light-border-color;
- border-radius: 3px;
-}
-
-.product-text {
- word-wrap: break-word;
- height: 75px;
- display: block; /* Fallback for non-webkit */
- display: -webkit-box;
- max-width: 100%;
- margin: 0 auto;
- -webkit-line-clamp: 3;
- -webkit-box-orient: vertical;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.product-image-wrapper {
- padding-bottom: 40px;
-}
-
-.duration-bar {
- display: inline-block;
- color: white;
- background: #8FD288;
- padding: 3px;
-}
-
-.duration-invisible {
- visibility: hidden;
-}
-
-.duration-value {
- float: right;
-}
-
-.bar-outer-text {
- color: #8FD288;
- background: none;
- float: none;
- border: none;
-}
-
-.bom-spec {
- margin-bottom: 20px;
-}
-
-.modal-title {
- margin-top: 5px;
-}
-
-.modal-header {
- padding: 10px 15px;
-}
-// For Item Alternate Image
-.item-alternative-image {
- padding: 5px;
- margin-bottom: 5px;
-
- &:hover {
- border-color: @brand-primary;
- }
-}
-
-.item-slideshow-image {
- height: 3rem;
- width: 3rem;
- object-fit: contain;
- padding: 0.5rem;
- border: 1px solid @border-color;
- border-radius: 4px;
- cursor: pointer;
-
- &:hover, &.active {
- border-color: @brand-primary;
- }
-}
-
-.section-products {
- .card-img-top {
- max-height: 300px;
- object-fit: contain;
- }
-}
\ No newline at end of file
diff --git a/erpnext/public/less/email.less b/erpnext/public/scss/email.bundle.scss
similarity index 60%
rename from erpnext/public/less/email.less
rename to erpnext/public/scss/email.bundle.scss
index 4077c4940d..3c0b918dae 100644
--- a/erpnext/public/less/email.less
+++ b/erpnext/public/scss/email.bundle.scss
@@ -1,14 +1,14 @@
-@import "../../../../frappe/frappe/public/less/variables.less";
+@import "frappe/public/scss/desk/variables";
.panel-header {
- background-color: @light-bg;
- border: 1px solid @border-color;
+ background-color: var(--bg-color);
+ border: 1px solid $border-color;
border-radius: 3px 3px 0 0;
}
.panel-body {
background-color: #fff;
- border: 1px solid @border-color;
+ border: 1px solid $border-color;
border-top: none;
border-radius: 0 0 3px 3px;
overflow-wrap: break-word;
@@ -22,11 +22,11 @@
}
.sender-avatar-placeholder {
- .sender-avatar;
+ @extend .sender-avatar;
line-height: 24px;
text-align: center;
- color: @border-color;
- border: 1px solid @border-color;
+ color: $border-color;
+ border: 1px solid $border-color;
background-color: #fff;
-}
\ No newline at end of file
+}
diff --git a/erpnext/public/scss/erpnext-web.bundle.scss b/erpnext/public/scss/erpnext-web.bundle.scss
new file mode 100644
index 0000000000..6ef1892a3d
--- /dev/null
+++ b/erpnext/public/scss/erpnext-web.bundle.scss
@@ -0,0 +1,2 @@
+@import "./shopping_cart";
+@import "./website";
diff --git a/erpnext/public/scss/erpnext.bundle.scss b/erpnext/public/scss/erpnext.bundle.scss
new file mode 100644
index 0000000000..d3313c7cee
--- /dev/null
+++ b/erpnext/public/scss/erpnext.bundle.scss
@@ -0,0 +1,3 @@
+@import "./erpnext";
+@import "./call_popup";
+@import "./point-of-sale";
diff --git a/erpnext/public/less/erpnext.less b/erpnext/public/scss/erpnext.scss
similarity index 82%
rename from erpnext/public/less/erpnext.less
rename to erpnext/public/scss/erpnext.scss
index 4076ebec1f..0e6186138f 100644
--- a/erpnext/public/less/erpnext.less
+++ b/erpnext/public/scss/erpnext.scss
@@ -1,4 +1,4 @@
-@import "variables.less";
+@import "frappe/public/scss/desk/variables";
.erpnext-footer {
margin: 11px auto;
@@ -141,7 +141,7 @@ body[data-route="pos"] {
}
.pos-payment-row {
- border-bottom:1px solid @border-color;
+ border-bottom:1px solid $border-color;
margin: 2px 0px 5px 0px;
height: 60px;
margin-top: 0px;
@@ -149,12 +149,12 @@ body[data-route="pos"] {
}
.pos-payment-row:hover, .pos-keyboard-key:hover{
- background-color: @light-bg;
+ background-color: var(--bg-color);
cursor: pointer;
}
.pos-keyboard-key, .delete-btn {
- border: 1px solid @border-color;
+ border: 1px solid $border-color;
height:85px;
width:85px;
margin:10px 10px;
@@ -165,7 +165,7 @@ body[data-route="pos"] {
}
.numeric-keypad {
- border: 1px solid @border-color;
+ border: 1px solid $border-color;
height:69px;
width:69px;
font-size:20px;
@@ -192,13 +192,13 @@ body[data-route="pos"] {
background-color: #fff;
margin-left:-4px;
- @media (max-width: @screen-md) {
+ @media (max-width: map-get($grid-breakpoints, "xl")) {
height: 45px;
width: 45px;
font-size: 14px;
}
- @media (max-width: @screen-sm) {
+ @media (max-width: map-get($grid-breakpoints, "lg")) {
height: 40px;
width: 40px;
}
@@ -209,21 +209,21 @@ body[data-route="pos"] {
& > .row > button {
border: none;
- border-right: 1px solid @border-color;
- border-bottom: 1px solid @border-color;
+ border-right: 1px solid $border-color;
+ border-bottom: 1px solid $border-color;
&:first-child {
- border-left: 1px solid @border-color;
+ border-left: 1px solid $border-color;
}
}
& > .row:first-child > button {
- border-top: 1px solid @border-color;
+ border-top: 1px solid $border-color;
}
}
.pos-pay {
- background-color: @brand-primary;
+ background-color: var(--primary);
border: none;
}
@@ -236,13 +236,13 @@ body[data-route="pos"] {
}
.list-row-head.pos-invoice-list {
- border-top: 1px solid @border-color;
+ border-top: 1px solid $border-color;
}
.modal-dialog {
width: 750px;
- @media (max-width: @screen-xs) {
+ @media (max-width: map-get($grid-breakpoints, 'md')) {
width: auto;
.modal-content {
@@ -251,7 +251,7 @@ body[data-route="pos"] {
}
}
- @media (max-width: @screen-xs) {
+ @media (max-width: map-get($grid-breakpoints, 'md')) {
.amount-row h3 {
font-size: 15px;
}
@@ -271,7 +271,7 @@ body[data-route="pos"] {
}
.selected-payment-mode {
- background-color: @light-bg;
+ background-color: var(--bg-color);
cursor: pointer;
}
@@ -291,7 +291,7 @@ body[data-route="pos"] {
padding: 9px 15px;
font-size: 12px;
margin: 0px;
- border-bottom: 1px solid @border-color;
+ border-bottom: 1px solid $border-color;
.cell {
display: table-cell;
@@ -313,17 +313,17 @@ body[data-route="pos"] {
.pos-bill-header {
background-color: #f5f7fa;
- border: 1px solid @border-color;
+ border: 1px solid $border-color;
padding: 13px 15px;
}
.pos-list-row.active {
- background-color: @light-yellow;
+ background-color: var(--fg-hover-color);
}
.totals-area {
- border-right: 1px solid @border-color;
- border-left: 1px solid @border-color;
+ border-right: 1px solid $border-color;
+ border-left: 1px solid $border-color;
margin-bottom: 15px;
}
@@ -332,12 +332,12 @@ body[data-route="pos"] {
}
.item-cart-items {
- height: ~"calc(100vh - 526px)";
+ height: calc(100vh - 526px);
overflow: auto;
- border: 1px solid @border-color;
+ border: 1px solid $border-color;
border-top: none;
- @media (max-width: @screen-xs) {
+ @media (max-width: map-get($grid-breakpoints, 'md')) {
height: 30vh;
}
}
@@ -359,12 +359,12 @@ body[data-route="pos"] {
}
.item-list {
- border: 1px solid @border-color;
+ border: 1px solid $border-color;
border-top: none;
- max-height: ~"calc(100vh - 190px)";
+ max-height: calc(100vh - 190px);
overflow: auto;
- @media (max-width: @screen-xs) {
+ @media (max-width: map-get($grid-breakpoints, 'md')) {
max-height: initial;
}
@@ -402,7 +402,7 @@ body[data-route="pos"] {
&> .pos-list-row {
border: none;
- @media (max-width: @screen-md) {
+ @media (max-width: map-get($grid-breakpoints, 'xl')) {
padding: 5px 15px;
}
}
@@ -420,7 +420,7 @@ body[data-route="pos"] {
justify-content: center;
align-items: center;
cursor: pointer;
- background-color: @light-bg;
+ background-color: var(--bg-color);
min-height: 200px;
}
@@ -428,7 +428,7 @@ body[data-route="pos"] {
cursor: pointer;
}
- @media (max-width: @screen-xs) {
+ @media (max-width: map-get($grid-breakpoints, 'md')) {
.page-actions {
max-width: 110px;
}
@@ -491,4 +491,4 @@ body[data-route="pos"] {
.exercise-col {
padding: 10px;
-}
\ No newline at end of file
+}
From 464d838447fe4876df25d2ee328fa6d655ce4d6b Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Fri, 7 May 2021 14:53:42 +0530
Subject: [PATCH 060/149] fix: Update bundle paths
---
.../bank_reconciliation_tool.js | 2 +-
.../bank_statement_import/bank_statement_import.js | 2 +-
erpnext/hooks.py | 9 +++++----
erpnext/public/js/hub/hub_factory.js | 6 +-----
erpnext/selling/page/point_of_sale/point_of_sale.js | 4 ++--
erpnext/stock/doctype/item/item.js | 2 +-
erpnext/stock/page/stock_balance/stock_balance.js | 2 +-
.../warehouse_capacity_summary.js | 4 ++--
erpnext/templates/generators/item/item.html | 10 ++++------
erpnext/templates/pages/cart.html | 8 +++-----
10 files changed, 21 insertions(+), 28 deletions(-)
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
index 10f660a140..f2c3dea116 100644
--- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
@@ -15,7 +15,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
},
refresh: function (frm) {
- frappe.require("assets/js/bank-reconciliation-tool.min.js", () =>
+ frappe.require("bank-reconciliation-tool.bundle.js", () =>
frm.trigger("make_reconciliation_tool")
);
frm.upload_statement_button = frm.page.set_secondary_action(
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
index ad4ff9ee60..2b6aeee1bc 100644
--- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
@@ -319,7 +319,7 @@ frappe.ui.form.on("Bank Statement Import", {
return;
}
- frappe.require("/assets/js/data_import_tools.min.js", () => {
+ frappe.require("data_import_tools.bundle.js", () => {
frm.import_preview = new frappe.data_import.ImportPreview({
wrapper: frm.get_field("import_preview").$wrapper,
doctype: frm.doc.reference_doctype,
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 4b3597afd7..3f145dc958 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -15,10 +15,11 @@ app_logo_url = "/assets/erpnext/images/erpnext-logo.svg"
develop_version = '13.x.x-develop'
-app_include_js = "/assets/js/erpnext.min.js"
-app_include_css = "/assets/css/erpnext.css"
-web_include_js = "/assets/js/erpnext-web.min.js"
-web_include_css = "/assets/css/erpnext-web.css"
+app_include_js = "erpnext.bundle.js"
+app_include_css = "erpnext.bundle.css"
+web_include_js = "erpnext-web.bundle.js"
+web_include_css = "erpnext-web.bundle.css"
+email_css = "email.bundle.css"
doctype_js = {
"Address": "public/js/address.js",
diff --git a/erpnext/public/js/hub/hub_factory.js b/erpnext/public/js/hub/hub_factory.js
index 8dab2d6251..9c67c1cf9f 100644
--- a/erpnext/public/js/hub/hub_factory.js
+++ b/erpnext/public/js/hub/hub_factory.js
@@ -19,11 +19,7 @@ frappe.views.MarketplaceFactory = class MarketplaceFactory extends frappe.views.
}
make(page_name) {
- const assets = [
- '/assets/js/marketplace.min.js'
- ];
-
- frappe.require(assets, () => {
+ frappe.require('marketplace.bundle.js', () => {
erpnext.hub.marketplace = new erpnext.hub.Marketplace({
parent: this.make_page(true, page_name)
});
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js
index e3405e0ce8..6db4150be9 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.js
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.js
@@ -7,7 +7,7 @@ frappe.pages['point-of-sale'].on_page_load = function(wrapper) {
single_column: true
});
- frappe.require('assets/js/point-of-sale.min.js', function() {
+ frappe.require('point-of-sale.bundle.js', function() {
wrapper.pos = new erpnext.PointOfSale.Controller(wrapper);
window.cur_pos = wrapper.pos;
});
@@ -19,4 +19,4 @@ frappe.pages['point-of-sale'].refresh = function(wrapper) {
wrapper.pos.wrapper.html("");
wrapper.pos.check_opening_entry();
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 2079cf88dd..2aa42e66f8 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -379,7 +379,7 @@ $.extend(erpnext.item, {
// Show Stock Levels only if is_stock_item
if (frm.doc.is_stock_item) {
- frappe.require('assets/js/item-dashboard.min.js', function() {
+ frappe.require('item-dashboard.bundle.js', function() {
const section = frm.dashboard.add_section('', __("Stock Levels"));
erpnext.item.item_dashboard = new erpnext.stock.ItemDashboard({
parent: section,
diff --git a/erpnext/stock/page/stock_balance/stock_balance.js b/erpnext/stock/page/stock_balance/stock_balance.js
index bddffd465e..f00dd3e791 100644
--- a/erpnext/stock/page/stock_balance/stock_balance.js
+++ b/erpnext/stock/page/stock_balance/stock_balance.js
@@ -62,7 +62,7 @@ frappe.pages['stock-balance'].on_page_load = function(wrapper) {
// page.sort_selector.wrapper.css({'margin-right': '15px', 'margin-top': '4px'});
- frappe.require('assets/js/item-dashboard.min.js', function() {
+ frappe.require('item-dashboard.bundle.js', function() {
page.item_dashboard = new erpnext.stock.ItemDashboard({
parent: page.main,
page_length: 20,
diff --git a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js
index b610e7dd58..c0ffdc9d51 100644
--- a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js
+++ b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js
@@ -79,7 +79,7 @@ frappe.pages['warehouse-capacity-summary'].on_page_load = function(wrapper) {
}
});
- frappe.require('assets/js/item-dashboard.min.js', function() {
+ frappe.require('item-dashboard.bundle.js', function() {
$(frappe.render_template('warehouse_capacity_summary_header')).appendTo(page.main);
page.capacity_dashboard = new erpnext.stock.ItemDashboard({
@@ -117,4 +117,4 @@ frappe.pages['warehouse-capacity-summary'].on_page_load = function(wrapper) {
setup_click('Item');
setup_click('Warehouse');
});
-};
\ No newline at end of file
+};
diff --git a/erpnext/templates/generators/item/item.html b/erpnext/templates/generators/item/item.html
index 135982d709..17f6880293 100644
--- a/erpnext/templates/generators/item/item.html
+++ b/erpnext/templates/generators/item/item.html
@@ -28,9 +28,7 @@
{% block base_scripts %}
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
+{{ include_script("frappe-web.bundle.js") }}
+{{ include_script("controls.bundle.js") }}
+{{ include_script("dialog.bundle.js") }}
+{% endblock %}
diff --git a/erpnext/templates/pages/cart.html b/erpnext/templates/pages/cart.html
index ea343713a1..c64c6343cc 100644
--- a/erpnext/templates/pages/cart.html
+++ b/erpnext/templates/pages/cart.html
@@ -139,9 +139,7 @@
{% block base_scripts %}
-
-
-
-
-
+{{ include_script("frappe-web.bundle.js") }}
+{{ include_script("controls.bundle.js") }}
+{{ include_script("dialog.bundle.js") }}
{% endblock %}
From 0c8294c963782767829228c95191ec87e0f5afd0 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Fri, 7 May 2021 14:53:55 +0530
Subject: [PATCH 061/149] fix: gitignore dist directory
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 652fbdc317..63c51c4976 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@ latest_updates.json
.wnf-lang-status
*.egg-info
dist/
+erpnext/public/dist
erpnext/docs/current
*.swp
*.swo
From a0ac5e3b13b230c309c4069a7a5b9aa63e9c2bb9 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Fri, 7 May 2021 14:57:32 +0530
Subject: [PATCH 062/149] chore: Add git blame ignore revs file
Ignore the commit which replaces use of Class.extend with native class in git blames
---
.git-blame-ignore-revs | 12 ++++++++++++
1 file changed, 12 insertions(+)
create mode 100644 .git-blame-ignore-revs
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 0000000000..c820d233a5
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,12 @@
+# Since version 2.23 (released in August 2019), git-blame has a feature
+# to ignore or bypass certain commits.
+#
+# This file contains a list of commits that are not likely what you
+# are looking for in a blame, such as mass reformatting or renaming.
+# You can set this file as a default ignore file for blame by running
+# the following command.
+#
+# $ git config blame.ignoreRevsFile .git-blame-ignore-revs
+
+# Replace use of Class.extend with native JS class
+1fe891b287a1b3f225d29ee3d07e7b1824aba9e7
From f97cc0367b699cb8342bd753c7e54d8a3b1d0cf9 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Fri, 7 May 2021 15:32:06 +0530
Subject: [PATCH 063/149] fix: initialize filters in constructor
---
erpnext/public/js/stock_analytics.js | 48 ++++++++++++++--------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/erpnext/public/js/stock_analytics.js b/erpnext/public/js/stock_analytics.js
index c74b45e6db..dfe2c88ea8 100644
--- a/erpnext/public/js/stock_analytics.js
+++ b/erpnext/public/js/stock_analytics.js
@@ -31,6 +31,30 @@ erpnext.StockAnalytics = class StockAnalytics extends erpnext.StockGridReport {
if(opts) $.extend(args, opts);
super(args);
+
+ this.filters = [
+ {fieldtype:"Select", label: __("Value or Qty"), fieldname: "value_or_qty",
+ options:[{label:__("Value"), value:"Value"}, {label:__("Quantity"), value:"Quantity"}],
+ filter: function(val, item, opts, me) {
+ return me.apply_zero_filter(val, item, opts, me);
+ }},
+ {fieldtype:"Select", label: __("Brand"), link:"Brand", fieldname: "brand",
+ default_value: __("Select Brand..."), filter: function(val, item, opts) {
+ return val == opts.default_value || item.brand == val || item._show;
+ }, link_formatter: {filter_input: "brand"}},
+ {fieldtype:"Select", label: __("Warehouse"), link:"Warehouse", fieldname: "warehouse",
+ default_value: __("Select Warehouse...")},
+ {fieldtype:"Date", label: __("From Date"), fieldname: "from_date"},
+ {fieldtype:"Date", label: __("To Date"), fieldname: "to_date"},
+ {fieldtype:"Select", label: __("Range"), fieldname: "range",
+ options:[
+ {label:__("Daily"), value:"Daily"},
+ {label:__("Weekly"), value:"Weekly"},
+ {label:__("Monthly"), value:"Monthly"},
+ {label:__("Quarterly"), value:"Quarterly"},
+ {label:__("Yearly"), value:"Yearly"},
+ ]}
+ ];
}
setup_columns() {
var std_columns = [
@@ -45,30 +69,6 @@ erpnext.StockAnalytics = class StockAnalytics extends erpnext.StockGridReport {
this.columns = std_columns.concat(this.columns);
}
- filters = [
- {fieldtype:"Select", label: __("Value or Qty"), fieldname: "value_or_qty",
- options:[{label:__("Value"), value:"Value"}, {label:__("Quantity"), value:"Quantity"}],
- filter: function(val, item, opts, me) {
- return me.apply_zero_filter(val, item, opts, me);
- }},
- {fieldtype:"Select", label: __("Brand"), link:"Brand", fieldname: "brand",
- default_value: __("Select Brand..."), filter: function(val, item, opts) {
- return val == opts.default_value || item.brand == val || item._show;
- }, link_formatter: {filter_input: "brand"}},
- {fieldtype:"Select", label: __("Warehouse"), link:"Warehouse", fieldname: "warehouse",
- default_value: __("Select Warehouse...")},
- {fieldtype:"Date", label: __("From Date"), fieldname: "from_date"},
- {fieldtype:"Date", label: __("To Date"), fieldname: "to_date"},
- {fieldtype:"Select", label: __("Range"), fieldname: "range",
- options:[
- {label:__("Daily"), value:"Daily"},
- {label:__("Weekly"), value:"Weekly"},
- {label:__("Monthly"), value:"Monthly"},
- {label:__("Quarterly"), value:"Quarterly"},
- {label:__("Yearly"), value:"Yearly"},
- ]}
- ]
-
setup_filters() {
var me = this;
super.setup_filters();
From da7fefe29d82886a90263064b309b1fa0a9b02d9 Mon Sep 17 00:00:00 2001
From: Anupam Kumar
Date: Fri, 7 May 2021 20:26:50 +0530
Subject: [PATCH 064/149] fix: timesheet filter date exclusive issue (#25626)
---
erpnext/projects/doctype/timesheet/timesheet.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index ed02f79c2d..8d99b48b59 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -209,7 +209,7 @@ def get_projectwise_timesheet_data(project, parent=None, from_time=None, to_time
if parent:
condition = "AND parent = %(parent)s"
if from_time and to_time:
- condition += "AND from_time BETWEEN %(from_time)s AND %(to_time)s"
+ condition += "AND CAST(from_time as DATE) BETWEEN %(from_time)s AND %(to_time)s"
return frappe.db.sql("""select name, parent, billing_hours, billing_amount as billing_amt
from `tabTimesheet Detail` where parenttype = 'Timesheet' and docstatus=1 and project = %(project)s {0} and billable = 1
From e28165ea871720a68ebdc00cfb7b97d6bf775d73 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Fri, 7 May 2021 20:27:51 +0530
Subject: [PATCH 065/149] fix: force https for shopify webhook registration
(#25630)
---
.../doctype/shopify_settings/shopify_settings.py | 2 +-
erpnext/erpnext_integrations/utils.py | 8 ++++++--
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
index 7634fd0caf..381c5e5dec 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
@@ -37,7 +37,7 @@ class ShopifySettings(Document):
res = session.post(url, data=json.dumps({
"webhook": {
"topic": method,
- "address": get_webhook_address(connector_name='shopify_connection', method='store_request_data'),
+ "address": get_webhook_address(connector_name='shopify_connection', method='store_request_data', force_https=True),
"format": "json"
}
}), headers=get_header(self))
diff --git a/erpnext/erpnext_integrations/utils.py b/erpnext/erpnext_integrations/utils.py
index 362f6cf88e..3840e781b4 100644
--- a/erpnext/erpnext_integrations/utils.py
+++ b/erpnext/erpnext_integrations/utils.py
@@ -28,7 +28,7 @@ def validate_webhooks_request(doctype, hmac_key, secret_key='secret'):
return innerfn
-def get_webhook_address(connector_name, method, exclude_uri=False):
+def get_webhook_address(connector_name, method, exclude_uri=False, force_https=False):
endpoint = "erpnext.erpnext_integrations.connectors.{0}.{1}".format(connector_name, method)
if exclude_uri:
@@ -39,7 +39,11 @@ def get_webhook_address(connector_name, method, exclude_uri=False):
except RuntimeError:
url = "http://localhost:8000"
- server_url = '{uri.scheme}://{uri.netloc}/api/method/{endpoint}'.format(uri=urlparse(url), endpoint=endpoint)
+ url_data = urlparse(url)
+ scheme = "https" if force_https else url_data.scheme
+ netloc = url_data.netloc
+
+ server_url = f"{scheme}://{netloc}/api/method/{endpoint}"
return server_url
From 90e671905a9a4e8b496a84a8315ceba25e10d9ed Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Fri, 7 May 2021 20:28:51 +0530
Subject: [PATCH 066/149] chore: replace assertEquals with alias assertEqual
(#25613)
* chore: replace assertEquals with alias assertEqual
assertEquals has been deprecated.
ref: https://docs.python.org/3/library/unittest.html#deprecated-aliases
* chore: sider fixes
---
.../accounts/doctype/dunning/test_dunning.py | 6 +-
.../doctype/gl_entry/test_gl_entry.py | 2 +-
.../payment_order/test_payment_order.py | 8 +-
.../doctype/pricing_rule/test_pricing_rule.py | 36 +++----
erpnext/assets/doctype/asset/test_asset.py | 4 +-
.../purchase_order/test_purchase_order.py | 42 ++++----
.../mpesa_settings/test_mpesa_settings.py | 26 ++---
.../test_clinical_procedure.py | 2 +-
.../doctype/lab_test/test_lab_test.py | 4 +-
.../test_patient_appointment.py | 8 +-
.../doctype/therapy_plan/test_therapy_plan.py | 12 +--
.../doctype/therapy_type/test_therapy_type.py | 2 +-
.../test_compensatory_leave_request.py | 16 ++--
.../expense_claim/test_expense_claim.py | 12 +--
.../hr/doctype/job_offer/test_job_offer.py | 4 +-
.../leave_allocation/test_leave_allocation.py | 14 +--
.../test_leave_application.py | 78 +++++++--------
.../leave_encashment/test_leave_encashment.py | 8 +-
.../loan_management/doctype/loan/test_loan.py | 96 +++++++++----------
.../test_loan_disbursement.py | 6 +-
.../test_loan_interest_accrual.py | 6 +-
erpnext/manufacturing/doctype/bom/test_bom.py | 2 +-
.../bom_update_tool/test_bom_update_tool.py | 6 +-
.../doctype/work_order/test_work_order.py | 10 +-
.../doctype/donation/test_donation.py | 2 +-
.../portal/doctype/homepage/test_homepage.py | 2 +-
.../homepage_section/test_homepage_section.py | 4 +-
.../test_tax_exemption_80g_certificate.py | 12 +--
.../doctype/quotation/test_quotation.py | 2 +-
.../doctype/sales_order/test_sales_order.py | 4 +-
.../delivery_note/test_delivery_note.py | 6 +-
.../purchase_receipt/test_purchase_receipt.py | 10 +-
erpnext/support/doctype/issue/test_issue.py | 28 +++---
33 files changed, 240 insertions(+), 240 deletions(-)
diff --git a/erpnext/accounts/doctype/dunning/test_dunning.py b/erpnext/accounts/doctype/dunning/test_dunning.py
index cb18309e3c..c5ce514cdd 100644
--- a/erpnext/accounts/doctype/dunning/test_dunning.py
+++ b/erpnext/accounts/doctype/dunning/test_dunning.py
@@ -42,9 +42,9 @@ class TestDunning(unittest.TestCase):
['Sales - _TC', 0.0, 20.44]
])
for gle in gl_entries:
- self.assertEquals(expected_values[gle.account][0], gle.account)
- self.assertEquals(expected_values[gle.account][1], gle.debit)
- self.assertEquals(expected_values[gle.account][2], gle.credit)
+ self.assertEqual(expected_values[gle.account][0], gle.account)
+ self.assertEqual(expected_values[gle.account][1], gle.debit)
+ self.assertEqual(expected_values[gle.account][2], gle.credit)
def test_payment_entry(self):
dunning = create_dunning()
diff --git a/erpnext/accounts/doctype/gl_entry/test_gl_entry.py b/erpnext/accounts/doctype/gl_entry/test_gl_entry.py
index b4a547b21b..4167ca70df 100644
--- a/erpnext/accounts/doctype/gl_entry/test_gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/test_gl_entry.py
@@ -54,4 +54,4 @@ class TestGLEntry(unittest.TestCase):
self.assertTrue(all(new.name != old.name for new, old in zip(gl_entries, new_gl_entries)))
new_naming_series_current_value = frappe.db.sql("SELECT current from tabSeries where name = %s", naming_series)[0][0]
- self.assertEquals(old_naming_series_current_value + 2, new_naming_series_current_value)
+ self.assertEqual(old_naming_series_current_value + 2, new_naming_series_current_value)
diff --git a/erpnext/accounts/doctype/payment_order/test_payment_order.py b/erpnext/accounts/doctype/payment_order/test_payment_order.py
index 1c23e2a0ec..5fdde07faa 100644
--- a/erpnext/accounts/doctype/payment_order/test_payment_order.py
+++ b/erpnext/accounts/doctype/payment_order/test_payment_order.py
@@ -31,10 +31,10 @@ class TestPaymentOrder(unittest.TestCase):
doc = create_payment_order_against_payment_entry(payment_entry, "Payment Entry")
reference_doc = doc.get("references")[0]
- self.assertEquals(reference_doc.reference_name, payment_entry.name)
- self.assertEquals(reference_doc.reference_doctype, "Payment Entry")
- self.assertEquals(reference_doc.supplier, "_Test Supplier")
- self.assertEquals(reference_doc.amount, 250)
+ self.assertEqual(reference_doc.reference_name, payment_entry.name)
+ self.assertEqual(reference_doc.reference_doctype, "Payment Entry")
+ self.assertEqual(reference_doc.supplier, "_Test Supplier")
+ self.assertEqual(reference_doc.amount, 250)
def create_payment_order_against_payment_entry(ref_doc, order_type):
payment_order = frappe.get_doc(dict(
diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
index ef9aad562d..ffe8be1162 100644
--- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
@@ -99,7 +99,7 @@ class TestPricingRule(unittest.TestCase):
args.item_code = "_Test Item 2"
details = get_item_details(args)
- self.assertEquals(details.get("discount_percentage"), 15)
+ self.assertEqual(details.get("discount_percentage"), 15)
def test_pricing_rule_for_margin(self):
from erpnext.stock.get_item_details import get_item_details
@@ -145,8 +145,8 @@ class TestPricingRule(unittest.TestCase):
"name": None
})
details = get_item_details(args)
- self.assertEquals(details.get("margin_type"), "Percentage")
- self.assertEquals(details.get("margin_rate_or_amount"), 10)
+ self.assertEqual(details.get("margin_type"), "Percentage")
+ self.assertEqual(details.get("margin_rate_or_amount"), 10)
def test_mixed_conditions_for_item_group(self):
for item in ["Mixed Cond Item 1", "Mixed Cond Item 2"]:
@@ -192,7 +192,7 @@ class TestPricingRule(unittest.TestCase):
"name": None
})
details = get_item_details(args)
- self.assertEquals(details.get("discount_percentage"), 10)
+ self.assertEqual(details.get("discount_percentage"), 10)
def test_pricing_rule_for_variants(self):
from erpnext.stock.get_item_details import get_item_details
@@ -322,11 +322,11 @@ class TestPricingRule(unittest.TestCase):
si.insert(ignore_permissions=True)
item = si.items[0]
- self.assertEquals(item.margin_rate_or_amount, 10)
- self.assertEquals(item.rate_with_margin, 1100)
+ self.assertEqual(item.margin_rate_or_amount, 10)
+ self.assertEqual(item.rate_with_margin, 1100)
self.assertEqual(item.discount_percentage, 10)
- self.assertEquals(item.discount_amount, 110)
- self.assertEquals(item.rate, 990)
+ self.assertEqual(item.discount_amount, 110)
+ self.assertEqual(item.rate, 990)
def test_pricing_rule_with_margin_and_discount_amount(self):
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
@@ -338,10 +338,10 @@ class TestPricingRule(unittest.TestCase):
si.insert(ignore_permissions=True)
item = si.items[0]
- self.assertEquals(item.margin_rate_or_amount, 10)
- self.assertEquals(item.rate_with_margin, 1100)
- self.assertEquals(item.discount_amount, 110)
- self.assertEquals(item.rate, 990)
+ self.assertEqual(item.margin_rate_or_amount, 10)
+ self.assertEqual(item.rate_with_margin, 1100)
+ self.assertEqual(item.discount_amount, 110)
+ self.assertEqual(item.rate, 990)
def test_pricing_rule_for_product_discount_on_same_item(self):
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
@@ -458,21 +458,21 @@ class TestPricingRule(unittest.TestCase):
si.items[0].price_list_rate = 1000
si.submit()
item = si.items[0]
- self.assertEquals(item.rate, 100)
+ self.assertEqual(item.rate, 100)
# Correct Customer and Incorrect is_return value
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=1, qty=-1)
si.items[0].price_list_rate = 1000
si.submit()
item = si.items[0]
- self.assertEquals(item.rate, 100)
+ self.assertEqual(item.rate, 100)
# Correct Customer and correct is_return value
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=0)
si.items[0].price_list_rate = 1000
si.submit()
item = si.items[0]
- self.assertEquals(item.rate, 900)
+ self.assertEqual(item.rate, 900)
def test_multiple_pricing_rules(self):
make_pricing_rule(discount_percentage=20, selling=1, priority=1, apply_multiple_pricing_rules=1,
@@ -545,11 +545,11 @@ class TestPricingRule(unittest.TestCase):
apply_on="Transaction", free_item="Water Flask 1", free_qty=1, free_item_rate=10)
si = create_sales_invoice(qty=5, do_not_submit=True)
- self.assertEquals(len(si.items), 2)
- self.assertEquals(si.items[1].rate, 10)
+ self.assertEqual(len(si.items), 2)
+ self.assertEqual(si.items[1].rate, 10)
si1 = create_sales_invoice(qty=2, do_not_submit=True)
- self.assertEquals(len(si1.items), 1)
+ self.assertEqual(len(si1.items), 1)
for doc in [si, si1]:
doc.delete()
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index a0d76031fc..40a8f85d8d 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -78,7 +78,7 @@ class TestAsset(unittest.TestCase):
})
doc.set_missing_values()
- self.assertEquals(doc.items[0].is_fixed_asset, 1)
+ self.assertEqual(doc.items[0].is_fixed_asset, 1)
def test_schedule_for_straight_line_method(self):
pr = make_purchase_receipt(item_code="Macbook Pro",
@@ -565,7 +565,7 @@ class TestAsset(unittest.TestCase):
doc = make_invoice(pr.name)
- self.assertEquals('Asset Received But Not Billed - _TC', doc.items[0].expense_account)
+ self.assertEqual('Asset Received But Not Billed - _TC', doc.items[0].expense_account)
def test_asset_cwip_toggling_cases(self):
cwip = frappe.db.get_value("Asset Category", "Computers", "enable_cwip_accounting")
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 42f4472f29..aaa98f2f1f 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -187,7 +187,7 @@ class TestPurchaseOrder(unittest.TestCase):
update_child_qty_rate('Purchase Order', trans_item, po.name)
po.reload()
- self.assertEquals(len(po.get('items')), 2)
+ self.assertEqual(len(po.get('items')), 2)
self.assertEqual(po.status, 'To Receive and Bill')
# ordered qty should increase on row addition
self.assertEqual(get_ordered_qty(), existing_ordered_qty + 7)
@@ -234,7 +234,7 @@ class TestPurchaseOrder(unittest.TestCase):
update_child_qty_rate('Purchase Order', trans_item, po.name)
po.reload()
- self.assertEquals(len(po.get('items')), 1)
+ self.assertEqual(len(po.get('items')), 1)
self.assertEqual(po.status, 'To Receive and Bill')
# ordered qty should decrease (back to initial) on row deletion
@@ -448,13 +448,13 @@ class TestPurchaseOrder(unittest.TestCase):
pi.load_from_db()
- self.assertEquals(pi.per_received, 100.00)
- self.assertEquals(pi.items[0].qty, pi.items[0].received_qty)
+ self.assertEqual(pi.per_received, 100.00)
+ self.assertEqual(pi.items[0].qty, pi.items[0].received_qty)
po.load_from_db()
- self.assertEquals(po.per_received, 100.00)
- self.assertEquals(po.per_billed, 100.00)
+ self.assertEqual(po.per_received, 100.00)
+ self.assertEqual(po.per_billed, 100.00)
pr.cancel()
@@ -674,8 +674,8 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname=["reserved_qty_for_sub_contract", "projected_qty"], as_dict=1)
- self.assertEquals(bin2.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
- self.assertEquals(bin2.projected_qty, bin1.projected_qty - 10)
+ self.assertEqual(bin2.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
+ self.assertEqual(bin2.projected_qty, bin1.projected_qty - 10)
# Create stock transfer
rm_item = [{"item_code":"_Test FG Item","rm_item_code":"_Test Item","item_name":"_Test Item",
@@ -690,7 +690,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin3.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
+ self.assertEqual(bin3.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
# close PO
po.update_status("Closed")
@@ -698,7 +698,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin4.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
+ self.assertEqual(bin4.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
# Re-open PO
po.update_status("Submitted")
@@ -706,7 +706,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin5.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
+ self.assertEqual(bin5.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
make_stock_entry(target="_Test Warehouse 1 - _TC", item_code="_Test Item",
qty=40, basic_rate=100)
@@ -723,7 +723,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin6.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
+ self.assertEqual(bin6.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
# Cancel PR
pr.cancel()
@@ -731,7 +731,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin7.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
+ self.assertEqual(bin7.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
# Make Purchase Invoice
pi = make_pi_from_po(po.name)
@@ -743,7 +743,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin8.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
+ self.assertEqual(bin8.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
# Cancel PR
pi.cancel()
@@ -751,7 +751,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin9.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
+ self.assertEqual(bin9.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
# Cancel Stock Entry
se.cancel()
@@ -759,7 +759,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin10.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
+ self.assertEqual(bin10.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
# Cancel PO
po.reload()
@@ -768,7 +768,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin11.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
+ self.assertEqual(bin11.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
def test_exploded_items_in_subcontracted(self):
item_code = "_Test Subcontracted FG Item 1"
@@ -782,7 +782,7 @@ class TestPurchaseOrder(unittest.TestCase):
exploded_items = sorted([d.item_code for d in bom.exploded_items if not d.get('sourced_by_supplier')])
supplied_items = sorted([d.rm_item_code for d in po.supplied_items])
- self.assertEquals(exploded_items, supplied_items)
+ self.assertEqual(exploded_items, supplied_items)
po1 = create_purchase_order(item_code=item_code, qty=1,
is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC", include_exploded_items=0)
@@ -790,7 +790,7 @@ class TestPurchaseOrder(unittest.TestCase):
supplied_items1 = sorted([d.rm_item_code for d in po1.supplied_items])
bom_items = sorted([d.item_code for d in bom.items if not d.get('sourced_by_supplier')])
- self.assertEquals(supplied_items1, bom_items)
+ self.assertEqual(supplied_items1, bom_items)
def test_backflush_based_on_stock_entry(self):
item_code = "_Test Subcontracted FG Item 1"
@@ -840,8 +840,8 @@ class TestPurchaseOrder(unittest.TestCase):
transferred_items = sorted([d.item_code for d in se.get('items') if se.purchase_order == po.name])
issued_items = sorted([d.rm_item_code for d in pr.get('supplied_items')])
- self.assertEquals(transferred_items, issued_items)
- self.assertEquals(pr.get('items')[0].rm_supp_cost, 2000)
+ self.assertEqual(transferred_items, issued_items)
+ self.assertEqual(pr.get('items')[0].rm_supp_cost, 2000)
transferred_rm_map = frappe._dict()
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
index 29487962f6..d370fbcda7 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
@@ -19,7 +19,7 @@ class TestMpesaSettings(unittest.TestCase):
mode_of_payment = frappe.get_doc("Mode of Payment", "Mpesa-_Test")
self.assertTrue(frappe.db.exists("Payment Gateway Account", {'payment_gateway': "Mpesa-_Test"}))
self.assertTrue(mode_of_payment.name)
- self.assertEquals(mode_of_payment.type, "Phone")
+ self.assertEqual(mode_of_payment.type, "Phone")
def test_processing_of_account_balance(self):
mpesa_doc = create_mpesa_settings(payment_gateway_name="_Account Balance")
@@ -31,11 +31,11 @@ class TestMpesaSettings(unittest.TestCase):
# test integration request creation and successful update of the status on receiving callback response
self.assertTrue(integration_request)
- self.assertEquals(integration_request.status, "Completed")
+ self.assertEqual(integration_request.status, "Completed")
# test formatting of account balance received as string to json with appropriate currency symbol
mpesa_doc.reload()
- self.assertEquals(mpesa_doc.account_balance, dumps({
+ self.assertEqual(mpesa_doc.account_balance, dumps({
"Working Account": {
"current_balance": "Sh 481,000.00",
"available_balance": "Sh 481,000.00",
@@ -60,7 +60,7 @@ class TestMpesaSettings(unittest.TestCase):
pr = pos_invoice.create_payment_request()
# test payment request creation
- self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
+ self.assertEqual(pr.payment_gateway, "Mpesa-Payment")
# submitting payment request creates integration requests with random id
integration_req_ids = frappe.get_all("Integration Request", filters={
@@ -75,12 +75,12 @@ class TestMpesaSettings(unittest.TestCase):
# test integration request creation and successful update of the status on receiving callback response
self.assertTrue(integration_request)
- self.assertEquals(integration_request.status, "Completed")
+ self.assertEqual(integration_request.status, "Completed")
pos_invoice.reload()
integration_request.reload()
- self.assertEquals(pos_invoice.mpesa_receipt_number, "LGR7OWQX0R")
- self.assertEquals(integration_request.status, "Completed")
+ self.assertEqual(pos_invoice.mpesa_receipt_number, "LGR7OWQX0R")
+ self.assertEqual(integration_request.status, "Completed")
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
integration_request.delete()
@@ -104,7 +104,7 @@ class TestMpesaSettings(unittest.TestCase):
pr = pos_invoice.create_payment_request()
# test payment request creation
- self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
+ self.assertEqual(pr.payment_gateway, "Mpesa-Payment")
# submitting payment request creates integration requests with random id
integration_req_ids = frappe.get_all("Integration Request", filters={
@@ -126,12 +126,12 @@ class TestMpesaSettings(unittest.TestCase):
verify_transaction(**callback_response)
# test completion of integration request
integration_request = frappe.get_doc("Integration Request", integration_req_ids[i])
- self.assertEquals(integration_request.status, "Completed")
+ self.assertEqual(integration_request.status, "Completed")
integration_requests.append(integration_request)
# check receipt number once all the integration requests are completed
pos_invoice.reload()
- self.assertEquals(pos_invoice.mpesa_receipt_number, ', '.join(mpesa_receipt_numbers))
+ self.assertEqual(pos_invoice.mpesa_receipt_number, ', '.join(mpesa_receipt_numbers))
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
[d.delete() for d in integration_requests]
@@ -155,7 +155,7 @@ class TestMpesaSettings(unittest.TestCase):
pr = pos_invoice.create_payment_request()
# test payment request creation
- self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
+ self.assertEqual(pr.payment_gateway, "Mpesa-Payment")
# submitting payment request creates integration requests with random id
integration_req_ids = frappe.get_all("Integration Request", filters={
@@ -175,7 +175,7 @@ class TestMpesaSettings(unittest.TestCase):
verify_transaction(**callback_response)
# test completion of integration request
integration_request = frappe.get_doc("Integration Request", integration_req_ids[0])
- self.assertEquals(integration_request.status, "Completed")
+ self.assertEqual(integration_request.status, "Completed")
# now one request is completed
# second integration request fails
@@ -187,7 +187,7 @@ class TestMpesaSettings(unittest.TestCase):
'name': ['not in', integration_req_ids]
}, pluck="name")
- self.assertEquals(len(new_integration_req_ids), 1)
+ self.assertEqual(len(new_integration_req_ids), 1)
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
frappe.db.sql("delete from `tabIntegration Request` where integration_request_service = 'Mpesa'")
diff --git a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
index fb72073a07..03e96a4b3b 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
@@ -17,7 +17,7 @@ class TestClinicalProcedure(unittest.TestCase):
procedure_template.disabled = 1
procedure_template.save()
- self.assertEquals(frappe.db.get_value('Item', procedure_template.item, 'disabled'), 1)
+ self.assertEqual(frappe.db.get_value('Item', procedure_template.item, 'disabled'), 1)
def test_consumables(self):
patient, medical_department, practitioner = create_healthcare_docs()
diff --git a/erpnext/healthcare/doctype/lab_test/test_lab_test.py b/erpnext/healthcare/doctype/lab_test/test_lab_test.py
index 79ab8a4d7f..c9f0029ed8 100644
--- a/erpnext/healthcare/doctype/lab_test/test_lab_test.py
+++ b/erpnext/healthcare/doctype/lab_test/test_lab_test.py
@@ -18,7 +18,7 @@ class TestLabTest(unittest.TestCase):
lab_template.disabled = 1
lab_template.save()
- self.assertEquals(frappe.db.get_value('Item', lab_template.item, 'disabled'), 1)
+ self.assertEqual(frappe.db.get_value('Item', lab_template.item, 'disabled'), 1)
lab_template.reload()
@@ -57,7 +57,7 @@ class TestLabTest(unittest.TestCase):
# sample collection should not be created
lab_test.reload()
- self.assertEquals(lab_test.sample, None)
+ self.assertEqual(lab_test.sample, None)
def test_create_lab_tests_from_sales_invoice(self):
sales_invoice = create_sales_invoice()
diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
index 2bb8a53c45..5f2dc480a1 100644
--- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
@@ -20,13 +20,13 @@ class TestPatientAppointment(unittest.TestCase):
patient, medical_department, practitioner = create_healthcare_docs()
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 0)
appointment = create_appointment(patient, practitioner, nowdate())
- self.assertEquals(appointment.status, 'Open')
+ self.assertEqual(appointment.status, 'Open')
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2))
- self.assertEquals(appointment.status, 'Scheduled')
+ self.assertEqual(appointment.status, 'Scheduled')
encounter = create_encounter(appointment)
- self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
+ self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
encounter.cancel()
- self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
+ self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
def test_start_encounter(self):
patient, medical_department, practitioner = create_healthcare_docs()
diff --git a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
index 7fb159d6b5..d079bedb42 100644
--- a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
+++ b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
@@ -18,24 +18,24 @@ class TestTherapyPlan(unittest.TestCase):
def test_status(self):
plan = create_therapy_plan()
- self.assertEquals(plan.status, 'Not Started')
+ self.assertEqual(plan.status, 'Not Started')
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
frappe.get_doc(session).submit()
- self.assertEquals(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'In Progress')
+ self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'In Progress')
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
frappe.get_doc(session).submit()
- self.assertEquals(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed')
+ self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed')
patient, medical_department, practitioner = create_healthcare_docs()
appointment = create_appointment(patient, practitioner, nowdate())
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company', appointment.name)
session = frappe.get_doc(session)
session.submit()
- self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
+ self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
session.cancel()
- self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
+ self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
def test_therapy_plan_from_template(self):
patient = create_patient()
@@ -49,7 +49,7 @@ class TestTherapyPlan(unittest.TestCase):
si.save()
therapy_plan_template_amt = frappe.db.get_value('Therapy Plan Template', template, 'total_amount')
- self.assertEquals(si.items[0].amount, therapy_plan_template_amt)
+ self.assertEqual(si.items[0].amount, therapy_plan_template_amt)
def create_therapy_plan(template=None):
diff --git a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py b/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
index 03a1be8a4e..21f6369975 100644
--- a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
+++ b/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
@@ -13,7 +13,7 @@ class TestTherapyType(unittest.TestCase):
therapy_type.disabled = 1
therapy_type.save()
- self.assertEquals(frappe.db.get_value('Item', therapy_type.item, 'disabled'), 1)
+ self.assertEqual(frappe.db.get_value('Item', therapy_type.item, 'disabled'), 1)
def create_therapy_type():
exercise = create_exercise_type()
diff --git a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py b/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py
index 74ce30108f..3b99c57051 100644
--- a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py
+++ b/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py
@@ -68,19 +68,19 @@ class TestCompensatoryLeaveRequest(unittest.TestCase):
filters = dict(transaction_name=compensatory_leave_request.leave_allocation)
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=filters)
- self.assertEquals(len(leave_ledger_entry), 1)
- self.assertEquals(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
- self.assertEquals(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
- self.assertEquals(leave_ledger_entry[0].leaves, 1)
+ self.assertEqual(len(leave_ledger_entry), 1)
+ self.assertEqual(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
+ self.assertEqual(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
+ self.assertEqual(leave_ledger_entry[0].leaves, 1)
# check reverse leave ledger entry on cancellation
compensatory_leave_request.cancel()
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=filters, order_by = 'creation desc')
- self.assertEquals(len(leave_ledger_entry), 2)
- self.assertEquals(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
- self.assertEquals(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
- self.assertEquals(leave_ledger_entry[0].leaves, -1)
+ self.assertEqual(len(leave_ledger_entry), 2)
+ self.assertEqual(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
+ self.assertEqual(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
+ self.assertEqual(leave_ledger_entry[0].leaves, -1)
def get_compensatory_leave_request(employee, leave_date=today()):
prev_comp_leave_req = frappe.db.get_value('Compensatory Leave Request',
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
index 3f22ca2141..578eccf787 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
@@ -88,9 +88,9 @@ class TestExpenseClaim(unittest.TestCase):
])
for gle in gl_entries:
- self.assertEquals(expected_values[gle.account][0], gle.account)
- self.assertEquals(expected_values[gle.account][1], gle.debit)
- self.assertEquals(expected_values[gle.account][2], gle.credit)
+ self.assertEqual(expected_values[gle.account][0], gle.account)
+ self.assertEqual(expected_values[gle.account][1], gle.debit)
+ self.assertEqual(expected_values[gle.account][2], gle.credit)
def test_rejected_expense_claim(self):
payable_account = get_payable_account(company_name)
@@ -104,11 +104,11 @@ class TestExpenseClaim(unittest.TestCase):
})
expense_claim.submit()
- self.assertEquals(expense_claim.status, 'Rejected')
- self.assertEquals(expense_claim.total_sanctioned_amount, 0.0)
+ self.assertEqual(expense_claim.status, 'Rejected')
+ self.assertEqual(expense_claim.total_sanctioned_amount, 0.0)
gl_entry = frappe.get_all('GL Entry', {'voucher_type': 'Expense Claim', 'voucher_no': expense_claim.name})
- self.assertEquals(len(gl_entry), 0)
+ self.assertEqual(len(gl_entry), 0)
def test_expense_approver_perms(self):
user = "test_approver_perm_emp@example.com"
diff --git a/erpnext/hr/doctype/job_offer/test_job_offer.py b/erpnext/hr/doctype/job_offer/test_job_offer.py
index 690a692ddc..b3e1dc8d87 100644
--- a/erpnext/hr/doctype/job_offer/test_job_offer.py
+++ b/erpnext/hr/doctype/job_offer/test_job_offer.py
@@ -35,13 +35,13 @@ class TestJobOffer(unittest.TestCase):
job_offer = create_job_offer(job_applicant=job_applicant.name)
job_offer.submit()
job_applicant.reload()
- self.assertEquals(job_applicant.status, "Accepted")
+ self.assertEqual(job_applicant.status, "Accepted")
# status update after rejection
job_offer.status = "Rejected"
job_offer.submit()
job_applicant.reload()
- self.assertEquals(job_applicant.status, "Rejected")
+ self.assertEqual(job_applicant.status, "Rejected")
def create_job_offer(**args):
args = frappe._dict(args)
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index 0b71036c86..6e7ae87d08 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -96,7 +96,7 @@ class TestLeaveAllocation(unittest.TestCase):
carry_forward=1)
leave_allocation_1.submit()
- self.assertEquals(leave_allocation_1.unused_leaves, 10)
+ self.assertEqual(leave_allocation_1.unused_leaves, 10)
leave_allocation_1.cancel()
@@ -108,7 +108,7 @@ class TestLeaveAllocation(unittest.TestCase):
new_leaves_allocated=25)
leave_allocation_2.submit()
- self.assertEquals(leave_allocation_2.unused_leaves, 5)
+ self.assertEqual(leave_allocation_2.unused_leaves, 5)
def test_carry_forward_leaves_expiry(self):
frappe.db.sql("delete from `tabLeave Allocation`")
@@ -145,7 +145,7 @@ class TestLeaveAllocation(unittest.TestCase):
to_date=add_months(nowdate(), 12))
leave_allocation_1.submit()
- self.assertEquals(leave_allocation_1.unused_leaves, leave_allocation.new_leaves_allocated)
+ self.assertEqual(leave_allocation_1.unused_leaves, leave_allocation.new_leaves_allocated)
def test_creation_of_leave_ledger_entry_on_submit(self):
frappe.db.sql("delete from `tabLeave Allocation`")
@@ -155,10 +155,10 @@ class TestLeaveAllocation(unittest.TestCase):
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_allocation.name))
- self.assertEquals(len(leave_ledger_entry), 1)
- self.assertEquals(leave_ledger_entry[0].employee, leave_allocation.employee)
- self.assertEquals(leave_ledger_entry[0].leave_type, leave_allocation.leave_type)
- self.assertEquals(leave_ledger_entry[0].leaves, leave_allocation.new_leaves_allocated)
+ self.assertEqual(len(leave_ledger_entry), 1)
+ self.assertEqual(leave_ledger_entry[0].employee, leave_allocation.employee)
+ self.assertEqual(leave_ledger_entry[0].leave_type, leave_allocation.leave_type)
+ self.assertEqual(leave_ledger_entry[0].leaves, leave_allocation.new_leaves_allocated)
# check if leave ledger entry is deleted on cancellation
leave_allocation.cancel()
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index b54c9712c8..a4a96b813e 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -16,36 +16,36 @@ from erpnext.hr.doctype.employee.test_employee import make_employee
test_dependencies = ["Leave Allocation", "Leave Block List", "Employee"]
_test_records = [
- {
- "company": "_Test Company",
- "doctype": "Leave Application",
- "employee": "_T-Employee-00001",
- "from_date": "2013-05-01",
- "description": "_Test Reason",
- "leave_type": "_Test Leave Type",
- "posting_date": "2013-01-02",
- "to_date": "2013-05-05"
- },
- {
- "company": "_Test Company",
- "doctype": "Leave Application",
- "employee": "_T-Employee-00002",
- "from_date": "2013-05-01",
- "description": "_Test Reason",
- "leave_type": "_Test Leave Type",
- "posting_date": "2013-01-02",
- "to_date": "2013-05-05"
- },
- {
- "company": "_Test Company",
- "doctype": "Leave Application",
- "employee": "_T-Employee-00001",
- "from_date": "2013-01-15",
- "description": "_Test Reason",
- "leave_type": "_Test Leave Type LWP",
- "posting_date": "2013-01-02",
- "to_date": "2013-01-15"
- }
+ {
+ "company": "_Test Company",
+ "doctype": "Leave Application",
+ "employee": "_T-Employee-00001",
+ "from_date": "2013-05-01",
+ "description": "_Test Reason",
+ "leave_type": "_Test Leave Type",
+ "posting_date": "2013-01-02",
+ "to_date": "2013-05-05"
+ },
+ {
+ "company": "_Test Company",
+ "doctype": "Leave Application",
+ "employee": "_T-Employee-00002",
+ "from_date": "2013-05-01",
+ "description": "_Test Reason",
+ "leave_type": "_Test Leave Type",
+ "posting_date": "2013-01-02",
+ "to_date": "2013-05-05"
+ },
+ {
+ "company": "_Test Company",
+ "doctype": "Leave Application",
+ "employee": "_T-Employee-00001",
+ "from_date": "2013-01-15",
+ "description": "_Test Reason",
+ "leave_type": "_Test Leave Type LWP",
+ "posting_date": "2013-01-02",
+ "to_date": "2013-01-15"
+ }
]
@@ -516,9 +516,9 @@ class TestLeaveApplication(unittest.TestCase):
leave_application.submit()
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_application.name))
- self.assertEquals(leave_ledger_entry[0].employee, leave_application.employee)
- self.assertEquals(leave_ledger_entry[0].leave_type, leave_application.leave_type)
- self.assertEquals(leave_ledger_entry[0].leaves, leave_application.total_leave_days * -1)
+ self.assertEqual(leave_ledger_entry[0].employee, leave_application.employee)
+ self.assertEqual(leave_ledger_entry[0].leave_type, leave_application.leave_type)
+ self.assertEqual(leave_ledger_entry[0].leaves, leave_application.total_leave_days * -1)
# check if leave ledger entry is deleted on cancellation
leave_application.cancel()
@@ -549,11 +549,11 @@ class TestLeaveApplication(unittest.TestCase):
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', '*', filters=dict(transaction_name=leave_application.name))
- self.assertEquals(len(leave_ledger_entry), 2)
- self.assertEquals(leave_ledger_entry[0].employee, leave_application.employee)
- self.assertEquals(leave_ledger_entry[0].leave_type, leave_application.leave_type)
- self.assertEquals(leave_ledger_entry[0].leaves, -9)
- self.assertEquals(leave_ledger_entry[1].leaves, -2)
+ self.assertEqual(len(leave_ledger_entry), 2)
+ self.assertEqual(leave_ledger_entry[0].employee, leave_application.employee)
+ self.assertEqual(leave_ledger_entry[0].leave_type, leave_application.leave_type)
+ self.assertEqual(leave_ledger_entry[0].leaves, -9)
+ self.assertEqual(leave_ledger_entry[1].leaves, -2)
def test_leave_application_creation_after_expiry(self):
# test leave balance for carry forwarded allocation
@@ -566,7 +566,7 @@ class TestLeaveApplication(unittest.TestCase):
create_carry_forwarded_allocation(employee, leave_type)
- self.assertEquals(get_leave_balance_on(employee.name, leave_type.name, add_days(nowdate(), -85), add_days(nowdate(), -84)), 0)
+ self.assertEqual(get_leave_balance_on(employee.name, leave_type.name, add_days(nowdate(), -85), add_days(nowdate(), -84)), 0)
def test_leave_approver_perms(self):
employee = get_employee()
diff --git a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
index aafc9642d4..e0ffa5dd41 100644
--- a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
@@ -88,10 +88,10 @@ class TestLeaveEncashment(unittest.TestCase):
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_encashment.name))
- self.assertEquals(len(leave_ledger_entry), 1)
- self.assertEquals(leave_ledger_entry[0].employee, leave_encashment.employee)
- self.assertEquals(leave_ledger_entry[0].leave_type, leave_encashment.leave_type)
- self.assertEquals(leave_ledger_entry[0].leaves, leave_encashment.encashable_days * -1)
+ self.assertEqual(len(leave_ledger_entry), 1)
+ self.assertEqual(leave_ledger_entry[0].employee, leave_encashment.employee)
+ self.assertEqual(leave_ledger_entry[0].leave_type, leave_encashment.leave_type)
+ self.assertEqual(leave_ledger_entry[0].leaves, leave_encashment.encashable_days * -1)
# check if leave ledger entry is deleted on cancellation
diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py
index fae6f860b6..fa4707ce2b 100644
--- a/erpnext/loan_management/doctype/loan/test_loan.py
+++ b/erpnext/loan_management/doctype/loan/test_loan.py
@@ -55,9 +55,9 @@ class TestLoan(unittest.TestCase):
def test_loan(self):
loan = frappe.get_doc("Loan", {"applicant":self.applicant1})
- self.assertEquals(loan.monthly_repayment_amount, 15052)
- self.assertEquals(flt(loan.total_interest_payable, 0), 21034)
- self.assertEquals(flt(loan.total_payment, 0), 301034)
+ self.assertEqual(loan.monthly_repayment_amount, 15052)
+ self.assertEqual(flt(loan.total_interest_payable, 0), 21034)
+ self.assertEqual(flt(loan.total_payment, 0), 301034)
schedule = loan.repayment_schedule
@@ -72,9 +72,9 @@ class TestLoan(unittest.TestCase):
loan.monthly_repayment_amount = 14000
loan.save()
- self.assertEquals(len(loan.repayment_schedule), 22)
- self.assertEquals(flt(loan.total_interest_payable, 0), 22712)
- self.assertEquals(flt(loan.total_payment, 0), 302712)
+ self.assertEqual(len(loan.repayment_schedule), 22)
+ self.assertEqual(flt(loan.total_interest_payable, 0), 22712)
+ self.assertEqual(flt(loan.total_payment, 0), 302712)
def test_loan_with_security(self):
@@ -89,7 +89,7 @@ class TestLoan(unittest.TestCase):
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods",
12, loan_application)
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
def test_loan_disbursement(self):
pledge = [{
@@ -102,7 +102,7 @@ class TestLoan(unittest.TestCase):
create_pledge(loan_application)
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application)
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
loan.submit()
@@ -120,8 +120,8 @@ class TestLoan(unittest.TestCase):
filters = {'voucher_type': 'Loan Disbursement', 'voucher_no': loan_disbursement_entry2.name}
)
- self.assertEquals(loan.status, "Disbursed")
- self.assertEquals(loan.disbursed_amount, 1000000)
+ self.assertEqual(loan.status, "Disbursed")
+ self.assertEqual(loan.disbursed_amount, 1000000)
self.assertTrue(gl_entries1)
self.assertTrue(gl_entries2)
@@ -137,7 +137,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -156,15 +156,15 @@ class TestLoan(unittest.TestCase):
repayment_entry.submit()
penalty_amount = (accrued_interest_amount * 5 * 25) / 100
- self.assertEquals(flt(repayment_entry.penalty_amount,0), flt(penalty_amount, 0))
+ self.assertEqual(flt(repayment_entry.penalty_amount,0), flt(penalty_amount, 0))
amounts = frappe.db.get_all('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount'])
loan.load_from_db()
total_interest_paid = amounts[0]['paid_interest_amount'] + amounts[1]['paid_interest_amount']
- self.assertEquals(amounts[1]['paid_interest_amount'], repayment_entry.interest_payable)
- self.assertEquals(flt(loan.total_principal_paid, 0), flt(repayment_entry.amount_paid -
+ self.assertEqual(amounts[1]['paid_interest_amount'], repayment_entry.interest_payable)
+ self.assertEqual(flt(loan.total_principal_paid, 0), flt(repayment_entry.amount_paid -
penalty_amount - total_interest_paid, 0))
def test_loan_closure(self):
@@ -179,7 +179,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -204,12 +204,12 @@ class TestLoan(unittest.TestCase):
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
- self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
- self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
+ self.assertEqual(flt(amount, 0),flt(accrued_interest_amount, 0))
+ self.assertEqual(flt(repayment_entry.penalty_amount, 5), 0)
request_loan_closure(loan.name)
loan.load_from_db()
- self.assertEquals(loan.status, "Loan Closure Requested")
+ self.assertEqual(loan.status, "Loan Closure Requested")
def test_loan_repayment_for_term_loan(self):
pledges = [{
@@ -241,8 +241,8 @@ class TestLoan(unittest.TestCase):
amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
'paid_principal_amount'])
- self.assertEquals(amounts[0], 11250.00)
- self.assertEquals(amounts[1], 78303.00)
+ self.assertEqual(amounts[0], 11250.00)
+ self.assertEqual(amounts[1], 78303.00)
def test_security_shortfall(self):
pledges = [{
@@ -268,17 +268,17 @@ class TestLoan(unittest.TestCase):
loan_security_shortfall = frappe.get_doc("Loan Security Shortfall", {"loan": loan.name})
self.assertTrue(loan_security_shortfall)
- self.assertEquals(loan_security_shortfall.loan_amount, 1000000.00)
- self.assertEquals(loan_security_shortfall.security_value, 800000.00)
- self.assertEquals(loan_security_shortfall.shortfall_amount, 600000.00)
+ self.assertEqual(loan_security_shortfall.loan_amount, 1000000.00)
+ self.assertEqual(loan_security_shortfall.security_value, 800000.00)
+ self.assertEqual(loan_security_shortfall.shortfall_amount, 600000.00)
frappe.db.sql(""" UPDATE `tabLoan Security Price` SET loan_security_price = 250
where loan_security='Test Security 2'""")
create_process_loan_security_shortfall()
loan_security_shortfall = frappe.get_doc("Loan Security Shortfall", {"loan": loan.name})
- self.assertEquals(loan_security_shortfall.status, "Completed")
- self.assertEquals(loan_security_shortfall.shortfall_amount, 0)
+ self.assertEqual(loan_security_shortfall.status, "Completed")
+ self.assertEqual(loan_security_shortfall.shortfall_amount, 0)
def test_loan_security_unpledge(self):
pledge = [{
@@ -292,7 +292,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -312,7 +312,7 @@ class TestLoan(unittest.TestCase):
request_loan_closure(loan.name)
loan.load_from_db()
- self.assertEquals(loan.status, "Loan Closure Requested")
+ self.assertEqual(loan.status, "Loan Closure Requested")
unpledge_request = unpledge_security(loan=loan.name, save=1)
unpledge_request.submit()
@@ -323,11 +323,11 @@ class TestLoan(unittest.TestCase):
pledged_qty = get_pledged_security_qty(loan.name)
self.assertEqual(loan.status, 'Closed')
- self.assertEquals(sum(pledged_qty.values()), 0)
+ self.assertEqual(sum(pledged_qty.values()), 0)
amounts = amounts = calculate_amounts(loan.name, add_days(last_date, 5))
self.assertEqual(amounts['pending_principal_amount'], 0)
- self.assertEquals(amounts['payable_principal_amount'], 0.0)
+ self.assertEqual(amounts['payable_principal_amount'], 0.0)
self.assertEqual(amounts['interest_amount'], 0)
def test_partial_loan_security_unpledge(self):
@@ -346,7 +346,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -379,7 +379,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
unpledge_map = {'Test Security 1': 4000}
unpledge_request = unpledge_security(loan=loan.name, security_map = unpledge_map, save=1)
@@ -450,7 +450,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -475,7 +475,7 @@ class TestLoan(unittest.TestCase):
request_loan_closure(loan.name)
loan.load_from_db()
- self.assertEquals(loan.status, "Loan Closure Requested")
+ self.assertEqual(loan.status, "Loan Closure Requested")
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
self.assertEqual(amounts['pending_principal_amount'], 0.0)
@@ -492,7 +492,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -533,8 +533,8 @@ class TestLoan(unittest.TestCase):
calculated_penalty_amount = frappe.db.get_value('Loan Interest Accrual',
{'process_loan_interest_accrual': process, 'loan': loan.name}, 'penalty_amount')
- self.assertEquals(loan.loan_amount, 1000000)
- self.assertEquals(calculated_penalty_amount, penalty_amount)
+ self.assertEqual(loan.loan_amount, 1000000)
+ self.assertEqual(calculated_penalty_amount, penalty_amount)
def test_penalty_repayment(self):
loan, dummy = create_loan_scenario_for_penalty(self)
@@ -547,13 +547,13 @@ class TestLoan(unittest.TestCase):
repayment_entry.submit()
amounts = calculate_amounts(loan.name, '2019-11-30 00:00:01')
- self.assertEquals(amounts['penalty_amount'], second_penalty)
+ self.assertEqual(amounts['penalty_amount'], second_penalty)
repayment_entry = create_repayment_entry(loan.name, self.applicant2, '2019-11-30 00:00:01', second_penalty)
repayment_entry.submit()
amounts = calculate_amounts(loan.name, '2019-11-30 00:00:02')
- self.assertEquals(amounts['penalty_amount'], 0)
+ self.assertEqual(amounts['penalty_amount'], 0)
def test_loan_write_off_limit(self):
pledge = [{
@@ -567,7 +567,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -589,15 +589,15 @@ class TestLoan(unittest.TestCase):
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
- self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
- self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
+ self.assertEqual(flt(amount, 0),flt(accrued_interest_amount, 0))
+ self.assertEqual(flt(repayment_entry.penalty_amount, 5), 0)
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
- self.assertEquals(flt(amounts['pending_principal_amount'], 0), 50)
+ self.assertEqual(flt(amounts['pending_principal_amount'], 0), 50)
request_loan_closure(loan.name)
loan.load_from_db()
- self.assertEquals(loan.status, "Loan Closure Requested")
+ self.assertEqual(loan.status, "Loan Closure Requested")
def test_loan_amount_write_off(self):
pledge = [{
@@ -611,7 +611,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -633,17 +633,17 @@ class TestLoan(unittest.TestCase):
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
- self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
- self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
+ self.assertEqual(flt(amount, 0),flt(accrued_interest_amount, 0))
+ self.assertEqual(flt(repayment_entry.penalty_amount, 5), 0)
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
- self.assertEquals(flt(amounts['pending_principal_amount'], 0), 100)
+ self.assertEqual(flt(amounts['pending_principal_amount'], 0), 100)
we = make_loan_write_off(loan.name, amount=amounts['pending_principal_amount'])
we.submit()
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
- self.assertEquals(flt(amounts['pending_principal_amount'], 0), 0)
+ self.assertEqual(flt(amounts['pending_principal_amount'], 0), 0)
def create_loan_scenario_for_penalty(doc):
pledge = [{
diff --git a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
index a8753877a6..da56710c67 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
+++ b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
@@ -87,7 +87,7 @@ class TestLoanDisbursement(unittest.TestCase):
loan = create_demand_loan(self.applicant, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -114,5 +114,5 @@ class TestLoanDisbursement(unittest.TestCase):
per_day_interest = get_per_day_interest(1500000, 13.5, '2019-10-30')
interest = per_day_interest * 15
- self.assertEquals(amounts['pending_principal_amount'], 1500000)
- self.assertEquals(amounts['interest_amount'], flt(interest + previous_interest, 2))
+ self.assertEqual(amounts['pending_principal_amount'], 1500000)
+ self.assertEqual(amounts['interest_amount'], flt(interest + previous_interest, 2))
diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py
index 85e008ac29..eb626f3eee 100644
--- a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py
@@ -52,7 +52,7 @@ class TestLoanInterestAccrual(unittest.TestCase):
process_loan_interest_accrual_for_demand_loans(posting_date=last_date)
loan_interest_accural = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
- self.assertEquals(flt(loan_interest_accural.interest_amount, 0), flt(accrued_interest_amount, 0))
+ self.assertEqual(flt(loan_interest_accural.interest_amount, 0), flt(accrued_interest_amount, 0))
def test_accumulated_amounts(self):
pledge = [{
@@ -76,7 +76,7 @@ class TestLoanInterestAccrual(unittest.TestCase):
process_loan_interest_accrual_for_demand_loans(posting_date=last_date)
loan_interest_accrual = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
- self.assertEquals(flt(loan_interest_accrual.interest_amount, 0), flt(accrued_interest_amount, 0))
+ self.assertEqual(flt(loan_interest_accrual.interest_amount, 0), flt(accrued_interest_amount, 0))
next_start_date = '2019-10-31'
next_end_date = '2019-11-29'
@@ -90,4 +90,4 @@ class TestLoanInterestAccrual(unittest.TestCase):
loan_interest_accrual = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name,
'process_loan_interest_accrual': process})
- self.assertEquals(flt(loan_interest_accrual.total_pending_interest_amount, 0), total_pending_interest_amount)
+ self.assertEqual(flt(loan_interest_accrual.total_pending_interest_amount, 0), total_pending_interest_amount)
diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py
index 7108338dab..e1cca9e3ef 100644
--- a/erpnext/manufacturing/doctype/bom/test_bom.py
+++ b/erpnext/manufacturing/doctype/bom/test_bom.py
@@ -223,7 +223,7 @@ class TestBOM(unittest.TestCase):
is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
bom_items = sorted([d.item_code for d in bom.items if d.sourced_by_supplier != 1])
supplied_items = sorted([d.rm_item_code for d in po.supplied_items])
- self.assertEquals(bom_items, supplied_items)
+ self.assertEqual(bom_items, supplied_items)
def get_default_bom(item_code="_Test FG Item 2"):
return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1})
diff --git a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py
index ac9a409bcb..80d1cdfc8f 100644
--- a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py
+++ b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py
@@ -45,16 +45,16 @@ class TestBOMUpdateTool(unittest.TestCase):
else:
doc = frappe.get_doc("BOM", bom_no)
- self.assertEquals(doc.total_cost, 200)
+ self.assertEqual(doc.total_cost, 200)
frappe.db.set_value("Item", "BOM Cost Test Item 2", "valuation_rate", 200)
update_cost()
doc.load_from_db()
- self.assertEquals(doc.total_cost, 300)
+ self.assertEqual(doc.total_cost, 300)
frappe.db.set_value("Item", "BOM Cost Test Item 2", "valuation_rate", 100)
update_cost()
doc.load_from_db()
- self.assertEquals(doc.total_cost, 200)
+ self.assertEqual(doc.total_cost, 200)
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index 6b1fafe5f4..cb1ee92196 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -473,7 +473,7 @@ class TestWorkOrder(unittest.TestCase):
def test_cost_center_for_manufacture(self):
wo_order = make_wo_order_test_record()
ste = make_stock_entry(wo_order.name, "Material Transfer for Manufacture", wo_order.qty)
- self.assertEquals(ste.get("items")[0].get("cost_center"), "_Test Cost Center - _TC")
+ self.assertEqual(ste.get("items")[0].get("cost_center"), "_Test Cost Center - _TC")
def test_operation_time_with_batch_size(self):
fg_item = "Test Batch Size Item For BOM"
@@ -539,11 +539,11 @@ class TestWorkOrder(unittest.TestCase):
ste_cancel_list.append(ste1)
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Material Consumption for Manufacture", 2))
- self.assertEquals(ste3.fg_completed_qty, 2)
+ self.assertEqual(ste3.fg_completed_qty, 2)
expected_qty = {"_Test Item": 2, "_Test Item Home Desktop 100": 4}
for row in ste3.items:
- self.assertEquals(row.qty, expected_qty.get(row.item_code))
+ self.assertEqual(row.qty, expected_qty.get(row.item_code))
ste_cancel_list.reverse()
for ste_doc in ste_cancel_list:
ste_doc.cancel()
@@ -577,7 +577,7 @@ class TestWorkOrder(unittest.TestCase):
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
for ste_row in ste3.items:
if itemwise_qty.get(ste_row.item_code) and ste_row.s_warehouse:
- self.assertEquals(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
+ self.assertEqual(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
ste3.submit()
ste_cancel_list.append(ste3)
@@ -585,7 +585,7 @@ class TestWorkOrder(unittest.TestCase):
ste2 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
for ste_row in ste2.items:
if itemwise_qty.get(ste_row.item_code) and ste_row.s_warehouse:
- self.assertEquals(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
+ self.assertEqual(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
ste_cancel_list.reverse()
for ste_doc in ste_cancel_list:
ste_doc.cancel()
diff --git a/erpnext/non_profit/doctype/donation/test_donation.py b/erpnext/non_profit/doctype/donation/test_donation.py
index c6a534dac3..bbe9bf5228 100644
--- a/erpnext/non_profit/doctype/donation/test_donation.py
+++ b/erpnext/non_profit/doctype/donation/test_donation.py
@@ -39,7 +39,7 @@ class TestDonation(unittest.TestCase):
donation.on_payment_authorized()
donation.reload()
- self.assertEquals(donation.paid, 1)
+ self.assertEqual(donation.paid, 1)
self.assertTrue(frappe.db.exists('Payment Entry', {'reference_no': donation.name}))
diff --git a/erpnext/portal/doctype/homepage/test_homepage.py b/erpnext/portal/doctype/homepage/test_homepage.py
index bf5c4025a0..b717491a82 100644
--- a/erpnext/portal/doctype/homepage/test_homepage.py
+++ b/erpnext/portal/doctype/homepage/test_homepage.py
@@ -13,7 +13,7 @@ class TestHomepage(unittest.TestCase):
set_request(method='GET', path='home')
response = render()
- self.assertEquals(response.status_code, 200)
+ self.assertEqual(response.status_code, 200)
html = frappe.safe_decode(response.get_data())
self.assertTrue('
Date: Fri, 7 May 2021 20:30:04 +0530
Subject: [PATCH 067/149] feat!: add pick batch button (#25413)
* feat!: add pick batch button
BREAKING CHANGE: replaces setup_serial_no with setup_serial_or_batch_no.
* refactor: use setup_serial_or_batch_no instead of setup_serial_no
* refactor: use setup_serial_or_batch_no instead of setup_serial_no
* refactor: use setup_serial_or_batch_no instead of setup_serial_no
* style: add sider review changes
* refactor: make consice, extract function
* refactor: camel to snake casing
---
.../doctype/sales_invoice/sales_invoice.js | 4 +-
erpnext/public/js/utils.js | 48 ++++++++++---------
.../doctype/delivery_note/delivery_note.js | 4 +-
.../stock/doctype/stock_entry/stock_entry.js | 2 +-
4 files changed, 31 insertions(+), 27 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 8a42d9e13c..7c73ad6c90 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -356,11 +356,11 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
},
items_on_form_rendered: function() {
- erpnext.setup_serial_no();
+ erpnext.setup_serial_or_batch_no();
},
packed_items_on_form_rendered: function(doc, grid_row) {
- erpnext.setup_serial_no();
+ erpnext.setup_serial_or_batch_no();
},
make_sales_return: function() {
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 19c9073090..472746ab84 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -48,31 +48,24 @@ $.extend(erpnext, {
return cint(frappe.boot.sysdefaults.allow_stale);
},
- setup_serial_no: function() {
- var grid_row = cur_frm.open_grid_row();
- if(!grid_row || !grid_row.grid_form.fields_dict.serial_no ||
- grid_row.grid_form.fields_dict.serial_no.get_status()!=="Write") return;
+ setup_serial_or_batch_no: function() {
+ let grid_row = cur_frm.open_grid_row();
+ if (!grid_row || !grid_row.grid_form.fields_dict.serial_no ||
+ grid_row.grid_form.fields_dict.serial_no.get_status() !== "Write") return;
- var $btn = $(''+__("Add Serial No")+' ')
- .appendTo($("")
- .css({"margin-bottom": "10px", "margin-top": "10px"})
- .appendTo(grid_row.grid_form.fields_dict.serial_no.$wrapper));
+ frappe.model.get_value('Item', {'name': grid_row.doc.item_code},
+ ['has_serial_no', 'has_batch_no'], ({has_serial_no, has_batch_no}) => {
+ Object.assign(grid_row.doc, {has_serial_no, has_batch_no});
- var me = this;
- $btn.on("click", function() {
- let callback = '';
- let on_close = '';
-
- frappe.model.get_value('Item', {'name':grid_row.doc.item_code}, 'has_serial_no',
- (data) => {
- if(data) {
- grid_row.doc.has_serial_no = data.has_serial_no;
- me.show_serial_batch_selector(grid_row.frm, grid_row.doc,
- callback, on_close, true);
- }
+ if (has_serial_no) {
+ attach_selector_button(__("Add Serial No"),
+ grid_row.grid_form.fields_dict.serial_no.$wrapper, this, grid_row);
+ } else if (has_batch_no) {
+ attach_selector_button(__("Pick Batch No"),
+ grid_row.grid_form.fields_dict.batch_no.$wrapper, this, grid_row);
}
- );
- });
+ }
+ );
},
route_to_adjustment_jv: (args) => {
@@ -743,3 +736,14 @@ $(document).on('app_ready', function() {
});
}
});
+
+function attach_selector_button(inner_text, append_loction, context, grid_row) {
+ let $btn_div = $("
").css({"margin-bottom": "10px", "margin-top": "10px"})
+ .appendTo(append_loction);
+ let $btn = $(`
${inner_text} `)
+ .appendTo($btn_div);
+
+ $btn.on("click", function() {
+ context.show_serial_batch_selector(grid_row.frm, grid_row.doc, "", "", true);
+ });
+}
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index 334bdeac9d..7875b9cd87 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -273,11 +273,11 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend(
},
items_on_form_rendered: function(doc, grid_row) {
- erpnext.setup_serial_no();
+ erpnext.setup_serial_or_batch_no();
},
packed_items_on_form_rendered: function(doc, grid_row) {
- erpnext.setup_serial_no();
+ erpnext.setup_serial_or_batch_no();
},
close_delivery_note: function(doc){
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index ef7d54ac96..772c8df96e 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -996,7 +996,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
},
items_on_form_rendered: function(doc, grid_row) {
- erpnext.setup_serial_no();
+ erpnext.setup_serial_or_batch_no();
},
toggle_related_fields: function(doc) {
From 490aed2a16bce43bd3e4373628b75f3e4f46932d Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sat, 8 May 2021 00:04:34 +0530
Subject: [PATCH 068/149] chore: Debug
---
.github/workflows/patch.yml | 69 +++++++++++++++++++
.../{ci-tests.yml => server-tests.yml} | 31 +++------
2 files changed, 78 insertions(+), 22 deletions(-)
create mode 100644 .github/workflows/patch.yml
rename .github/workflows/{ci-tests.yml => server-tests.yml} (70%)
diff --git a/.github/workflows/patch.yml b/.github/workflows/patch.yml
new file mode 100644
index 0000000000..7c9e0272c9
--- /dev/null
+++ b/.github/workflows/patch.yml
@@ -0,0 +1,69 @@
+name: Patch
+
+on: [pull_request, workflow_dispatch]
+
+jobs:
+ test:
+ runs-on: ubuntu-18.04
+
+ name: Patch Test
+
+ services:
+ mysql:
+ image: mariadb:10.3
+ env:
+ MYSQL_ALLOW_EMPTY_PASSWORD: YES
+ ports:
+ - 3306:3306
+ options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
+
+ steps:
+ - name: Clone
+ uses: actions/checkout@v2
+
+ - name: Setup Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.6
+
+ - name: Add to Hosts
+ run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
+
+ - name: Cache pip
+ uses: actions/cache@v2
+ with:
+ path: ~/.cache/pip
+ key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+ restore-keys: |
+ ${{ runner.os }}-pip-
+ ${{ runner.os }}-
+
+ - name: Cache node modules
+ uses: actions/cache@v2
+ env:
+ cache-name: cache-node-modules
+ with:
+ path: ~/.npm
+ key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-build-${{ env.cache-name }}-
+ ${{ runner.os }}-build-
+ ${{ runner.os }}-
+
+ - name: Get yarn cache directory path
+ id: yarn-cache-dir-path
+ run: echo "::set-output name=dir::$(yarn cache dir)"
+
+ - uses: actions/cache@v2
+ id: yarn-cache
+ with:
+ path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
+ key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-yarn-
+
+ - name: Install
+ run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
+
+ - name: Run Patch Tests
+ run: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz && bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/server-tests.yml
similarity index 70%
rename from .github/workflows/ci-tests.yml
rename to .github/workflows/server-tests.yml
index 4d955190be..4042a407e7 100644
--- a/.github/workflows/ci-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -1,4 +1,4 @@
-name: CI
+name: Server
on: [pull_request, workflow_dispatch]
@@ -7,24 +7,12 @@ jobs:
runs-on: ubuntu-18.04
strategy:
- fail-fast: false
+ fail-fast: true
matrix:
- include:
- - TYPE: "server"
- JOB_NAME: "Server.1"
- RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext
- - TYPE: "server"
- JOB_NAME: "Server.2"
- RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext
- - TYPE: "server"
- JOB_NAME: "Server.3"
- RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext
- - TYPE: "patch"
- JOB_NAME: "Patch"
- RUN_COMMAND: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz && bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate
+ container: [1, 2]
- name: ${{ matrix.JOB_NAME }}
+ name: Server Tests
services:
mysql:
@@ -42,7 +30,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v2
with:
- python-version: 3.6
+ python-version: 3.7
- name: Add to Hosts
run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
@@ -55,6 +43,7 @@ jobs:
restore-keys: |
${{ runner.os }}-pip-
${{ runner.os }}-
+
- name: Cache node modules
uses: actions/cache@v2
env:
@@ -66,6 +55,7 @@ jobs:
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
+
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
@@ -82,12 +72,11 @@ jobs:
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
- name: Run Tests
- run: ${{ matrix.RUN_COMMAND }}
+ run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --build-number ${{ matrix.container }} --total-builds 2 --with-coverage
env:
- TYPE: ${{ matrix.TYPE }}
+ TYPE: server
- name: Upload Coverage Data
- if: matrix.TYPE == 'server'
run: |
cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
cd ${GITHUB_WORKSPACE}
@@ -113,10 +102,8 @@ jobs:
- name: Coveralls Finished
run: |
cd ${GITHUB_WORKSPACE}
- ls -al
pip3 install coverage==5.5
pip3 install coveralls==3.0.1
coveralls --finish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
From ccf6249bfb70e5614525bfa91e46fa4030674911 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sat, 8 May 2021 00:05:48 +0530
Subject: [PATCH 069/149] chore: Debug
---
.github/workflows/server-tests.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index 4042a407e7..1e9196119e 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -10,7 +10,7 @@ jobs:
fail-fast: true
matrix:
- container: [1, 2]
+ container: [1, 2, 3]
name: Server Tests
@@ -72,7 +72,7 @@ jobs:
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
- name: Run Tests
- run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --build-number ${{ matrix.container }} --total-builds 2 --with-coverage
+ run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --build-number ${{ matrix.container }} --total-builds 3 --with-coverage
env:
TYPE: server
From 622bf077e76faeba5c7006d52438b5c1508b5c86 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sat, 8 May 2021 13:51:34 +0530
Subject: [PATCH 070/149] ci: Disble failfast temporarily
---
.github/workflows/server-tests.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index 1e9196119e..0d5a3ba61a 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-18.04
strategy:
- fail-fast: true
+ fail-fast: false
matrix:
container: [1, 2, 3]
From d27e70a67aa194703f81c7d5a4a81441f632dc9b Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sat, 8 May 2021 16:02:40 +0530
Subject: [PATCH 071/149] ci: Fix coveralls
---
.github/workflows/server-tests.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index 0d5a3ba61a..e5fb72538d 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -82,12 +82,12 @@ jobs:
cd ${GITHUB_WORKSPACE}
pip3 install coverage==5.5
pip3 install coveralls==3.0.1
- coveralls --service=github-actions
+ coveralls
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
COVERALLS_FLAG_NAME: run-${{ matrix.container }}
- COVERALLS_SERVICE_NAME: github-actions
+ COVERALLS_SERVICE_NAME: ${{ github.event_name == 'pull_request' && 'github' || 'github-actions' }}
COVERALLS_PARALLEL: true
coveralls:
From aa9e1720913527aef4193a053606d5cf38a4f1cf Mon Sep 17 00:00:00 2001
From: Ganga Manoj
Date: Sat, 8 May 2021 17:15:33 +0530
Subject: [PATCH 072/149] feat: Add Create Expense Claim button in Delivery
Trip (#25526)
* feat(Delivery Trip): Add employee_code field
* feat(Expense Claim): Add Delivery Trip Number field
* feat(Delivery Trip): Add Create Expense Claim button
* feat(Delivery Trip): Make Create Expense Claim button show up after save
* fix(Delivery Trip): Fix Sider issues
* fix(Delivery Trip): Display button after submit
* fix(Delivery Trip & Expense Claim): Rename new fields
* fix(Delivery Trip): Add button in refresh
* fix(Delivery Trip): Remove redundant line
* fix(Expense Claim): Display delivery_trip only if non-empty
* fix(Delivery Trip): Add test for Create Expense Claim
* fix(Delivery Trip): Fix Sider Issue
* fix(Delivery Trip): Only display Create Expense Claim if the driver is an employee
* fix(Delivery Trip): Fix test
* fix(Delivery Trip): Fix make_expense_claim()
* fix: sider
Co-authored-by: Saqib
---
erpnext/hr/doctype/expense_claim/expense_claim.json | 10 +++++++++-
.../stock/doctype/delivery_trip/delivery_trip.js | 9 +++++++++
.../stock/doctype/delivery_trip/delivery_trip.json | 11 ++++++++++-
.../stock/doctype/delivery_trip/delivery_trip.py | 13 +++++++++++++
.../doctype/delivery_trip/test_delivery_trip.py | 6 +++++-
5 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.json b/erpnext/hr/doctype/expense_claim/expense_claim.json
index e3e6e80616..a268c15c70 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.json
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.json
@@ -14,6 +14,7 @@
"column_break_5",
"expense_approver",
"approval_status",
+ "delivery_trip",
"is_paid",
"expense_details",
"expenses",
@@ -365,13 +366,20 @@
"label": "Total Taxes and Charges",
"options": "Company:company:default_currency",
"read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.delivery_trip",
+ "fieldname": "delivery_trip",
+ "fieldtype": "Link",
+ "label": "Delivery Trip",
+ "options": "Delivery Trip"
}
],
"icon": "fa fa-money",
"idx": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-09-18 17:26:09.703215",
+ "modified": "2021-05-04 05:35:12.040199",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Claim",
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.js b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
index a6fbb66aa2..68cba2993c 100755
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.js
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
@@ -41,6 +41,15 @@ frappe.ui.form.on('Delivery Trip', {
},
refresh: function (frm) {
+ if (frm.doc.docstatus == 1 && frm.doc.employee) {
+ frm.add_custom_button(__('Expense Claim'), function() {
+ frappe.model.open_mapped_doc({
+ method: 'erpnext.stock.doctype.delivery_trip.delivery_trip.make_expense_claim',
+ frm: cur_frm,
+ });
+ }, __("Create"));
+ }
+
if (frm.doc.docstatus == 1 && frm.doc.delivery_stops.length > 0) {
frm.add_custom_button(__("Notify Customers via Email"), function () {
frm.trigger('notify_customers');
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.json b/erpnext/stock/doctype/delivery_trip/delivery_trip.json
index 879901f6a8..11b71c2076 100644
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.json
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.json
@@ -21,6 +21,7 @@
"column_break_4",
"vehicle",
"departure_time",
+ "employee",
"delivery_service_stops",
"delivery_stops",
"calculate_arrival_time",
@@ -176,11 +177,19 @@
"fieldtype": "Data",
"label": "Driver Email",
"read_only": 1
+ },
+ {
+ "fetch_from": "driver.employee",
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "label": "Employee",
+ "options": "Employee",
+ "read_only": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-01-26 22:37:14.824021",
+ "modified": "2021-04-30 21:21:36.610142",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Trip",
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.py b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
index de85bc3922..81e730126e 100644
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.py
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
@@ -11,6 +11,7 @@ from frappe import _
from frappe.contacts.doctype.address.address import get_address_display
from frappe.model.document import Document
from frappe.utils import cint, get_datetime, get_link_to_form
+from frappe.model.mapper import get_mapped_doc
class DeliveryTrip(Document):
@@ -394,3 +395,15 @@ def get_driver_email(driver):
employee = frappe.db.get_value("Driver", driver, "employee")
email = frappe.db.get_value("Employee", employee, "prefered_email")
return {"email": email}
+
+@frappe.whitelist()
+def make_expense_claim(source_name, target_doc=None):
+ doc = get_mapped_doc("Delivery Trip", source_name,
+ {"Delivery Trip": {
+ "doctype": "Expense Claim",
+ "field_map": {
+ "name" : "delivery_trip"
+ }
+ }}, target_doc)
+
+ return doc
\ No newline at end of file
diff --git a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
index eeea6da7a4..1e71603175 100644
--- a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
+++ b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
@@ -7,7 +7,7 @@ import unittest
import erpnext
import frappe
-from erpnext.stock.doctype.delivery_trip.delivery_trip import get_contact_and_address, notify_customers
+from erpnext.stock.doctype.delivery_trip.delivery_trip import get_contact_and_address, notify_customers, make_expense_claim
from erpnext.tests.utils import create_test_contact_and_address
from frappe.utils import add_days, flt, now_datetime, nowdate
@@ -28,6 +28,10 @@ class TestDeliveryTrip(unittest.TestCase):
frappe.db.sql("delete from `tabEmail Template`")
frappe.db.sql("delete from `tabDelivery Trip`")
+ def test_expense_claim_fields_are_fetched_properly(self):
+ expense_claim = make_expense_claim(self.delivery_trip.name)
+ self.assertEqual(self.delivery_trip.name, expense_claim.delivery_trip)
+
def test_delivery_trip_notify_customers(self):
notify_customers(delivery_trip=self.delivery_trip.name)
self.delivery_trip.load_from_db()
From 142ec9e99e2e077c6eb0c36b5d3c4a24b71fb5ab Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sat, 8 May 2021 19:03:53 +0530
Subject: [PATCH 073/149] test: Pass ConflictingTaxRule during tax rule test
---
erpnext/shopping_cart/test_shopping_cart.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/shopping_cart/test_shopping_cart.py b/erpnext/shopping_cart/test_shopping_cart.py
index d857bf5f5c..ac61aebc56 100644
--- a/erpnext/shopping_cart/test_shopping_cart.py
+++ b/erpnext/shopping_cart/test_shopping_cart.py
@@ -7,7 +7,7 @@ import frappe
from frappe.utils import nowdate, add_months
from erpnext.shopping_cart.cart import _get_cart_quotation, update_cart, get_party
from erpnext.tests.utils import create_test_contact_and_address
-
+from erpnext.accounts.doctype.tax_rule.tax_rule import ConflictingTaxRule
# test_dependencies = ['Payment Terms Template']
@@ -125,7 +125,7 @@ class TestShoppingCart(unittest.TestCase):
tax_rule = frappe.get_test_records("Tax Rule")[0]
try:
frappe.get_doc(tax_rule).insert()
- except frappe.DuplicateEntryError:
+ except (frappe.DuplicateEntryError, ConflictingTaxRule):
pass
def create_quotation(self):
From 7044bcfaabb54ccd6416b87404bb9a2bcc2d0cec Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sun, 9 May 2021 11:29:00 +0530
Subject: [PATCH 074/149] ci: Try parallel testing with orchestrator
---
.github/workflows/server-tests.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index e5fb72538d..0e638104c8 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -72,9 +72,10 @@ jobs:
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
- name: Run Tests
- run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --build-number ${{ matrix.container }} --total-builds 3 --with-coverage
+ run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --use-orchestrator --with-coverage
env:
TYPE: server
+ CI_BUILD_ID: ${{ github.run_id }}
- name: Upload Coverage Data
run: |
From 2ac27d774d69ebc562e6d0ec566b45e9fdfa5ee7 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sun, 9 May 2021 14:38:28 +0530
Subject: [PATCH 075/149] test: Fix test dependency
---
.../doctype/accounting_dimension/test_accounting_dimension.py | 2 +-
.../test_accounting_dimension_filter.py | 2 +-
.../doctype/accounting_period/test_accounting_period.py | 4 +++-
erpnext/tests/__init__.py | 2 +-
4 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
index 6fb661eb54..e657a9ae34 100644
--- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
@@ -8,7 +8,7 @@ import unittest
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
-test_dependencies = ['Location']
+test_dependencies = ['Cost Center', 'Location', 'Warehouse', 'Department']
class TestAccountingDimension(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py
index 78a88eb48c..7f6254f99f 100644
--- a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py
+++ b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py
@@ -9,7 +9,7 @@ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sal
from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import create_dimension, disable_dimension
from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
-test_dependencies = ['Location']
+test_dependencies = ['Location', 'Cost Center', 'Department']
class TestAccountingDimensionFilter(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
index 10cd939894..3b4f138495 100644
--- a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
+++ b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
@@ -10,6 +10,8 @@ from erpnext.accounts.general_ledger import ClosedAccountingPeriod
from erpnext.accounts.doctype.accounting_period.accounting_period import OverlapError
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+test_dependencies = ['Item']
+
class TestAccountingPeriod(unittest.TestCase):
def test_overlap(self):
ap1 = create_accounting_period(start_date = "2018-04-01",
@@ -38,7 +40,7 @@ def create_accounting_period(**args):
accounting_period.start_date = args.start_date or nowdate()
accounting_period.end_date = args.end_date or add_months(nowdate(), 1)
accounting_period.company = args.company or "_Test Company"
- accounting_period.period_name =args.period_name or "_Test_Period_Name_1"
+ accounting_period.period_name = args.period_name or "_Test_Period_Name_1"
accounting_period.append("closed_documents", {
"document_type": 'Sales Invoice', "closed": 1
})
diff --git a/erpnext/tests/__init__.py b/erpnext/tests/__init__.py
index 593bc7c71b..a504340d40 100644
--- a/erpnext/tests/__init__.py
+++ b/erpnext/tests/__init__.py
@@ -1 +1 @@
-global_test_dependencies = ['User', 'Company', 'Cost Center', 'Account', 'Warehouse', 'Item']
+global_test_dependencies = ['User', 'Company', 'Item']
From dfb8aa017d4c9d1a8f3d24d8b05a5949c673e525 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sun, 9 May 2021 14:38:54 +0530
Subject: [PATCH 076/149] ci: Check limits
---
.github/workflows/server-tests.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index 0e638104c8..e7830c07f6 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -10,7 +10,7 @@ jobs:
fail-fast: false
matrix:
- container: [1, 2, 3]
+ container: [1, 2, 3, 4]
name: Server Tests
@@ -30,7 +30,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v2
with:
- python-version: 3.7
+ python-version: 3.6
- name: Add to Hosts
run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
From ec6b652cd4f572356073fd9ab5098c21af67cb3b Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 10 May 2021 09:18:25 +0530
Subject: [PATCH 077/149] refactor: Rename assertEquals to assertEqual to avoid
deprecation warnings
---
.../accounts/doctype/dunning/test_dunning.py | 8 +-
.../doctype/gl_entry/test_gl_entry.py | 2 +-
.../payment_order/test_payment_order.py | 8 +-
.../doctype/pricing_rule/pricing_rule.py | 2 +-
.../doctype/pricing_rule/test_pricing_rule.py | 36 +++----
erpnext/assets/doctype/asset/test_asset.py | 6 +-
.../purchase_order/test_purchase_order.py | 42 ++++----
.../mpesa_settings/test_mpesa_settings.py | 30 +++---
.../test_clinical_procedure.py | 2 +-
.../doctype/lab_test/test_lab_test.py | 4 +-
.../test_patient_appointment.py | 8 +-
.../doctype/therapy_plan/test_therapy_plan.py | 14 +--
.../doctype/therapy_type/test_therapy_type.py | 2 +-
.../test_compensatory_leave_request.py | 16 ++--
.../expense_claim/test_expense_claim.py | 12 +--
.../hr/doctype/job_offer/test_job_offer.py | 4 +-
.../leave_allocation/test_leave_allocation.py | 14 +--
.../test_leave_application.py | 18 ++--
.../leave_encashment/test_leave_encashment.py | 8 +-
.../loan_management/doctype/loan/test_loan.py | 96 +++++++++----------
.../test_loan_disbursement.py | 6 +-
.../test_loan_interest_accrual.py | 6 +-
erpnext/manufacturing/doctype/bom/test_bom.py | 2 +-
.../bom_update_tool/test_bom_update_tool.py | 6 +-
.../doctype/work_order/test_work_order.py | 10 +-
.../doctype/donation/test_donation.py | 2 +-
.../portal/doctype/homepage/test_homepage.py | 2 +-
.../homepage_section/test_homepage_section.py | 4 +-
.../test_tax_exemption_80g_certificate.py | 12 +--
erpnext/regional/india/utils.py | 2 +-
.../doctype/quotation/test_quotation.py | 2 +-
.../doctype/sales_order/test_sales_order.py | 4 +-
.../delivery_note/test_delivery_note.py | 6 +-
.../purchase_receipt/test_purchase_receipt.py | 10 +-
erpnext/support/doctype/issue/test_issue.py | 28 +++---
35 files changed, 217 insertions(+), 217 deletions(-)
diff --git a/erpnext/accounts/doctype/dunning/test_dunning.py b/erpnext/accounts/doctype/dunning/test_dunning.py
index cb18309e3c..e2d4d82e41 100644
--- a/erpnext/accounts/doctype/dunning/test_dunning.py
+++ b/erpnext/accounts/doctype/dunning/test_dunning.py
@@ -29,7 +29,7 @@ class TestDunning(unittest.TestCase):
self.assertEqual(round(amounts.get('interest_amount'), 2), 0.44)
self.assertEqual(round(amounts.get('dunning_amount'), 2), 20.44)
self.assertEqual(round(amounts.get('grand_total'), 2), 120.44)
-
+
def test_gl_entries(self):
dunning = create_dunning()
dunning.submit()
@@ -42,9 +42,9 @@ class TestDunning(unittest.TestCase):
['Sales - _TC', 0.0, 20.44]
])
for gle in gl_entries:
- self.assertEquals(expected_values[gle.account][0], gle.account)
- self.assertEquals(expected_values[gle.account][1], gle.debit)
- self.assertEquals(expected_values[gle.account][2], gle.credit)
+ self.assertEqual(expected_values[gle.account][0], gle.account)
+ self.assertEqual(expected_values[gle.account][1], gle.debit)
+ self.assertEqual(expected_values[gle.account][2], gle.credit)
def test_payment_entry(self):
dunning = create_dunning()
diff --git a/erpnext/accounts/doctype/gl_entry/test_gl_entry.py b/erpnext/accounts/doctype/gl_entry/test_gl_entry.py
index b4a547b21b..4167ca70df 100644
--- a/erpnext/accounts/doctype/gl_entry/test_gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/test_gl_entry.py
@@ -54,4 +54,4 @@ class TestGLEntry(unittest.TestCase):
self.assertTrue(all(new.name != old.name for new, old in zip(gl_entries, new_gl_entries)))
new_naming_series_current_value = frappe.db.sql("SELECT current from tabSeries where name = %s", naming_series)[0][0]
- self.assertEquals(old_naming_series_current_value + 2, new_naming_series_current_value)
+ self.assertEqual(old_naming_series_current_value + 2, new_naming_series_current_value)
diff --git a/erpnext/accounts/doctype/payment_order/test_payment_order.py b/erpnext/accounts/doctype/payment_order/test_payment_order.py
index 1c23e2a0ec..5fdde07faa 100644
--- a/erpnext/accounts/doctype/payment_order/test_payment_order.py
+++ b/erpnext/accounts/doctype/payment_order/test_payment_order.py
@@ -31,10 +31,10 @@ class TestPaymentOrder(unittest.TestCase):
doc = create_payment_order_against_payment_entry(payment_entry, "Payment Entry")
reference_doc = doc.get("references")[0]
- self.assertEquals(reference_doc.reference_name, payment_entry.name)
- self.assertEquals(reference_doc.reference_doctype, "Payment Entry")
- self.assertEquals(reference_doc.supplier, "_Test Supplier")
- self.assertEquals(reference_doc.amount, 250)
+ self.assertEqual(reference_doc.reference_name, payment_entry.name)
+ self.assertEqual(reference_doc.reference_doctype, "Payment Entry")
+ self.assertEqual(reference_doc.supplier, "_Test Supplier")
+ self.assertEqual(reference_doc.amount, 250)
def create_payment_order_against_payment_entry(ref_doc, order_type):
payment_order = frappe.get_doc(dict(
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index aedf1c6f1a..556f49d34c 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -152,7 +152,7 @@ class PricingRule(Document):
frappe.throw(_("Valid from date must be less than valid upto date"))
def validate_condition(self):
- if self.condition and ("=" in self.condition) and re.match("""[\w\.:_]+\s*={1}\s*[\w\.@'"]+""", self.condition):
+ if self.condition and ("=" in self.condition) and re.match(r'[\w\.:_]+\s*={1}\s*[\w\.@\'"]+', self.condition):
frappe.throw(_("Invalid condition expression"))
#--------------------------------------------------------------------------------
diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
index ef9aad562d..ffe8be1162 100644
--- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
@@ -99,7 +99,7 @@ class TestPricingRule(unittest.TestCase):
args.item_code = "_Test Item 2"
details = get_item_details(args)
- self.assertEquals(details.get("discount_percentage"), 15)
+ self.assertEqual(details.get("discount_percentage"), 15)
def test_pricing_rule_for_margin(self):
from erpnext.stock.get_item_details import get_item_details
@@ -145,8 +145,8 @@ class TestPricingRule(unittest.TestCase):
"name": None
})
details = get_item_details(args)
- self.assertEquals(details.get("margin_type"), "Percentage")
- self.assertEquals(details.get("margin_rate_or_amount"), 10)
+ self.assertEqual(details.get("margin_type"), "Percentage")
+ self.assertEqual(details.get("margin_rate_or_amount"), 10)
def test_mixed_conditions_for_item_group(self):
for item in ["Mixed Cond Item 1", "Mixed Cond Item 2"]:
@@ -192,7 +192,7 @@ class TestPricingRule(unittest.TestCase):
"name": None
})
details = get_item_details(args)
- self.assertEquals(details.get("discount_percentage"), 10)
+ self.assertEqual(details.get("discount_percentage"), 10)
def test_pricing_rule_for_variants(self):
from erpnext.stock.get_item_details import get_item_details
@@ -322,11 +322,11 @@ class TestPricingRule(unittest.TestCase):
si.insert(ignore_permissions=True)
item = si.items[0]
- self.assertEquals(item.margin_rate_or_amount, 10)
- self.assertEquals(item.rate_with_margin, 1100)
+ self.assertEqual(item.margin_rate_or_amount, 10)
+ self.assertEqual(item.rate_with_margin, 1100)
self.assertEqual(item.discount_percentage, 10)
- self.assertEquals(item.discount_amount, 110)
- self.assertEquals(item.rate, 990)
+ self.assertEqual(item.discount_amount, 110)
+ self.assertEqual(item.rate, 990)
def test_pricing_rule_with_margin_and_discount_amount(self):
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
@@ -338,10 +338,10 @@ class TestPricingRule(unittest.TestCase):
si.insert(ignore_permissions=True)
item = si.items[0]
- self.assertEquals(item.margin_rate_or_amount, 10)
- self.assertEquals(item.rate_with_margin, 1100)
- self.assertEquals(item.discount_amount, 110)
- self.assertEquals(item.rate, 990)
+ self.assertEqual(item.margin_rate_or_amount, 10)
+ self.assertEqual(item.rate_with_margin, 1100)
+ self.assertEqual(item.discount_amount, 110)
+ self.assertEqual(item.rate, 990)
def test_pricing_rule_for_product_discount_on_same_item(self):
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
@@ -458,21 +458,21 @@ class TestPricingRule(unittest.TestCase):
si.items[0].price_list_rate = 1000
si.submit()
item = si.items[0]
- self.assertEquals(item.rate, 100)
+ self.assertEqual(item.rate, 100)
# Correct Customer and Incorrect is_return value
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=1, qty=-1)
si.items[0].price_list_rate = 1000
si.submit()
item = si.items[0]
- self.assertEquals(item.rate, 100)
+ self.assertEqual(item.rate, 100)
# Correct Customer and correct is_return value
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=0)
si.items[0].price_list_rate = 1000
si.submit()
item = si.items[0]
- self.assertEquals(item.rate, 900)
+ self.assertEqual(item.rate, 900)
def test_multiple_pricing_rules(self):
make_pricing_rule(discount_percentage=20, selling=1, priority=1, apply_multiple_pricing_rules=1,
@@ -545,11 +545,11 @@ class TestPricingRule(unittest.TestCase):
apply_on="Transaction", free_item="Water Flask 1", free_qty=1, free_item_rate=10)
si = create_sales_invoice(qty=5, do_not_submit=True)
- self.assertEquals(len(si.items), 2)
- self.assertEquals(si.items[1].rate, 10)
+ self.assertEqual(len(si.items), 2)
+ self.assertEqual(si.items[1].rate, 10)
si1 = create_sales_invoice(qty=2, do_not_submit=True)
- self.assertEquals(len(si1.items), 1)
+ self.assertEqual(len(si1.items), 1)
for doc in [si, si1]:
doc.delete()
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index a0d76031fc..f12a33dd2b 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -78,7 +78,7 @@ class TestAsset(unittest.TestCase):
})
doc.set_missing_values()
- self.assertEquals(doc.items[0].is_fixed_asset, 1)
+ self.assertEqual(doc.items[0].is_fixed_asset, 1)
def test_schedule_for_straight_line_method(self):
pr = make_purchase_receipt(item_code="Macbook Pro",
@@ -565,8 +565,8 @@ class TestAsset(unittest.TestCase):
doc = make_invoice(pr.name)
- self.assertEquals('Asset Received But Not Billed - _TC', doc.items[0].expense_account)
-
+ self.assertEqual('Asset Received But Not Billed - _TC', doc.items[0].expense_account)
+
def test_asset_cwip_toggling_cases(self):
cwip = frappe.db.get_value("Asset Category", "Computers", "enable_cwip_accounting")
name = frappe.db.get_value("Asset Category Account", filters={"parent": "Computers"}, fieldname=["name"])
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 42f4472f29..aaa98f2f1f 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -187,7 +187,7 @@ class TestPurchaseOrder(unittest.TestCase):
update_child_qty_rate('Purchase Order', trans_item, po.name)
po.reload()
- self.assertEquals(len(po.get('items')), 2)
+ self.assertEqual(len(po.get('items')), 2)
self.assertEqual(po.status, 'To Receive and Bill')
# ordered qty should increase on row addition
self.assertEqual(get_ordered_qty(), existing_ordered_qty + 7)
@@ -234,7 +234,7 @@ class TestPurchaseOrder(unittest.TestCase):
update_child_qty_rate('Purchase Order', trans_item, po.name)
po.reload()
- self.assertEquals(len(po.get('items')), 1)
+ self.assertEqual(len(po.get('items')), 1)
self.assertEqual(po.status, 'To Receive and Bill')
# ordered qty should decrease (back to initial) on row deletion
@@ -448,13 +448,13 @@ class TestPurchaseOrder(unittest.TestCase):
pi.load_from_db()
- self.assertEquals(pi.per_received, 100.00)
- self.assertEquals(pi.items[0].qty, pi.items[0].received_qty)
+ self.assertEqual(pi.per_received, 100.00)
+ self.assertEqual(pi.items[0].qty, pi.items[0].received_qty)
po.load_from_db()
- self.assertEquals(po.per_received, 100.00)
- self.assertEquals(po.per_billed, 100.00)
+ self.assertEqual(po.per_received, 100.00)
+ self.assertEqual(po.per_billed, 100.00)
pr.cancel()
@@ -674,8 +674,8 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname=["reserved_qty_for_sub_contract", "projected_qty"], as_dict=1)
- self.assertEquals(bin2.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
- self.assertEquals(bin2.projected_qty, bin1.projected_qty - 10)
+ self.assertEqual(bin2.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
+ self.assertEqual(bin2.projected_qty, bin1.projected_qty - 10)
# Create stock transfer
rm_item = [{"item_code":"_Test FG Item","rm_item_code":"_Test Item","item_name":"_Test Item",
@@ -690,7 +690,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin3.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
+ self.assertEqual(bin3.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
# close PO
po.update_status("Closed")
@@ -698,7 +698,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin4.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
+ self.assertEqual(bin4.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
# Re-open PO
po.update_status("Submitted")
@@ -706,7 +706,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin5.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
+ self.assertEqual(bin5.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
make_stock_entry(target="_Test Warehouse 1 - _TC", item_code="_Test Item",
qty=40, basic_rate=100)
@@ -723,7 +723,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin6.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
+ self.assertEqual(bin6.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
# Cancel PR
pr.cancel()
@@ -731,7 +731,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin7.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
+ self.assertEqual(bin7.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
# Make Purchase Invoice
pi = make_pi_from_po(po.name)
@@ -743,7 +743,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin8.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
+ self.assertEqual(bin8.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
# Cancel PR
pi.cancel()
@@ -751,7 +751,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin9.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
+ self.assertEqual(bin9.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
# Cancel Stock Entry
se.cancel()
@@ -759,7 +759,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin10.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
+ self.assertEqual(bin10.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
# Cancel PO
po.reload()
@@ -768,7 +768,7 @@ class TestPurchaseOrder(unittest.TestCase):
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
- self.assertEquals(bin11.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
+ self.assertEqual(bin11.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
def test_exploded_items_in_subcontracted(self):
item_code = "_Test Subcontracted FG Item 1"
@@ -782,7 +782,7 @@ class TestPurchaseOrder(unittest.TestCase):
exploded_items = sorted([d.item_code for d in bom.exploded_items if not d.get('sourced_by_supplier')])
supplied_items = sorted([d.rm_item_code for d in po.supplied_items])
- self.assertEquals(exploded_items, supplied_items)
+ self.assertEqual(exploded_items, supplied_items)
po1 = create_purchase_order(item_code=item_code, qty=1,
is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC", include_exploded_items=0)
@@ -790,7 +790,7 @@ class TestPurchaseOrder(unittest.TestCase):
supplied_items1 = sorted([d.rm_item_code for d in po1.supplied_items])
bom_items = sorted([d.item_code for d in bom.items if not d.get('sourced_by_supplier')])
- self.assertEquals(supplied_items1, bom_items)
+ self.assertEqual(supplied_items1, bom_items)
def test_backflush_based_on_stock_entry(self):
item_code = "_Test Subcontracted FG Item 1"
@@ -840,8 +840,8 @@ class TestPurchaseOrder(unittest.TestCase):
transferred_items = sorted([d.item_code for d in se.get('items') if se.purchase_order == po.name])
issued_items = sorted([d.rm_item_code for d in pr.get('supplied_items')])
- self.assertEquals(transferred_items, issued_items)
- self.assertEquals(pr.get('items')[0].rm_supp_cost, 2000)
+ self.assertEqual(transferred_items, issued_items)
+ self.assertEqual(pr.get('items')[0].rm_supp_cost, 2000)
transferred_rm_map = frappe._dict()
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
index 29487962f6..3c2e59ab82 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
@@ -19,7 +19,7 @@ class TestMpesaSettings(unittest.TestCase):
mode_of_payment = frappe.get_doc("Mode of Payment", "Mpesa-_Test")
self.assertTrue(frappe.db.exists("Payment Gateway Account", {'payment_gateway': "Mpesa-_Test"}))
self.assertTrue(mode_of_payment.name)
- self.assertEquals(mode_of_payment.type, "Phone")
+ self.assertEqual(mode_of_payment.type, "Phone")
def test_processing_of_account_balance(self):
mpesa_doc = create_mpesa_settings(payment_gateway_name="_Account Balance")
@@ -31,11 +31,11 @@ class TestMpesaSettings(unittest.TestCase):
# test integration request creation and successful update of the status on receiving callback response
self.assertTrue(integration_request)
- self.assertEquals(integration_request.status, "Completed")
+ self.assertEqual(integration_request.status, "Completed")
# test formatting of account balance received as string to json with appropriate currency symbol
mpesa_doc.reload()
- self.assertEquals(mpesa_doc.account_balance, dumps({
+ self.assertEqual(mpesa_doc.account_balance, dumps({
"Working Account": {
"current_balance": "Sh 481,000.00",
"available_balance": "Sh 481,000.00",
@@ -60,7 +60,7 @@ class TestMpesaSettings(unittest.TestCase):
pr = pos_invoice.create_payment_request()
# test payment request creation
- self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
+ self.assertEqual(pr.payment_gateway, "Mpesa-Payment")
# submitting payment request creates integration requests with random id
integration_req_ids = frappe.get_all("Integration Request", filters={
@@ -75,13 +75,13 @@ class TestMpesaSettings(unittest.TestCase):
# test integration request creation and successful update of the status on receiving callback response
self.assertTrue(integration_request)
- self.assertEquals(integration_request.status, "Completed")
+ self.assertEqual(integration_request.status, "Completed")
pos_invoice.reload()
integration_request.reload()
- self.assertEquals(pos_invoice.mpesa_receipt_number, "LGR7OWQX0R")
- self.assertEquals(integration_request.status, "Completed")
-
+ self.assertEqual(pos_invoice.mpesa_receipt_number, "LGR7OWQX0R")
+ self.assertEqual(integration_request.status, "Completed")
+
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
integration_request.delete()
pr.reload()
@@ -104,7 +104,7 @@ class TestMpesaSettings(unittest.TestCase):
pr = pos_invoice.create_payment_request()
# test payment request creation
- self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
+ self.assertEqual(pr.payment_gateway, "Mpesa-Payment")
# submitting payment request creates integration requests with random id
integration_req_ids = frappe.get_all("Integration Request", filters={
@@ -126,12 +126,12 @@ class TestMpesaSettings(unittest.TestCase):
verify_transaction(**callback_response)
# test completion of integration request
integration_request = frappe.get_doc("Integration Request", integration_req_ids[i])
- self.assertEquals(integration_request.status, "Completed")
+ self.assertEqual(integration_request.status, "Completed")
integration_requests.append(integration_request)
# check receipt number once all the integration requests are completed
pos_invoice.reload()
- self.assertEquals(pos_invoice.mpesa_receipt_number, ', '.join(mpesa_receipt_numbers))
+ self.assertEqual(pos_invoice.mpesa_receipt_number, ', '.join(mpesa_receipt_numbers))
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
[d.delete() for d in integration_requests]
@@ -139,7 +139,7 @@ class TestMpesaSettings(unittest.TestCase):
pr.cancel()
pr.delete()
pos_invoice.delete()
-
+
def test_processing_of_only_one_succes_callback_payload(self):
create_mpesa_settings(payment_gateway_name="Payment")
mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account")
@@ -155,7 +155,7 @@ class TestMpesaSettings(unittest.TestCase):
pr = pos_invoice.create_payment_request()
# test payment request creation
- self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
+ self.assertEqual(pr.payment_gateway, "Mpesa-Payment")
# submitting payment request creates integration requests with random id
integration_req_ids = frappe.get_all("Integration Request", filters={
@@ -175,7 +175,7 @@ class TestMpesaSettings(unittest.TestCase):
verify_transaction(**callback_response)
# test completion of integration request
integration_request = frappe.get_doc("Integration Request", integration_req_ids[0])
- self.assertEquals(integration_request.status, "Completed")
+ self.assertEqual(integration_request.status, "Completed")
# now one request is completed
# second integration request fails
@@ -187,7 +187,7 @@ class TestMpesaSettings(unittest.TestCase):
'name': ['not in', integration_req_ids]
}, pluck="name")
- self.assertEquals(len(new_integration_req_ids), 1)
+ self.assertEqual(len(new_integration_req_ids), 1)
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
frappe.db.sql("delete from `tabIntegration Request` where integration_request_service = 'Mpesa'")
diff --git a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
index fb72073a07..03e96a4b3b 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
@@ -17,7 +17,7 @@ class TestClinicalProcedure(unittest.TestCase):
procedure_template.disabled = 1
procedure_template.save()
- self.assertEquals(frappe.db.get_value('Item', procedure_template.item, 'disabled'), 1)
+ self.assertEqual(frappe.db.get_value('Item', procedure_template.item, 'disabled'), 1)
def test_consumables(self):
patient, medical_department, practitioner = create_healthcare_docs()
diff --git a/erpnext/healthcare/doctype/lab_test/test_lab_test.py b/erpnext/healthcare/doctype/lab_test/test_lab_test.py
index 79ab8a4d7f..c9f0029ed8 100644
--- a/erpnext/healthcare/doctype/lab_test/test_lab_test.py
+++ b/erpnext/healthcare/doctype/lab_test/test_lab_test.py
@@ -18,7 +18,7 @@ class TestLabTest(unittest.TestCase):
lab_template.disabled = 1
lab_template.save()
- self.assertEquals(frappe.db.get_value('Item', lab_template.item, 'disabled'), 1)
+ self.assertEqual(frappe.db.get_value('Item', lab_template.item, 'disabled'), 1)
lab_template.reload()
@@ -57,7 +57,7 @@ class TestLabTest(unittest.TestCase):
# sample collection should not be created
lab_test.reload()
- self.assertEquals(lab_test.sample, None)
+ self.assertEqual(lab_test.sample, None)
def test_create_lab_tests_from_sales_invoice(self):
sales_invoice = create_sales_invoice()
diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
index 2bb8a53c45..5f2dc480a1 100644
--- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
@@ -20,13 +20,13 @@ class TestPatientAppointment(unittest.TestCase):
patient, medical_department, practitioner = create_healthcare_docs()
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 0)
appointment = create_appointment(patient, practitioner, nowdate())
- self.assertEquals(appointment.status, 'Open')
+ self.assertEqual(appointment.status, 'Open')
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2))
- self.assertEquals(appointment.status, 'Scheduled')
+ self.assertEqual(appointment.status, 'Scheduled')
encounter = create_encounter(appointment)
- self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
+ self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
encounter.cancel()
- self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
+ self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
def test_start_encounter(self):
patient, medical_department, practitioner = create_healthcare_docs()
diff --git a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
index 7fb159d6b5..113fa513f9 100644
--- a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
+++ b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
@@ -18,24 +18,24 @@ class TestTherapyPlan(unittest.TestCase):
def test_status(self):
plan = create_therapy_plan()
- self.assertEquals(plan.status, 'Not Started')
+ self.assertEqual(plan.status, 'Not Started')
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
frappe.get_doc(session).submit()
- self.assertEquals(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'In Progress')
+ self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'In Progress')
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
frappe.get_doc(session).submit()
- self.assertEquals(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed')
+ self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed')
patient, medical_department, practitioner = create_healthcare_docs()
- appointment = create_appointment(patient, practitioner, nowdate())
+ appointment = create_appointment(patient, practitioner, nowdate())
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company', appointment.name)
session = frappe.get_doc(session)
session.submit()
- self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
+ self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
session.cancel()
- self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
+ self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
def test_therapy_plan_from_template(self):
patient = create_patient()
@@ -49,7 +49,7 @@ class TestTherapyPlan(unittest.TestCase):
si.save()
therapy_plan_template_amt = frappe.db.get_value('Therapy Plan Template', template, 'total_amount')
- self.assertEquals(si.items[0].amount, therapy_plan_template_amt)
+ self.assertEqual(si.items[0].amount, therapy_plan_template_amt)
def create_therapy_plan(template=None):
diff --git a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py b/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
index 03a1be8a4e..21f6369975 100644
--- a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
+++ b/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
@@ -13,7 +13,7 @@ class TestTherapyType(unittest.TestCase):
therapy_type.disabled = 1
therapy_type.save()
- self.assertEquals(frappe.db.get_value('Item', therapy_type.item, 'disabled'), 1)
+ self.assertEqual(frappe.db.get_value('Item', therapy_type.item, 'disabled'), 1)
def create_therapy_type():
exercise = create_exercise_type()
diff --git a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py b/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py
index 74ce30108f..3b99c57051 100644
--- a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py
+++ b/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py
@@ -68,19 +68,19 @@ class TestCompensatoryLeaveRequest(unittest.TestCase):
filters = dict(transaction_name=compensatory_leave_request.leave_allocation)
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=filters)
- self.assertEquals(len(leave_ledger_entry), 1)
- self.assertEquals(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
- self.assertEquals(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
- self.assertEquals(leave_ledger_entry[0].leaves, 1)
+ self.assertEqual(len(leave_ledger_entry), 1)
+ self.assertEqual(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
+ self.assertEqual(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
+ self.assertEqual(leave_ledger_entry[0].leaves, 1)
# check reverse leave ledger entry on cancellation
compensatory_leave_request.cancel()
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=filters, order_by = 'creation desc')
- self.assertEquals(len(leave_ledger_entry), 2)
- self.assertEquals(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
- self.assertEquals(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
- self.assertEquals(leave_ledger_entry[0].leaves, -1)
+ self.assertEqual(len(leave_ledger_entry), 2)
+ self.assertEqual(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
+ self.assertEqual(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
+ self.assertEqual(leave_ledger_entry[0].leaves, -1)
def get_compensatory_leave_request(employee, leave_date=today()):
prev_comp_leave_req = frappe.db.get_value('Compensatory Leave Request',
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
index 3f22ca2141..578eccf787 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
@@ -88,9 +88,9 @@ class TestExpenseClaim(unittest.TestCase):
])
for gle in gl_entries:
- self.assertEquals(expected_values[gle.account][0], gle.account)
- self.assertEquals(expected_values[gle.account][1], gle.debit)
- self.assertEquals(expected_values[gle.account][2], gle.credit)
+ self.assertEqual(expected_values[gle.account][0], gle.account)
+ self.assertEqual(expected_values[gle.account][1], gle.debit)
+ self.assertEqual(expected_values[gle.account][2], gle.credit)
def test_rejected_expense_claim(self):
payable_account = get_payable_account(company_name)
@@ -104,11 +104,11 @@ class TestExpenseClaim(unittest.TestCase):
})
expense_claim.submit()
- self.assertEquals(expense_claim.status, 'Rejected')
- self.assertEquals(expense_claim.total_sanctioned_amount, 0.0)
+ self.assertEqual(expense_claim.status, 'Rejected')
+ self.assertEqual(expense_claim.total_sanctioned_amount, 0.0)
gl_entry = frappe.get_all('GL Entry', {'voucher_type': 'Expense Claim', 'voucher_no': expense_claim.name})
- self.assertEquals(len(gl_entry), 0)
+ self.assertEqual(len(gl_entry), 0)
def test_expense_approver_perms(self):
user = "test_approver_perm_emp@example.com"
diff --git a/erpnext/hr/doctype/job_offer/test_job_offer.py b/erpnext/hr/doctype/job_offer/test_job_offer.py
index 690a692ddc..b3e1dc8d87 100644
--- a/erpnext/hr/doctype/job_offer/test_job_offer.py
+++ b/erpnext/hr/doctype/job_offer/test_job_offer.py
@@ -35,13 +35,13 @@ class TestJobOffer(unittest.TestCase):
job_offer = create_job_offer(job_applicant=job_applicant.name)
job_offer.submit()
job_applicant.reload()
- self.assertEquals(job_applicant.status, "Accepted")
+ self.assertEqual(job_applicant.status, "Accepted")
# status update after rejection
job_offer.status = "Rejected"
job_offer.submit()
job_applicant.reload()
- self.assertEquals(job_applicant.status, "Rejected")
+ self.assertEqual(job_applicant.status, "Rejected")
def create_job_offer(**args):
args = frappe._dict(args)
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index 0b71036c86..6e7ae87d08 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -96,7 +96,7 @@ class TestLeaveAllocation(unittest.TestCase):
carry_forward=1)
leave_allocation_1.submit()
- self.assertEquals(leave_allocation_1.unused_leaves, 10)
+ self.assertEqual(leave_allocation_1.unused_leaves, 10)
leave_allocation_1.cancel()
@@ -108,7 +108,7 @@ class TestLeaveAllocation(unittest.TestCase):
new_leaves_allocated=25)
leave_allocation_2.submit()
- self.assertEquals(leave_allocation_2.unused_leaves, 5)
+ self.assertEqual(leave_allocation_2.unused_leaves, 5)
def test_carry_forward_leaves_expiry(self):
frappe.db.sql("delete from `tabLeave Allocation`")
@@ -145,7 +145,7 @@ class TestLeaveAllocation(unittest.TestCase):
to_date=add_months(nowdate(), 12))
leave_allocation_1.submit()
- self.assertEquals(leave_allocation_1.unused_leaves, leave_allocation.new_leaves_allocated)
+ self.assertEqual(leave_allocation_1.unused_leaves, leave_allocation.new_leaves_allocated)
def test_creation_of_leave_ledger_entry_on_submit(self):
frappe.db.sql("delete from `tabLeave Allocation`")
@@ -155,10 +155,10 @@ class TestLeaveAllocation(unittest.TestCase):
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_allocation.name))
- self.assertEquals(len(leave_ledger_entry), 1)
- self.assertEquals(leave_ledger_entry[0].employee, leave_allocation.employee)
- self.assertEquals(leave_ledger_entry[0].leave_type, leave_allocation.leave_type)
- self.assertEquals(leave_ledger_entry[0].leaves, leave_allocation.new_leaves_allocated)
+ self.assertEqual(len(leave_ledger_entry), 1)
+ self.assertEqual(leave_ledger_entry[0].employee, leave_allocation.employee)
+ self.assertEqual(leave_ledger_entry[0].leave_type, leave_allocation.leave_type)
+ self.assertEqual(leave_ledger_entry[0].leaves, leave_allocation.new_leaves_allocated)
# check if leave ledger entry is deleted on cancellation
leave_allocation.cancel()
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index b54c9712c8..a9379e230b 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -516,9 +516,9 @@ class TestLeaveApplication(unittest.TestCase):
leave_application.submit()
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_application.name))
- self.assertEquals(leave_ledger_entry[0].employee, leave_application.employee)
- self.assertEquals(leave_ledger_entry[0].leave_type, leave_application.leave_type)
- self.assertEquals(leave_ledger_entry[0].leaves, leave_application.total_leave_days * -1)
+ self.assertEqual(leave_ledger_entry[0].employee, leave_application.employee)
+ self.assertEqual(leave_ledger_entry[0].leave_type, leave_application.leave_type)
+ self.assertEqual(leave_ledger_entry[0].leaves, leave_application.total_leave_days * -1)
# check if leave ledger entry is deleted on cancellation
leave_application.cancel()
@@ -549,11 +549,11 @@ class TestLeaveApplication(unittest.TestCase):
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', '*', filters=dict(transaction_name=leave_application.name))
- self.assertEquals(len(leave_ledger_entry), 2)
- self.assertEquals(leave_ledger_entry[0].employee, leave_application.employee)
- self.assertEquals(leave_ledger_entry[0].leave_type, leave_application.leave_type)
- self.assertEquals(leave_ledger_entry[0].leaves, -9)
- self.assertEquals(leave_ledger_entry[1].leaves, -2)
+ self.assertEqual(len(leave_ledger_entry), 2)
+ self.assertEqual(leave_ledger_entry[0].employee, leave_application.employee)
+ self.assertEqual(leave_ledger_entry[0].leave_type, leave_application.leave_type)
+ self.assertEqual(leave_ledger_entry[0].leaves, -9)
+ self.assertEqual(leave_ledger_entry[1].leaves, -2)
def test_leave_application_creation_after_expiry(self):
# test leave balance for carry forwarded allocation
@@ -566,7 +566,7 @@ class TestLeaveApplication(unittest.TestCase):
create_carry_forwarded_allocation(employee, leave_type)
- self.assertEquals(get_leave_balance_on(employee.name, leave_type.name, add_days(nowdate(), -85), add_days(nowdate(), -84)), 0)
+ self.assertEqual(get_leave_balance_on(employee.name, leave_type.name, add_days(nowdate(), -85), add_days(nowdate(), -84)), 0)
def test_leave_approver_perms(self):
employee = get_employee()
diff --git a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
index aafc9642d4..1f7fb6e68a 100644
--- a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
@@ -88,10 +88,10 @@ class TestLeaveEncashment(unittest.TestCase):
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_encashment.name))
- self.assertEquals(len(leave_ledger_entry), 1)
- self.assertEquals(leave_ledger_entry[0].employee, leave_encashment.employee)
- self.assertEquals(leave_ledger_entry[0].leave_type, leave_encashment.leave_type)
- self.assertEquals(leave_ledger_entry[0].leaves, leave_encashment.encashable_days * -1)
+ self.assertEqual(len(leave_ledger_entry), 1)
+ self.assertEqual(leave_ledger_entry[0].employee, leave_encashment.employee)
+ self.assertEqual(leave_ledger_entry[0].leave_type, leave_encashment.leave_type)
+ self.assertEqual(leave_ledger_entry[0].leaves, leave_encashment.encashable_days * -1)
# check if leave ledger entry is deleted on cancellation
diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py
index fae6f860b6..fa4707ce2b 100644
--- a/erpnext/loan_management/doctype/loan/test_loan.py
+++ b/erpnext/loan_management/doctype/loan/test_loan.py
@@ -55,9 +55,9 @@ class TestLoan(unittest.TestCase):
def test_loan(self):
loan = frappe.get_doc("Loan", {"applicant":self.applicant1})
- self.assertEquals(loan.monthly_repayment_amount, 15052)
- self.assertEquals(flt(loan.total_interest_payable, 0), 21034)
- self.assertEquals(flt(loan.total_payment, 0), 301034)
+ self.assertEqual(loan.monthly_repayment_amount, 15052)
+ self.assertEqual(flt(loan.total_interest_payable, 0), 21034)
+ self.assertEqual(flt(loan.total_payment, 0), 301034)
schedule = loan.repayment_schedule
@@ -72,9 +72,9 @@ class TestLoan(unittest.TestCase):
loan.monthly_repayment_amount = 14000
loan.save()
- self.assertEquals(len(loan.repayment_schedule), 22)
- self.assertEquals(flt(loan.total_interest_payable, 0), 22712)
- self.assertEquals(flt(loan.total_payment, 0), 302712)
+ self.assertEqual(len(loan.repayment_schedule), 22)
+ self.assertEqual(flt(loan.total_interest_payable, 0), 22712)
+ self.assertEqual(flt(loan.total_payment, 0), 302712)
def test_loan_with_security(self):
@@ -89,7 +89,7 @@ class TestLoan(unittest.TestCase):
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods",
12, loan_application)
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
def test_loan_disbursement(self):
pledge = [{
@@ -102,7 +102,7 @@ class TestLoan(unittest.TestCase):
create_pledge(loan_application)
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application)
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
loan.submit()
@@ -120,8 +120,8 @@ class TestLoan(unittest.TestCase):
filters = {'voucher_type': 'Loan Disbursement', 'voucher_no': loan_disbursement_entry2.name}
)
- self.assertEquals(loan.status, "Disbursed")
- self.assertEquals(loan.disbursed_amount, 1000000)
+ self.assertEqual(loan.status, "Disbursed")
+ self.assertEqual(loan.disbursed_amount, 1000000)
self.assertTrue(gl_entries1)
self.assertTrue(gl_entries2)
@@ -137,7 +137,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -156,15 +156,15 @@ class TestLoan(unittest.TestCase):
repayment_entry.submit()
penalty_amount = (accrued_interest_amount * 5 * 25) / 100
- self.assertEquals(flt(repayment_entry.penalty_amount,0), flt(penalty_amount, 0))
+ self.assertEqual(flt(repayment_entry.penalty_amount,0), flt(penalty_amount, 0))
amounts = frappe.db.get_all('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount'])
loan.load_from_db()
total_interest_paid = amounts[0]['paid_interest_amount'] + amounts[1]['paid_interest_amount']
- self.assertEquals(amounts[1]['paid_interest_amount'], repayment_entry.interest_payable)
- self.assertEquals(flt(loan.total_principal_paid, 0), flt(repayment_entry.amount_paid -
+ self.assertEqual(amounts[1]['paid_interest_amount'], repayment_entry.interest_payable)
+ self.assertEqual(flt(loan.total_principal_paid, 0), flt(repayment_entry.amount_paid -
penalty_amount - total_interest_paid, 0))
def test_loan_closure(self):
@@ -179,7 +179,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -204,12 +204,12 @@ class TestLoan(unittest.TestCase):
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
- self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
- self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
+ self.assertEqual(flt(amount, 0),flt(accrued_interest_amount, 0))
+ self.assertEqual(flt(repayment_entry.penalty_amount, 5), 0)
request_loan_closure(loan.name)
loan.load_from_db()
- self.assertEquals(loan.status, "Loan Closure Requested")
+ self.assertEqual(loan.status, "Loan Closure Requested")
def test_loan_repayment_for_term_loan(self):
pledges = [{
@@ -241,8 +241,8 @@ class TestLoan(unittest.TestCase):
amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
'paid_principal_amount'])
- self.assertEquals(amounts[0], 11250.00)
- self.assertEquals(amounts[1], 78303.00)
+ self.assertEqual(amounts[0], 11250.00)
+ self.assertEqual(amounts[1], 78303.00)
def test_security_shortfall(self):
pledges = [{
@@ -268,17 +268,17 @@ class TestLoan(unittest.TestCase):
loan_security_shortfall = frappe.get_doc("Loan Security Shortfall", {"loan": loan.name})
self.assertTrue(loan_security_shortfall)
- self.assertEquals(loan_security_shortfall.loan_amount, 1000000.00)
- self.assertEquals(loan_security_shortfall.security_value, 800000.00)
- self.assertEquals(loan_security_shortfall.shortfall_amount, 600000.00)
+ self.assertEqual(loan_security_shortfall.loan_amount, 1000000.00)
+ self.assertEqual(loan_security_shortfall.security_value, 800000.00)
+ self.assertEqual(loan_security_shortfall.shortfall_amount, 600000.00)
frappe.db.sql(""" UPDATE `tabLoan Security Price` SET loan_security_price = 250
where loan_security='Test Security 2'""")
create_process_loan_security_shortfall()
loan_security_shortfall = frappe.get_doc("Loan Security Shortfall", {"loan": loan.name})
- self.assertEquals(loan_security_shortfall.status, "Completed")
- self.assertEquals(loan_security_shortfall.shortfall_amount, 0)
+ self.assertEqual(loan_security_shortfall.status, "Completed")
+ self.assertEqual(loan_security_shortfall.shortfall_amount, 0)
def test_loan_security_unpledge(self):
pledge = [{
@@ -292,7 +292,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -312,7 +312,7 @@ class TestLoan(unittest.TestCase):
request_loan_closure(loan.name)
loan.load_from_db()
- self.assertEquals(loan.status, "Loan Closure Requested")
+ self.assertEqual(loan.status, "Loan Closure Requested")
unpledge_request = unpledge_security(loan=loan.name, save=1)
unpledge_request.submit()
@@ -323,11 +323,11 @@ class TestLoan(unittest.TestCase):
pledged_qty = get_pledged_security_qty(loan.name)
self.assertEqual(loan.status, 'Closed')
- self.assertEquals(sum(pledged_qty.values()), 0)
+ self.assertEqual(sum(pledged_qty.values()), 0)
amounts = amounts = calculate_amounts(loan.name, add_days(last_date, 5))
self.assertEqual(amounts['pending_principal_amount'], 0)
- self.assertEquals(amounts['payable_principal_amount'], 0.0)
+ self.assertEqual(amounts['payable_principal_amount'], 0.0)
self.assertEqual(amounts['interest_amount'], 0)
def test_partial_loan_security_unpledge(self):
@@ -346,7 +346,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -379,7 +379,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
unpledge_map = {'Test Security 1': 4000}
unpledge_request = unpledge_security(loan=loan.name, security_map = unpledge_map, save=1)
@@ -450,7 +450,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -475,7 +475,7 @@ class TestLoan(unittest.TestCase):
request_loan_closure(loan.name)
loan.load_from_db()
- self.assertEquals(loan.status, "Loan Closure Requested")
+ self.assertEqual(loan.status, "Loan Closure Requested")
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
self.assertEqual(amounts['pending_principal_amount'], 0.0)
@@ -492,7 +492,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -533,8 +533,8 @@ class TestLoan(unittest.TestCase):
calculated_penalty_amount = frappe.db.get_value('Loan Interest Accrual',
{'process_loan_interest_accrual': process, 'loan': loan.name}, 'penalty_amount')
- self.assertEquals(loan.loan_amount, 1000000)
- self.assertEquals(calculated_penalty_amount, penalty_amount)
+ self.assertEqual(loan.loan_amount, 1000000)
+ self.assertEqual(calculated_penalty_amount, penalty_amount)
def test_penalty_repayment(self):
loan, dummy = create_loan_scenario_for_penalty(self)
@@ -547,13 +547,13 @@ class TestLoan(unittest.TestCase):
repayment_entry.submit()
amounts = calculate_amounts(loan.name, '2019-11-30 00:00:01')
- self.assertEquals(amounts['penalty_amount'], second_penalty)
+ self.assertEqual(amounts['penalty_amount'], second_penalty)
repayment_entry = create_repayment_entry(loan.name, self.applicant2, '2019-11-30 00:00:01', second_penalty)
repayment_entry.submit()
amounts = calculate_amounts(loan.name, '2019-11-30 00:00:02')
- self.assertEquals(amounts['penalty_amount'], 0)
+ self.assertEqual(amounts['penalty_amount'], 0)
def test_loan_write_off_limit(self):
pledge = [{
@@ -567,7 +567,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -589,15 +589,15 @@ class TestLoan(unittest.TestCase):
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
- self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
- self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
+ self.assertEqual(flt(amount, 0),flt(accrued_interest_amount, 0))
+ self.assertEqual(flt(repayment_entry.penalty_amount, 5), 0)
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
- self.assertEquals(flt(amounts['pending_principal_amount'], 0), 50)
+ self.assertEqual(flt(amounts['pending_principal_amount'], 0), 50)
request_loan_closure(loan.name)
loan.load_from_db()
- self.assertEquals(loan.status, "Loan Closure Requested")
+ self.assertEqual(loan.status, "Loan Closure Requested")
def test_loan_amount_write_off(self):
pledge = [{
@@ -611,7 +611,7 @@ class TestLoan(unittest.TestCase):
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -633,17 +633,17 @@ class TestLoan(unittest.TestCase):
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
- self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
- self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
+ self.assertEqual(flt(amount, 0),flt(accrued_interest_amount, 0))
+ self.assertEqual(flt(repayment_entry.penalty_amount, 5), 0)
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
- self.assertEquals(flt(amounts['pending_principal_amount'], 0), 100)
+ self.assertEqual(flt(amounts['pending_principal_amount'], 0), 100)
we = make_loan_write_off(loan.name, amount=amounts['pending_principal_amount'])
we.submit()
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
- self.assertEquals(flt(amounts['pending_principal_amount'], 0), 0)
+ self.assertEqual(flt(amounts['pending_principal_amount'], 0), 0)
def create_loan_scenario_for_penalty(doc):
pledge = [{
diff --git a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
index a8753877a6..da56710c67 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
+++ b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
@@ -87,7 +87,7 @@ class TestLoanDisbursement(unittest.TestCase):
loan = create_demand_loan(self.applicant, "Demand Loan", loan_application, posting_date='2019-10-01')
loan.submit()
- self.assertEquals(loan.loan_amount, 1000000)
+ self.assertEqual(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
@@ -114,5 +114,5 @@ class TestLoanDisbursement(unittest.TestCase):
per_day_interest = get_per_day_interest(1500000, 13.5, '2019-10-30')
interest = per_day_interest * 15
- self.assertEquals(amounts['pending_principal_amount'], 1500000)
- self.assertEquals(amounts['interest_amount'], flt(interest + previous_interest, 2))
+ self.assertEqual(amounts['pending_principal_amount'], 1500000)
+ self.assertEqual(amounts['interest_amount'], flt(interest + previous_interest, 2))
diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py
index 85e008ac29..eb626f3eee 100644
--- a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py
@@ -52,7 +52,7 @@ class TestLoanInterestAccrual(unittest.TestCase):
process_loan_interest_accrual_for_demand_loans(posting_date=last_date)
loan_interest_accural = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
- self.assertEquals(flt(loan_interest_accural.interest_amount, 0), flt(accrued_interest_amount, 0))
+ self.assertEqual(flt(loan_interest_accural.interest_amount, 0), flt(accrued_interest_amount, 0))
def test_accumulated_amounts(self):
pledge = [{
@@ -76,7 +76,7 @@ class TestLoanInterestAccrual(unittest.TestCase):
process_loan_interest_accrual_for_demand_loans(posting_date=last_date)
loan_interest_accrual = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
- self.assertEquals(flt(loan_interest_accrual.interest_amount, 0), flt(accrued_interest_amount, 0))
+ self.assertEqual(flt(loan_interest_accrual.interest_amount, 0), flt(accrued_interest_amount, 0))
next_start_date = '2019-10-31'
next_end_date = '2019-11-29'
@@ -90,4 +90,4 @@ class TestLoanInterestAccrual(unittest.TestCase):
loan_interest_accrual = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name,
'process_loan_interest_accrual': process})
- self.assertEquals(flt(loan_interest_accrual.total_pending_interest_amount, 0), total_pending_interest_amount)
+ self.assertEqual(flt(loan_interest_accrual.total_pending_interest_amount, 0), total_pending_interest_amount)
diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py
index 7108338dab..e1cca9e3ef 100644
--- a/erpnext/manufacturing/doctype/bom/test_bom.py
+++ b/erpnext/manufacturing/doctype/bom/test_bom.py
@@ -223,7 +223,7 @@ class TestBOM(unittest.TestCase):
is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
bom_items = sorted([d.item_code for d in bom.items if d.sourced_by_supplier != 1])
supplied_items = sorted([d.rm_item_code for d in po.supplied_items])
- self.assertEquals(bom_items, supplied_items)
+ self.assertEqual(bom_items, supplied_items)
def get_default_bom(item_code="_Test FG Item 2"):
return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1})
diff --git a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py
index ac9a409bcb..80d1cdfc8f 100644
--- a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py
+++ b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py
@@ -45,16 +45,16 @@ class TestBOMUpdateTool(unittest.TestCase):
else:
doc = frappe.get_doc("BOM", bom_no)
- self.assertEquals(doc.total_cost, 200)
+ self.assertEqual(doc.total_cost, 200)
frappe.db.set_value("Item", "BOM Cost Test Item 2", "valuation_rate", 200)
update_cost()
doc.load_from_db()
- self.assertEquals(doc.total_cost, 300)
+ self.assertEqual(doc.total_cost, 300)
frappe.db.set_value("Item", "BOM Cost Test Item 2", "valuation_rate", 100)
update_cost()
doc.load_from_db()
- self.assertEquals(doc.total_cost, 200)
+ self.assertEqual(doc.total_cost, 200)
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index 6b1fafe5f4..cb1ee92196 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -473,7 +473,7 @@ class TestWorkOrder(unittest.TestCase):
def test_cost_center_for_manufacture(self):
wo_order = make_wo_order_test_record()
ste = make_stock_entry(wo_order.name, "Material Transfer for Manufacture", wo_order.qty)
- self.assertEquals(ste.get("items")[0].get("cost_center"), "_Test Cost Center - _TC")
+ self.assertEqual(ste.get("items")[0].get("cost_center"), "_Test Cost Center - _TC")
def test_operation_time_with_batch_size(self):
fg_item = "Test Batch Size Item For BOM"
@@ -539,11 +539,11 @@ class TestWorkOrder(unittest.TestCase):
ste_cancel_list.append(ste1)
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Material Consumption for Manufacture", 2))
- self.assertEquals(ste3.fg_completed_qty, 2)
+ self.assertEqual(ste3.fg_completed_qty, 2)
expected_qty = {"_Test Item": 2, "_Test Item Home Desktop 100": 4}
for row in ste3.items:
- self.assertEquals(row.qty, expected_qty.get(row.item_code))
+ self.assertEqual(row.qty, expected_qty.get(row.item_code))
ste_cancel_list.reverse()
for ste_doc in ste_cancel_list:
ste_doc.cancel()
@@ -577,7 +577,7 @@ class TestWorkOrder(unittest.TestCase):
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
for ste_row in ste3.items:
if itemwise_qty.get(ste_row.item_code) and ste_row.s_warehouse:
- self.assertEquals(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
+ self.assertEqual(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
ste3.submit()
ste_cancel_list.append(ste3)
@@ -585,7 +585,7 @@ class TestWorkOrder(unittest.TestCase):
ste2 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
for ste_row in ste2.items:
if itemwise_qty.get(ste_row.item_code) and ste_row.s_warehouse:
- self.assertEquals(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
+ self.assertEqual(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
ste_cancel_list.reverse()
for ste_doc in ste_cancel_list:
ste_doc.cancel()
diff --git a/erpnext/non_profit/doctype/donation/test_donation.py b/erpnext/non_profit/doctype/donation/test_donation.py
index c6a534dac3..bbe9bf5228 100644
--- a/erpnext/non_profit/doctype/donation/test_donation.py
+++ b/erpnext/non_profit/doctype/donation/test_donation.py
@@ -39,7 +39,7 @@ class TestDonation(unittest.TestCase):
donation.on_payment_authorized()
donation.reload()
- self.assertEquals(donation.paid, 1)
+ self.assertEqual(donation.paid, 1)
self.assertTrue(frappe.db.exists('Payment Entry', {'reference_no': donation.name}))
diff --git a/erpnext/portal/doctype/homepage/test_homepage.py b/erpnext/portal/doctype/homepage/test_homepage.py
index bf5c4025a0..b717491a82 100644
--- a/erpnext/portal/doctype/homepage/test_homepage.py
+++ b/erpnext/portal/doctype/homepage/test_homepage.py
@@ -13,7 +13,7 @@ class TestHomepage(unittest.TestCase):
set_request(method='GET', path='home')
response = render()
- self.assertEquals(response.status_code, 200)
+ self.assertEqual(response.status_code, 200)
html = frappe.safe_decode(response.get_data())
self.assertTrue('
Date: Mon, 10 May 2021 12:36:56 +0530
Subject: [PATCH 078/149] feat(india): reduced rate of depreciation as per IT
Act (#25648)
* feat(india): reduced rate of depreciation as per IT Act
* refactor: check date difference instead of month difference
* feat: add test for regional feature
---
erpnext/assets/doctype/asset/asset.py | 51 ++++++++++------------
erpnext/assets/doctype/asset/test_asset.py | 39 +++++++++++++++++
erpnext/hooks.py | 3 +-
erpnext/regional/india/utils.py | 21 +++++++++
4 files changed, 84 insertions(+), 30 deletions(-)
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 9aff1440d6..8799275fc4 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -195,8 +195,7 @@ class Asset(AccountsController):
# If depreciation is already completed (for double declining balance)
if skip_row: continue
- depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
- d.total_number_of_depreciations, d)
+ depreciation_amount = get_depreciation_amount(self, value_after_depreciation, d)
if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1:
schedule_date = add_months(d.depreciation_start_date,
@@ -208,7 +207,7 @@ class Asset(AccountsController):
# For first row
if has_pro_rata and n==0:
- depreciation_amount, days, months = get_pro_rata_amt(d, depreciation_amount,
+ depreciation_amount, days, months = self.get_pro_rata_amt(d, depreciation_amount,
self.available_for_use_date, d.depreciation_start_date)
# For first depr schedule date will be the start date
@@ -220,7 +219,7 @@ class Asset(AccountsController):
to_date = add_months(self.available_for_use_date,
n * cint(d.frequency_of_depreciation))
- depreciation_amount, days, months = get_pro_rata_amt(d,
+ depreciation_amount, days, months = self.get_pro_rata_amt(d,
depreciation_amount, schedule_date, to_date)
monthly_schedule_date = add_months(schedule_date, 1)
@@ -365,24 +364,6 @@ class Asset(AccountsController):
def get_value_after_depreciation(self, idx):
return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation)
- def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row):
- precision = self.precision("gross_purchase_amount")
-
- if row.depreciation_method in ("Straight Line", "Manual"):
- depreciation_left = (cint(row.total_number_of_depreciations) - cint(self.number_of_depreciations_booked))
-
- if not depreciation_left:
- frappe.msgprint(_("All the depreciations has been booked"))
- depreciation_amount = flt(row.expected_value_after_useful_life)
- return depreciation_amount
-
- depreciation_amount = (flt(row.value_after_depreciation) -
- flt(row.expected_value_after_useful_life)) / depreciation_left
- else:
- depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100), precision)
-
- return depreciation_amount
-
def validate_expected_value_after_useful_life(self):
for row in self.get('finance_books'):
accumulated_depreciation_after_full_schedule = [d.accumulated_depreciation_amount
@@ -575,6 +556,13 @@ class Asset(AccountsController):
return 100 * (1 - flt(depreciation_rate, float_precision))
+ def get_pro_rata_amt(self, row, depreciation_amount, from_date, to_date):
+ days = date_diff(to_date, from_date)
+ months = month_diff(to_date, from_date)
+ total_days = get_total_days(to_date, row.frequency_of_depreciation)
+
+ return (depreciation_amount * flt(days)) / flt(total_days), days, months
+
def update_maintenance_status():
assets = frappe.get_all(
"Asset", filters={"docstatus": 1, "maintenance_required": 1}
@@ -758,15 +746,20 @@ def make_asset_movement(assets, purpose=None):
def is_cwip_accounting_enabled(asset_category):
return cint(frappe.db.get_value("Asset Category", asset_category, "enable_cwip_accounting"))
-def get_pro_rata_amt(row, depreciation_amount, from_date, to_date):
- days = date_diff(to_date, from_date)
- months = month_diff(to_date, from_date)
- total_days = get_total_days(to_date, row.frequency_of_depreciation)
-
- return (depreciation_amount * flt(days)) / flt(total_days), days, months
-
def get_total_days(date, frequency):
period_start_date = add_months(date,
cint(frequency) * -1)
return date_diff(date, period_start_date)
+
+@erpnext.allow_regional
+def get_depreciation_amount(asset, depreciable_value, row):
+ depreciation_left = flt(row.total_number_of_depreciations) - flt(asset.number_of_depreciations_booked)
+
+ if row.depreciation_method in ("Straight Line", "Manual"):
+ depreciation_amount = (flt(row.value_after_depreciation) -
+ flt(row.expected_value_after_useful_life)) / depreciation_left
+ else:
+ depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100))
+
+ return depreciation_amount
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 40a8f85d8d..30a270c204 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -635,6 +635,45 @@ class TestAsset(unittest.TestCase):
frappe.db.set_value("Asset Category Account", name, "capital_work_in_progress_account", cwip_acc)
frappe.db.get_value("Company", "_Test Company", "capital_work_in_progress_account", cwip_acc)
+ def test_discounted_wdv_depreciation_rate_for_indian_region(self):
+ # set indian company
+ company_flag = frappe.flags.company
+ frappe.flags.company = "_Test Company"
+
+ pr = make_purchase_receipt(item_code="Macbook Pro",
+ qty=1, rate=8000.0, location="Test Location")
+
+ asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
+ asset = frappe.get_doc('Asset', asset_name)
+ asset.calculate_depreciation = 1
+ asset.available_for_use_date = '2030-06-12'
+ asset.purchase_date = '2030-01-01'
+ asset.append("finance_books", {
+ "expected_value_after_useful_life": 1000,
+ "depreciation_method": "Written Down Value",
+ "total_number_of_depreciations": 3,
+ "frequency_of_depreciation": 12,
+ "depreciation_start_date": "2030-12-31"
+ })
+ asset.save(ignore_permissions=True)
+
+ self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
+
+ expected_schedules = [
+ ["2030-12-31", 1106.85, 1106.85],
+ ["2031-12-31", 3446.58, 4553.43],
+ ["2032-12-31", 1723.29, 6276.72],
+ ["2033-06-12", 723.28, 7000.00]
+ ]
+
+ schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
+ for d in asset.get("schedules")]
+
+ self.assertEqual(schedules, expected_schedules)
+
+ # reset indian company
+ frappe.flags.company = company_flag
+
def create_asset_data():
if not frappe.db.exists("Asset Category", "Computers"):
create_asset_category()
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index bb6cd8bdc2..9d1ce9bbbf 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -426,7 +426,8 @@ regional_overrides = {
'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption',
'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period',
'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.india.utils.make_regional_gl_entries',
- 'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields'
+ 'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields',
+ 'erpnext.assets.doctype.asset.asset.get_depreciation_amount': 'erpnext.regional.india.utils.get_depreciation_amount'
},
'United Arab Emirates': {
'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data',
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 6338056698..052d7bdedf 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -879,3 +879,24 @@ def update_taxable_values(doc, method):
if total_charges != additional_taxes:
diff = additional_taxes - total_charges
doc.get('items')[item_count - 1].taxable_value += diff
+
+def get_depreciation_amount(asset, depreciable_value, row):
+ depreciation_left = flt(row.total_number_of_depreciations) - flt(asset.number_of_depreciations_booked)
+
+ if row.depreciation_method in ("Straight Line", "Manual"):
+ depreciation_amount = (flt(row.value_after_depreciation) -
+ flt(row.expected_value_after_useful_life)) / depreciation_left
+ else:
+ rate_of_depreciation = row.rate_of_depreciation
+ # if its the first depreciation
+ if depreciable_value == asset.gross_purchase_amount:
+ # as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2
+ diff = date_diff(asset.available_for_use_date, row.depreciation_start_date)
+ if diff <= 180:
+ rate_of_depreciation = rate_of_depreciation / 2
+ frappe.msgprint(
+ _('As per IT Act, the rate of depreciation for the first depreciation entry is reduced by 50%.'))
+
+ depreciation_amount = flt(depreciable_value * (flt(rate_of_depreciation) / 100))
+
+ return depreciation_amount
\ No newline at end of file
From 6e179c3092c5f31f43ed61610a654e8d61487993 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Mon, 10 May 2021 13:24:26 +0530
Subject: [PATCH 079/149] fix: sync shopify customer addresses (#25481)
---
.../doctype/shopify_settings/sync_customer.py | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py
index 7866fdea31..2af57f4c89 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py
@@ -32,10 +32,12 @@ def create_customer(shopify_customer, shopify_settings):
raise e
def create_customer_address(customer, shopify_customer):
- if not shopify_customer.get("addresses"):
- return
+ addresses = shopify_customer.get("addresses", [])
- for i, address in enumerate(shopify_customer.get("addresses")):
+ if not addresses and "default_address" in shopify_customer:
+ addresses.append(shopify_customer["default_address"])
+
+ for i, address in enumerate(addresses):
address_title, address_type = get_address_title_and_type(customer.customer_name, i)
try :
frappe.get_doc({
From f2eb8dd1d5b6a156f2d6df9a4eb4d41ca497738b Mon Sep 17 00:00:00 2001
From: Ganga Manoj
Date: Mon, 10 May 2021 14:02:58 +0530
Subject: [PATCH 080/149] feat: Transaction Deletion Record (#25354)
Co-authored-by: Saqib
---
erpnext/controllers/status_updater.py | 4 +
erpnext/setup/doctype/company/company.js | 4 +-
erpnext/setup/doctype/company/company.py | 11 +-
.../company/delete_company_transactions.py | 117 --------------
erpnext/setup/doctype/company/test_company.py | 9 --
.../transaction_deletion_record/__init__.py | 0
.../test_transaction_deletion_record.py | 68 ++++++++
.../transaction_deletion_record.js | 40 +++++
.../transaction_deletion_record.json | 79 ++++++++++
.../transaction_deletion_record.py | 147 ++++++++++++++++++
.../transaction_deletion_record_list.js | 12 ++
.../__init__.py | 0
.../transaction_deletion_record_item.json | 39 +++++
.../transaction_deletion_record_item.py | 10 ++
14 files changed, 411 insertions(+), 129 deletions(-)
delete mode 100644 erpnext/setup/doctype/company/delete_company_transactions.py
create mode 100644 erpnext/setup/doctype/transaction_deletion_record/__init__.py
create mode 100644 erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
create mode 100644 erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js
create mode 100644 erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
create mode 100644 erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
create mode 100644 erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js
create mode 100644 erpnext/setup/doctype/transaction_deletion_record_item/__init__.py
create mode 100644 erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.json
create mode 100644 erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index 4bb6138e5d..ed3aee5c1a 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -100,6 +100,10 @@ status_map = {
["Queued", "eval:self.status == 'Queued'"],
["Failed", "eval:self.status == 'Failed'"],
["Cancelled", "eval:self.docstatus == 2"],
+ ],
+ "Transaction Deletion Record": [
+ ["Draft", None],
+ ["Completed", "eval:self.docstatus == 1"],
]
}
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index c2b5e4f9a9..9957aad019 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -169,9 +169,9 @@ frappe.ui.form.on("Company", {
return;
}
frappe.call({
- method: "erpnext.setup.doctype.company.delete_company_transactions.delete_company_transactions",
+ method: "erpnext.setup.doctype.company.company.create_transaction_deletion_request",
args: {
- company_name: data.company_name
+ company: data.company_name
},
freeze: true,
callback: function(r, rt) {
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 64e027dd28..077538d479 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -613,4 +613,13 @@ def get_default_company_address(name, sort_key='is_primary_address', existing_ad
if out:
return sorted(out, key = functools.cmp_to_key(lambda x,y: cmp(y[1], x[1])))[0][0]
else:
- return None
\ No newline at end of file
+ return None
+
+@frappe.whitelist()
+def create_transaction_deletion_request(company):
+ tdr = frappe.get_doc({
+ 'doctype': 'Transaction Deletion Record',
+ 'company': company
+ })
+ tdr.insert()
+ tdr.submit()
diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py
deleted file mode 100644
index 8367a257ea..0000000000
--- a/erpnext/setup/doctype/company/delete_company_transactions.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-
-from frappe.utils import cint
-from frappe import _
-from frappe.desk.notifications import clear_notifications
-
-import functools
-
-@frappe.whitelist()
-def delete_company_transactions(company_name):
- frappe.only_for("System Manager")
- doc = frappe.get_doc("Company", company_name)
-
- if frappe.session.user != doc.owner and frappe.session.user != 'Administrator':
- frappe.throw(_("Transactions can only be deleted by the creator of the Company"),
- frappe.PermissionError)
-
- delete_bins(company_name)
- delete_lead_addresses(company_name)
-
- for doctype in frappe.db.sql_list("""select parent from
- tabDocField where fieldtype='Link' and options='Company'"""):
- if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
- "Party Account", "Employee", "Sales Taxes and Charges Template",
- "Purchase Taxes and Charges Template", "POS Profile", "BOM",
- "Company", "Bank Account", "Item Tax Template", "Mode Of Payment", "Mode of Payment Account",
- "Item Default", "Customer", "Supplier", "GST Account"):
- delete_for_doctype(doctype, company_name)
-
- # reset company values
- doc.total_monthly_sales = 0
- doc.sales_monthly_history = None
- doc.save()
- # Clear notification counts
- clear_notifications()
-
-def delete_for_doctype(doctype, company_name):
- meta = frappe.get_meta(doctype)
- company_fieldname = meta.get("fields", {"fieldtype": "Link",
- "options": "Company"})[0].fieldname
-
- if not meta.issingle:
- if not meta.istable:
- # delete communication
- delete_communications(doctype, company_name, company_fieldname)
-
- # delete children
- for df in meta.get_table_fields():
- frappe.db.sql("""delete from `tab{0}` where parent in
- (select name from `tab{1}` where `{2}`=%s)""".format(df.options,
- doctype, company_fieldname), company_name)
-
- #delete version log
- frappe.db.sql("""delete from `tabVersion` where ref_doctype=%s and docname in
- (select name from `tab{0}` where `{1}`=%s)""".format(doctype,
- company_fieldname), (doctype, company_name))
-
- # delete parent
- frappe.db.sql("""delete from `tab{0}`
- where {1}= %s """.format(doctype, company_fieldname), company_name)
-
- # reset series
- naming_series = meta.get_field("naming_series")
- if naming_series and naming_series.options:
- prefixes = sorted(naming_series.options.split("\n"),
- key=functools.cmp_to_key(lambda a, b: len(b) - len(a)))
-
- for prefix in prefixes:
- if prefix:
- last = frappe.db.sql("""select max(name) from `tab{0}`
- where name like %s""".format(doctype), prefix + "%")
- if last and last[0][0]:
- last = cint(last[0][0].replace(prefix, ""))
- else:
- last = 0
-
- frappe.db.sql("""update tabSeries set current = %s
- where name=%s""", (last, prefix))
-
-def delete_bins(company_name):
- frappe.db.sql("""delete from tabBin where warehouse in
- (select name from tabWarehouse where company=%s)""", company_name)
-
-def delete_lead_addresses(company_name):
- """Delete addresses to which leads are linked"""
- leads = frappe.get_all("Lead", filters={"company": company_name})
- leads = [ "'%s'"%row.get("name") for row in leads ]
- addresses = []
- if leads:
- addresses = frappe.db.sql_list("""select parent from `tabDynamic Link` where link_name
- in ({leads})""".format(leads=",".join(leads)))
-
- if addresses:
- addresses = ["%s" % frappe.db.escape(addr) for addr in addresses]
-
- frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
- name not in (select distinct dl1.parent from `tabDynamic Link` dl1
- inner join `tabDynamic Link` dl2 on dl1.parent=dl2.parent
- and dl1.link_doctype<>dl2.link_doctype)""".format(addresses=",".join(addresses)))
-
- frappe.db.sql("""delete from `tabDynamic Link` where link_doctype='Lead'
- and parenttype='Address' and link_name in ({leads})""".format(leads=",".join(leads)))
-
- frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
-
-def delete_communications(doctype, company_name, company_fieldname):
- reference_docs = frappe.get_all(doctype, filters={company_fieldname:company_name})
- reference_doc_names = [r.name for r in reference_docs]
-
- communications = frappe.get_all("Communication", filters={"reference_doctype":doctype,"reference_name":["in", reference_doc_names]})
- communication_names = [c.name for c in communications]
-
- frappe.delete_doc("Communication", communication_names, ignore_permissions=True)
diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py
index 29f6c3731d..e1c803a038 100644
--- a/erpnext/setup/doctype/company/test_company.py
+++ b/erpnext/setup/doctype/company/test_company.py
@@ -86,15 +86,6 @@ class TestCompany(unittest.TestCase):
self.delete_mode_of_payment(template)
frappe.delete_doc("Company", template)
- def test_delete_communication(self):
- from erpnext.setup.doctype.company.delete_company_transactions import delete_communications
- company = create_child_company()
- lead = create_test_lead_in_company(company)
- communication = create_company_communication("Lead", lead)
- delete_communications("Lead", "Test Company", "company")
- self.assertFalse(frappe.db.exists("Communcation", communication))
- self.assertFalse(frappe.db.exists({"doctype":"Comunication Link", "link_name": communication}))
-
def delete_mode_of_payment(self, company):
frappe.db.sql(""" delete from `tabMode of Payment Account`
where company =%s """, (company))
diff --git a/erpnext/setup/doctype/transaction_deletion_record/__init__.py b/erpnext/setup/doctype/transaction_deletion_record/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
new file mode 100644
index 0000000000..bbe68369ff
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestTransactionDeletionRecord(unittest.TestCase):
+ def setUp(self):
+ create_company('Dunder Mifflin Paper Co')
+
+ def tearDown(self):
+ frappe.db.rollback()
+
+ def test_doctypes_contain_company_field(self):
+ tdr = create_transaction_deletion_request('Dunder Mifflin Paper Co')
+ for doctype in tdr.doctypes:
+ contains_company = False
+ doctype_fields = frappe.get_meta(doctype.doctype_name).as_dict()['fields']
+ for doctype_field in doctype_fields:
+ if doctype_field['fieldtype'] == 'Link' and doctype_field['options'] == 'Company':
+ contains_company = True
+ break
+ self.assertTrue(contains_company)
+
+ def test_no_of_docs_is_correct(self):
+ for i in range(5):
+ create_task('Dunder Mifflin Paper Co')
+ tdr = create_transaction_deletion_request('Dunder Mifflin Paper Co')
+ for doctype in tdr.doctypes:
+ if doctype.doctype_name == 'Task':
+ self.assertEqual(doctype.no_of_docs, 5)
+
+ def test_deletion_is_successful(self):
+ create_task('Dunder Mifflin Paper Co')
+ create_transaction_deletion_request('Dunder Mifflin Paper Co')
+ tasks_containing_company = frappe.get_all('Task',
+ filters = {
+ 'company' : 'Dunder Mifflin Paper Co'
+ })
+ self.assertEqual(tasks_containing_company, [])
+
+def create_company(company_name):
+ company = frappe.get_doc({
+ 'doctype': 'Company',
+ 'company_name': company_name,
+ 'default_currency': 'INR'
+ })
+ company.insert(ignore_if_duplicate = True)
+
+def create_transaction_deletion_request(company):
+ tdr = frappe.get_doc({
+ 'doctype': 'Transaction Deletion Record',
+ 'company': company
+ })
+ tdr.insert()
+ tdr.submit()
+ return tdr
+
+
+def create_task(company):
+ task = frappe.get_doc({
+ 'doctype': 'Task',
+ 'company': company,
+ 'subject': 'Delete'
+ })
+ task.insert()
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js
new file mode 100644
index 0000000000..20caa15ee4
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js
@@ -0,0 +1,40 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Transaction Deletion Record', {
+ onload: function(frm) {
+ if (frm.doc.docstatus == 0) {
+ let doctypes_to_be_ignored_array;
+ frappe.call({
+ method: 'erpnext.setup.doctype.transaction_deletion_record.transaction_deletion_record.get_doctypes_to_be_ignored',
+ callback: function(r) {
+ doctypes_to_be_ignored_array = r.message;
+ populate_doctypes_to_be_ignored(doctypes_to_be_ignored_array, frm);
+ frm.fields_dict['doctypes_to_be_ignored'].grid.set_column_disp('no_of_docs', false);
+ frm.refresh_field('doctypes_to_be_ignored');
+ }
+ });
+ }
+
+ frm.get_field('doctypes_to_be_ignored').grid.cannot_add_rows = true;
+ frm.fields_dict['doctypes_to_be_ignored'].grid.set_column_disp('no_of_docs', false);
+ frm.refresh_field('doctypes_to_be_ignored');
+ },
+
+ refresh: function(frm) {
+ frm.fields_dict['doctypes_to_be_ignored'].grid.set_column_disp('no_of_docs', false);
+ frm.refresh_field('doctypes_to_be_ignored');
+ }
+
+});
+
+function populate_doctypes_to_be_ignored(doctypes_to_be_ignored_array, frm) {
+ if (!(frm.doc.doctypes_to_be_ignored)) {
+ var i;
+ for (i = 0; i < doctypes_to_be_ignored_array.length; i++) {
+ frm.add_child('doctypes_to_be_ignored', {
+ doctype_name: doctypes_to_be_ignored_array[i]
+ });
+ }
+ }
+}
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
new file mode 100644
index 0000000000..9313f95516
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
@@ -0,0 +1,79 @@
+{
+ "actions": [],
+ "autoname": "TDL.####",
+ "creation": "2021-04-06 20:17:18.404716",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "doctypes",
+ "doctypes_to_be_ignored",
+ "amended_from",
+ "status"
+ ],
+ "fields": [
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ "fieldname": "doctypes",
+ "fieldtype": "Table",
+ "label": "Summary",
+ "options": "Transaction Deletion Record Item",
+ "read_only": 1
+ },
+ {
+ "fieldname": "doctypes_to_be_ignored",
+ "fieldtype": "Table",
+ "label": "Excluded DocTypes",
+ "options": "Transaction Deletion Record Item"
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Transaction Deletion Record",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "label": "Status",
+ "options": "Draft\nCompleted"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2021-05-08 23:13:48.049879",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Transaction Deletion Record",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
new file mode 100644
index 0000000000..38f8de7a66
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
@@ -0,0 +1,147 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.utils import cint
+import frappe
+from frappe.model.document import Document
+from frappe import _
+from frappe.desk.notifications import clear_notifications
+
+class TransactionDeletionRecord(Document):
+ def validate(self):
+ frappe.only_for('System Manager')
+ company_obj = frappe.get_doc('Company', self.company)
+ if frappe.session.user != company_obj.owner and frappe.session.user != 'Administrator':
+ frappe.throw(_('Transactions can only be deleted by the creator of the Company or the Administrator.'),
+ frappe.PermissionError)
+ doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
+ for doctype in self.doctypes_to_be_ignored:
+ if doctype.doctype_name not in doctypes_to_be_ignored_list:
+ frappe.throw(_("DocTypes should not be added manually to the 'Excluded DocTypes' table. You are only allowed to remove entries from it. "), title=_("Not Allowed"))
+
+ def before_submit(self):
+ if not self.doctypes_to_be_ignored:
+ self.populate_doctypes_to_be_ignored_table()
+
+ self.delete_bins()
+ self.delete_lead_addresses()
+
+ company_obj = frappe.get_doc('Company', self.company)
+ # reset company values
+ company_obj.total_monthly_sales = 0
+ company_obj.sales_monthly_history = None
+ company_obj.save()
+ # Clear notification counts
+ clear_notifications()
+
+ singles = frappe.get_all('DocType', filters = {'issingle': 1}, pluck = 'name')
+ tables = frappe.get_all('DocType', filters = {'istable': 1}, pluck = 'name')
+ doctypes_to_be_ignored_list = singles
+ for doctype in self.doctypes_to_be_ignored:
+ doctypes_to_be_ignored_list.append(doctype.doctype_name)
+
+ docfields = frappe.get_all('DocField',
+ filters = {
+ 'fieldtype': 'Link',
+ 'options': 'Company',
+ 'parent': ['not in', doctypes_to_be_ignored_list]},
+ fields=['parent', 'fieldname'])
+
+ for docfield in docfields:
+ if docfield['parent'] != self.doctype:
+ no_of_docs = frappe.db.count(docfield['parent'], {
+ docfield['fieldname'] : self.company
+ })
+
+ if no_of_docs > 0:
+ self.delete_version_log(docfield['parent'], docfield['fieldname'])
+ self.delete_communications(docfield['parent'], docfield['fieldname'])
+
+ # populate DocTypes table
+ if docfield['parent'] not in tables:
+ self.append('doctypes', {
+ 'doctype_name' : docfield['parent'],
+ 'no_of_docs' : no_of_docs
+ })
+
+ # delete the docs linked with the specified company
+ frappe.db.delete(docfield['parent'], {
+ docfield['fieldname'] : self.company
+ })
+
+ naming_series = frappe.db.get_value('DocType', docfield['parent'], 'autoname')
+ if naming_series:
+ if '#' in naming_series:
+ self.update_naming_series(naming_series, docfield['parent'])
+
+ def populate_doctypes_to_be_ignored_table(self):
+ doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
+ for doctype in doctypes_to_be_ignored_list:
+ self.append('doctypes_to_be_ignored', {
+ 'doctype_name' : doctype
+ })
+
+ def update_naming_series(self, naming_series, doctype_name):
+ if '.' in naming_series:
+ prefix, hashes = naming_series.rsplit('.', 1)
+ else:
+ prefix, hashes = naming_series.rsplit('{', 1)
+ last = frappe.db.sql("""select max(name) from `tab{0}`
+ where name like %s""".format(doctype_name), prefix + '%')
+ if last and last[0][0]:
+ last = cint(last[0][0].replace(prefix, ''))
+ else:
+ last = 0
+
+ frappe.db.sql("""update tabSeries set current = %s where name=%s""", (last, prefix))
+
+ def delete_version_log(self, doctype, company_fieldname):
+ frappe.db.sql("""delete from `tabVersion` where ref_doctype=%s and docname in
+ (select name from `tab{0}` where `{1}`=%s)""".format(doctype,
+ company_fieldname), (doctype, self.company))
+
+ def delete_communications(self, doctype, company_fieldname):
+ reference_docs = frappe.get_all(doctype, filters={company_fieldname:self.company})
+ reference_doc_names = [r.name for r in reference_docs]
+
+ communications = frappe.get_all('Communication', filters={'reference_doctype':doctype,'reference_name':['in', reference_doc_names]})
+ communication_names = [c.name for c in communications]
+
+ frappe.delete_doc('Communication', communication_names, ignore_permissions=True)
+
+ def delete_bins(self):
+ frappe.db.sql("""delete from tabBin where warehouse in
+ (select name from tabWarehouse where company=%s)""", self.company)
+
+ def delete_lead_addresses(self):
+ """Delete addresses to which leads are linked"""
+ leads = frappe.get_all('Lead', filters={'company': self.company})
+ leads = ["'%s'" % row.get("name") for row in leads]
+ addresses = []
+ if leads:
+ addresses = frappe.db.sql_list("""select parent from `tabDynamic Link` where link_name
+ in ({leads})""".format(leads=",".join(leads)))
+
+ if addresses:
+ addresses = ["%s" % frappe.db.escape(addr) for addr in addresses]
+
+ frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
+ name not in (select distinct dl1.parent from `tabDynamic Link` dl1
+ inner join `tabDynamic Link` dl2 on dl1.parent=dl2.parent
+ and dl1.link_doctype<>dl2.link_doctype)""".format(addresses=",".join(addresses)))
+
+ frappe.db.sql("""delete from `tabDynamic Link` where link_doctype='Lead'
+ and parenttype='Address' and link_name in ({leads})""".format(leads=",".join(leads)))
+
+ frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
+
+@frappe.whitelist()
+def get_doctypes_to_be_ignored():
+ doctypes_to_be_ignored_list = ['Account', 'Cost Center', 'Warehouse', 'Budget',
+ 'Party Account', 'Employee', 'Sales Taxes and Charges Template',
+ 'Purchase Taxes and Charges Template', 'POS Profile', 'BOM',
+ 'Company', 'Bank Account', 'Item Tax Template', 'Mode of Payment',
+ 'Item Default', 'Customer', 'Supplier', 'GST Account']
+ return doctypes_to_be_ignored_list
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js
new file mode 100644
index 0000000000..d7175ddac4
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js
@@ -0,0 +1,12 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+frappe.listview_settings['Transaction Deletion Record'] = {
+ get_indicator: function(doc) {
+ if (doc.docstatus == 0) {
+ return [__("Draft"), "red"];
+ } else {
+ return [__("Completed"), "green"];
+ }
+ }
+};
\ No newline at end of file
diff --git a/erpnext/setup/doctype/transaction_deletion_record_item/__init__.py b/erpnext/setup/doctype/transaction_deletion_record_item/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.json b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.json
new file mode 100644
index 0000000000..be0be945c4
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.json
@@ -0,0 +1,39 @@
+{
+ "actions": [],
+ "creation": "2021-04-07 07:34:00.124124",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "doctype_name",
+ "no_of_docs"
+ ],
+ "fields": [
+ {
+ "fieldname": "doctype_name",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "DocType",
+ "options": "DocType",
+ "reqd": 1
+ },
+ {
+ "fieldname": "no_of_docs",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Number of Docs"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-08 23:10:46.166744",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Transaction Deletion Record Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
new file mode 100644
index 0000000000..2176cb10de
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class TransactionDeletionRecordItem(Document):
+ pass
From 1a48eb49cf912223913698383fce7568c52d510b Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Mon, 10 May 2021 14:37:10 +0530
Subject: [PATCH 081/149] fix: Client script breaking while settings tax labels
---
erpnext/public/js/controllers/transaction.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index f91b432a39..43eea1357a 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1351,7 +1351,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
});
}
- if(this.frm.fields_dict["taxes"]) {
+ if(this.frm.doc.taxes && this.frm.doc.taxes.length > 0) {
this.frm.set_currency_labels(["tax_amount", "total", "tax_amount_after_discount"], this.frm.doc.currency, "taxes");
this.frm.set_currency_labels(["base_tax_amount", "base_total", "base_tax_amount_after_discount"], company_currency, "taxes");
From 13dfb9734cb8a32a88b425177b0803fc7a838505 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Mon, 10 May 2021 15:38:32 +0530
Subject: [PATCH 082/149] fix: Lable for transaction child tables
---
erpnext/public/js/controllers/transaction.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 43eea1357a..a3f4de48b8 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1329,7 +1329,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
this.toggle_item_grid_columns(company_currency);
- if(this.frm.fields_dict["operations"]) {
+ if(this.frm.doc.operations && this.frm.doc.operations.length > 0) {
this.frm.set_currency_labels(["operating_cost", "hour_rate"], this.frm.doc.currency, "operations");
this.frm.set_currency_labels(["base_operating_cost", "base_hour_rate"], company_currency, "operations");
@@ -1340,7 +1340,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
});
}
- if(this.frm.fields_dict["scrap_items"]) {
+ if(this.frm.doc.scrap_items && this.frm.doc.scrap_items.length > 0) {
this.frm.set_currency_labels(["rate", "amount"], this.frm.doc.currency, "scrap_items");
this.frm.set_currency_labels(["base_rate", "base_amount"], company_currency, "scrap_items");
@@ -1357,7 +1357,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
this.frm.set_currency_labels(["base_tax_amount", "base_total", "base_tax_amount_after_discount"], company_currency, "taxes");
}
- if(this.frm.fields_dict["advances"]) {
+ if(this.frm.doc.advances && this.frm.doc.advances.length > 0) {
this.frm.set_currency_labels(["advance_amount", "allocated_amount"],
this.frm.doc.party_account_currency, "advances");
}
@@ -1384,7 +1384,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
company_currency, "payment_schedule");
this.frm.set_currency_labels(["payment_amount", "outstanding", "paid_amount"],
this.frm.doc.currency, "payment_schedule");
-
+
var schedule_grid = this.frm.fields_dict["payment_schedule"].grid;
$.each(["base_payment_amount", "base_outstanding", "base_paid_amount"], function(i, fname) {
if (frappe.meta.get_docfield(schedule_grid.doctype, fname))
From 55d47a2baaeb9d10c991ecfc048fba5ff853869b Mon Sep 17 00:00:00 2001
From: Saqib
Date: Mon, 10 May 2021 15:59:37 +0530
Subject: [PATCH 083/149] fix(pos): UI fixes related to overflowing payment
section (#25652)
* fix: additional fields overflowing in payment section
* fix: pos profile filter in pos opening dialog
* fix: item quantity pill
---
erpnext/public/scss/point-of-sale.scss | 29 ++++++++++++++++++-
.../page/point_of_sale/pos_controller.js | 2 +-
.../page/point_of_sale/pos_item_selector.js | 10 ++++---
3 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/erpnext/public/scss/point-of-sale.scss b/erpnext/public/scss/point-of-sale.scss
index 0bb8e68b69..9bdaa8d1ee 100644
--- a/erpnext/public/scss/point-of-sale.scss
+++ b/erpnext/public/scss/point-of-sale.scss
@@ -129,11 +129,20 @@
@extend .pointer-no-select;
border-radius: var(--border-radius-md);
box-shadow: var(--shadow-base);
+ position: relative;
&:hover {
transform: scale(1.02, 1.02);
}
+ .item-qty-pill {
+ position: absolute;
+ display: flex;
+ margin: var(--margin-sm);
+ justify-content: flex-end;
+ right: 0px;
+ }
+
.item-display {
display: flex;
align-items: center;
@@ -766,9 +775,10 @@
> .payment-modes {
display: flex;
padding-bottom: var(--padding-sm);
- margin-bottom: var(--margin-xs);
+ margin-bottom: var(--margin-sm);
overflow-x: scroll;
overflow-y: hidden;
+ flex-shrink: 0;
> .payment-mode-wrapper {
min-width: 40%;
@@ -825,9 +835,24 @@
> .fields-numpad-container {
display: flex;
flex: 1;
+ height: 100%;
+ position: relative;
+ justify-content: flex-end;
> .fields-section {
flex: 1;
+ position: absolute;
+ display: flex;
+ flex-direction: column;
+ width: 50%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ padding-bottom: var(--margin-md);
+
+ .invoice-fields {
+ overflow-y: scroll;
+ }
}
> .number-pad {
@@ -835,6 +860,7 @@
display: flex;
justify-content: flex-end;
align-items: flex-end;
+ max-width: 50%;
.numpad-container {
display: grid;
@@ -861,6 +887,7 @@
margin-bottom: var(--margin-sm);
justify-content: center;
flex-direction: column;
+ flex-shrink: 0;
> .totals {
display: flex;
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index 8adf5bf747..8e0a1e1c18 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -58,7 +58,7 @@ erpnext.PointOfSale.Controller = class {
}
const pos_profile_query = {
query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
- filters: { company: frappe.defaults.get_default('company') }
+ filters: { company: dialog.fields_dict.company.get_value() }
}
const dialog = new frappe.ui.Dialog({
title: __('Create POS Opening Entry'),
diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js
index 9384ae5542..b8a82a9eda 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_selector.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js
@@ -90,14 +90,16 @@ erpnext.PointOfSale.ItemSelector = class {
function get_item_image_html() {
if (!me.hide_images && item_image) {
- return `
- ${qty_to_display}
+ return `
+ ${qty_to_display}
+
`;
} else {
- return `
- ${qty_to_display}
+ return `
+ ${qty_to_display}
+
${frappe.get_abbr(item.item_name)}
`;
}
}
From 9f0823a164e43c740f4aac0e9cb93559b5b06d13 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Mon, 10 May 2021 16:07:41 +0530
Subject: [PATCH 084/149] fix: Linting issues
---
erpnext/public/js/controllers/transaction.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index a3f4de48b8..7cfd939e95 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1329,7 +1329,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
this.toggle_item_grid_columns(company_currency);
- if(this.frm.doc.operations && this.frm.doc.operations.length > 0) {
+ if (this.frm.doc.operations && this.frm.doc.operations.length > 0) {
this.frm.set_currency_labels(["operating_cost", "hour_rate"], this.frm.doc.currency, "operations");
this.frm.set_currency_labels(["base_operating_cost", "base_hour_rate"], company_currency, "operations");
@@ -1340,7 +1340,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
});
}
- if(this.frm.doc.scrap_items && this.frm.doc.scrap_items.length > 0) {
+ if (this.frm.doc.scrap_items && this.frm.doc.scrap_items.length > 0) {
this.frm.set_currency_labels(["rate", "amount"], this.frm.doc.currency, "scrap_items");
this.frm.set_currency_labels(["base_rate", "base_amount"], company_currency, "scrap_items");
@@ -1351,13 +1351,13 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
});
}
- if(this.frm.doc.taxes && this.frm.doc.taxes.length > 0) {
+ if (this.frm.doc.taxes && this.frm.doc.taxes.length > 0) {
this.frm.set_currency_labels(["tax_amount", "total", "tax_amount_after_discount"], this.frm.doc.currency, "taxes");
this.frm.set_currency_labels(["base_tax_amount", "base_total", "base_tax_amount_after_discount"], company_currency, "taxes");
}
- if(this.frm.doc.advances && this.frm.doc.advances.length > 0) {
+ if (this.frm.doc.advances && this.frm.doc.advances.length > 0) {
this.frm.set_currency_labels(["advance_amount", "allocated_amount"],
this.frm.doc.party_account_currency, "advances");
}
From 5ce2da8bed06978d2e1a25656136997b8f2ccbde Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 10 May 2021 16:13:43 +0530
Subject: [PATCH 085/149] fix: Pass ORCHESTRATOR_URL via secrets
---
.github/workflows/server-tests.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index e7830c07f6..0acafcab43 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -76,6 +76,7 @@ jobs:
env:
TYPE: server
CI_BUILD_ID: ${{ github.run_id }}
+ ORCHESTRATOR_URL: ${{ secrets.ORCHESTRATOR_URL }}
- name: Upload Coverage Data
run: |
From a132de42ca37865175b722903871c3c367b68e48 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 10 May 2021 17:25:21 +0530
Subject: [PATCH 086/149] fix: allow_zero_valuation_rate for rejected qty
---
.../doctype/purchase_invoice/test_purchase_invoice.py | 7 ++++---
.../doctype/stock_ledger_entry/test_stock_ledger_entry.py | 2 ++
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 66be11ff23..53db689c84 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -636,8 +636,8 @@ class TestPurchaseInvoice(unittest.TestCase):
def test_rejected_serial_no(self):
pi = make_purchase_invoice(item_code="_Test Serialized Item With Series", received_qty=2, qty=1,
- rejected_qty=1, rate=500, update_stock=1,
- rejected_warehouse = "_Test Rejected Warehouse - _TC")
+ rejected_qty=1, rate=500, update_stock=1, rejected_warehouse = "_Test Rejected Warehouse - _TC",
+ allow_zero_valuation_rate=1)
self.assertEqual(frappe.db.get_value("Serial No", pi.get("items")[0].serial_no, "warehouse"),
pi.get("items")[0].warehouse)
@@ -994,7 +994,8 @@ def make_purchase_invoice(**args):
"project": args.project,
"rejected_warehouse": args.rejected_warehouse or "",
"rejected_serial_no": args.rejected_serial_no or "",
- "asset_location": args.location or ""
+ "asset_location": args.location or "",
+ "allow_zero_valuation_rate": args.get("allow_zero_valuation_rate") or 0
})
if args.get_taxes_and_charges:
diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
index 3296f5ba4a..a1f1897041 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
@@ -15,10 +15,12 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_pu
from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import create_landed_cost_voucher
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import BackDatedStockTransaction
+from frappe.core.page.permission_manager.permission_manager import reset
class TestStockLedgerEntry(unittest.TestCase):
def setUp(self):
items = create_items()
+ reset('Stock Entry')
# delete SLE and BINs for all items
frappe.db.sql("delete from `tabStock Ledger Entry` where item_code in (%s)" % (', '.join(['%s']*len(items))), items)
From 4d6d5f4d893c8dd10c3e4cf9f7b01fbe648320f8 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 10 May 2021 17:37:44 +0530
Subject: [PATCH 087/149] test: Fix valuation rate for raw materials
---
.../stock/doctype/purchase_receipt/test_purchase_receipt.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 78f77733a2..868e553dfc 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -240,6 +240,8 @@ class TestPurchaseReceipt(unittest.TestCase):
item_code = "Test Extra Item 1", qty=10, basic_rate=100)
se2 = make_stock_entry(target="_Test Warehouse - _TC",
item_code = "_Test FG Item", qty=1, basic_rate=100)
+ se3 = make_stock_entry(target="_Test Warehouse - _TC",
+ item_code = "Test Extra Item 2", qty=1, basic_rate=100)
rm_items = [
{
"item_code": item_code,
@@ -274,6 +276,7 @@ class TestPurchaseReceipt(unittest.TestCase):
se.cancel()
se1.cancel()
se2.cancel()
+ se3.cancel()
po.reload()
po.cancel()
From 018ccc2b6d1eb4d0844966f67fc166f26cbfcf19 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 10 May 2021 18:01:53 +0530
Subject: [PATCH 088/149] test: Fix test name
- Rename TestSubcontractedItemToBeReceived > TestSubcontractedItemToBeTransferred
---
...t_subcontracted_raw_materials_to_be_transferred.py | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py
index 6900938236..c1fc6fb82f 100644
--- a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py
+++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py
@@ -9,12 +9,12 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
from erpnext.buying.report.subcontracted_raw_materials_to_be_transferred.subcontracted_raw_materials_to_be_transferred import execute
import json, frappe, unittest
-class TestSubcontractedItemToBeReceived(unittest.TestCase):
+class TestSubcontractedItemToBeTransferred(unittest.TestCase):
- def test_pending_and_received_qty(self):
+ def test_pending_and_transferred_qty(self):
po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes')
- make_stock_entry(item_code='_Test Item', target='_Test Warehouse 1 - _TC', qty=100, basic_rate=100)
- make_stock_entry(item_code='_Test Item Home Desktop 100', target='_Test Warehouse 1 - _TC', qty=100, basic_rate=100)
+ make_stock_entry(item_code='_Test Item', target='_Test Warehouse - _TC', qty=100, basic_rate=100)
+ make_stock_entry(item_code='_Test Item Home Desktop 100', target='_Test Warehouse - _TC', qty=100, basic_rate=100)
transfer_subcontracted_raw_materials(po.name)
col, data = execute(filters=frappe._dict({'supplier': po.supplier,
'from_date': frappe.utils.get_datetime(frappe.utils.add_to_date(po.transaction_date, days=-10)),
@@ -38,7 +38,8 @@ def transfer_subcontracted_raw_materials(po):
'warehouse': '_Test Warehouse - _TC', 'rate': 100, 'amount': 200, 'stock_uom': 'Nos'}]
rm_item_string = json.dumps(rm_item)
se = frappe.get_doc(make_rm_stock_entry(po, rm_item_string))
+ se.from_warehouse = '_Test Warehouse 1 - _TC'
se.to_warehouse = '_Test Warehouse 1 - _TC'
se.stock_entry_type = 'Send to Subcontractor'
se.save()
- se.submit()
\ No newline at end of file
+ se.submit()
From 404e7d07c57da2de4ec65cf9aa44763787c64008 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 10 May 2021 18:39:09 +0530
Subject: [PATCH 089/149] test: Fix permission error
---
.../doctype/stock_ledger_entry/test_stock_ledger_entry.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
index a1f1897041..ba31ad7b06 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
@@ -316,10 +316,11 @@ class TestStockLedgerEntry(unittest.TestCase):
# Set User with Stock User role but not Stock Manager
try:
user = frappe.get_doc("User", "test@example.com")
- frappe.set_user(user.name)
user.add_roles("Stock User")
user.remove_roles("Stock Manager")
+ frappe.set_user(user.name)
+
stock_entry_on_today = make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100)
back_dated_se_1 = make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100,
posting_date=add_days(today(), -1), do_not_submit=True)
From a13c453c695f971c42cab5944dacfab17ab8d181 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 10 May 2021 20:33:47 +0530
Subject: [PATCH 090/149] test: Fix a case where test used to fail due to
holiday list
- fixes: "Please set a default Holiday List for Employee EMP-00009 or Company Wind Power LLC" error
---
.../hr/doctype/upload_attendance/test_upload_attendance.py | 7 +++++++
.../payroll/doctype/payroll_entry/test_payroll_entry.py | 6 ++++++
2 files changed, 13 insertions(+)
diff --git a/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py
index 6e151d0e3c..03b0cf3da2 100644
--- a/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py
+++ b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py
@@ -5,11 +5,18 @@ from __future__ import unicode_literals
import frappe
import unittest
+import erpnext
from frappe.utils import getdate
from erpnext.hr.doctype.upload_attendance.upload_attendance import get_data
from erpnext.hr.doctype.employee.test_employee import make_employee
+test_dependencies = ['Holiday List']
+
class TestUploadAttendance(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", '_Test Holiday List')
+
def test_date_range(self):
employee = make_employee("test_employee@company.com")
employee_doc = frappe.get_doc("Employee", employee)
diff --git a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
index 7528bf7a7f..b80b32061f 100644
--- a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
+++ b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
@@ -15,7 +15,13 @@ from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_
from erpnext.loan_management.doctype.loan.test_loan import create_loan, make_loan_disbursement_entry, create_loan_type, create_loan_accounts
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans
+test_dependencies = ['Holiday List']
+
class TestPayrollEntry(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", '_Test Holiday List')
+
def setUp(self):
for dt in ["Salary Slip", "Salary Component", "Salary Component Account",
"Payroll Entry", "Salary Structure", "Salary Structure Assignment", "Payroll Employee Detail", "Additional Salary"]:
From b3fadebb419ecc17fe2799a9ac0fdbd063e9b374 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 10 May 2021 20:49:07 +0530
Subject: [PATCH 091/149] style: Fix sider issues
---
.../test_accounting_period.py | 2 +-
.../test_leave_application.py | 60 +++++++++----------
.../leave_encashment/test_leave_encashment.py | 2 +-
3 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
index 3b4f138495..dc472c7695 100644
--- a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
+++ b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
@@ -40,7 +40,7 @@ def create_accounting_period(**args):
accounting_period.start_date = args.start_date or nowdate()
accounting_period.end_date = args.end_date or add_months(nowdate(), 1)
accounting_period.company = args.company or "_Test Company"
- accounting_period.period_name = args.period_name or "_Test_Period_Name_1"
+ accounting_period.period_name = args.period_name or "_Test_Period_Name_1"
accounting_period.append("closed_documents", {
"document_type": 'Sales Invoice', "closed": 1
})
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index a9379e230b..a4a96b813e 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -16,36 +16,36 @@ from erpnext.hr.doctype.employee.test_employee import make_employee
test_dependencies = ["Leave Allocation", "Leave Block List", "Employee"]
_test_records = [
- {
- "company": "_Test Company",
- "doctype": "Leave Application",
- "employee": "_T-Employee-00001",
- "from_date": "2013-05-01",
- "description": "_Test Reason",
- "leave_type": "_Test Leave Type",
- "posting_date": "2013-01-02",
- "to_date": "2013-05-05"
- },
- {
- "company": "_Test Company",
- "doctype": "Leave Application",
- "employee": "_T-Employee-00002",
- "from_date": "2013-05-01",
- "description": "_Test Reason",
- "leave_type": "_Test Leave Type",
- "posting_date": "2013-01-02",
- "to_date": "2013-05-05"
- },
- {
- "company": "_Test Company",
- "doctype": "Leave Application",
- "employee": "_T-Employee-00001",
- "from_date": "2013-01-15",
- "description": "_Test Reason",
- "leave_type": "_Test Leave Type LWP",
- "posting_date": "2013-01-02",
- "to_date": "2013-01-15"
- }
+ {
+ "company": "_Test Company",
+ "doctype": "Leave Application",
+ "employee": "_T-Employee-00001",
+ "from_date": "2013-05-01",
+ "description": "_Test Reason",
+ "leave_type": "_Test Leave Type",
+ "posting_date": "2013-01-02",
+ "to_date": "2013-05-05"
+ },
+ {
+ "company": "_Test Company",
+ "doctype": "Leave Application",
+ "employee": "_T-Employee-00002",
+ "from_date": "2013-05-01",
+ "description": "_Test Reason",
+ "leave_type": "_Test Leave Type",
+ "posting_date": "2013-01-02",
+ "to_date": "2013-05-05"
+ },
+ {
+ "company": "_Test Company",
+ "doctype": "Leave Application",
+ "employee": "_T-Employee-00001",
+ "from_date": "2013-01-15",
+ "description": "_Test Reason",
+ "leave_type": "_Test Leave Type LWP",
+ "posting_date": "2013-01-02",
+ "to_date": "2013-01-15"
+ }
]
diff --git a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
index 1f7fb6e68a..e0ffa5dd41 100644
--- a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
@@ -91,7 +91,7 @@ class TestLeaveEncashment(unittest.TestCase):
self.assertEqual(len(leave_ledger_entry), 1)
self.assertEqual(leave_ledger_entry[0].employee, leave_encashment.employee)
self.assertEqual(leave_ledger_entry[0].leave_type, leave_encashment.leave_type)
- self.assertEqual(leave_ledger_entry[0].leaves, leave_encashment.encashable_days * -1)
+ self.assertEqual(leave_ledger_entry[0].leaves, leave_encashment.encashable_days * -1)
# check if leave ledger entry is deleted on cancellation
From d2520680bc2f64d5a4692e63c70b129b2b46a8b7 Mon Sep 17 00:00:00 2001
From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Date: Mon, 10 May 2021 21:17:06 +0530
Subject: [PATCH 092/149] fix: Error on applying TDS without party (#25632)
* fix: Error on applying TDS without party
* fix: Add placeholder value
---
.../tax_withholding_category/tax_withholding_category.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index 09db7fee2b..5c1cbaa4aa 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -21,7 +21,10 @@ def get_party_details(inv):
else:
party_type = 'Supplier'
party = inv.supplier
-
+
+ if not party:
+ frappe.throw(_("Please select {0} first").format(party_type))
+
return party_type, party
def get_party_tax_withholding_details(inv, tax_withholding_category=None):
@@ -324,7 +327,7 @@ def get_tds_amount_from_ldc(ldc, parties, fiscal_year, pan_no, tax_details, post
net_total, ldc.certificate_limit
):
tds_amount = get_ltds_amount(net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details)
-
+
return tds_amount
def get_debit_note_amount(suppliers, fiscal_year_details, company=None):
From 6408367285f2912e7ecff57401d747e1bdd3a647 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Mon, 10 May 2021 23:48:37 +0530
Subject: [PATCH 093/149] ci: Add test orchestrator URL
---
.github/workflows/server-tests.yml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index 0acafcab43..bd60081064 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -76,7 +76,7 @@ jobs:
env:
TYPE: server
CI_BUILD_ID: ${{ github.run_id }}
- ORCHESTRATOR_URL: ${{ secrets.ORCHESTRATOR_URL }}
+ ORCHESTRATOR_URL: http://test-orchestrator.frappe.io
- name: Upload Coverage Data
run: |
@@ -87,7 +87,6 @@ jobs:
coveralls
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
COVERALLS_FLAG_NAME: run-${{ matrix.container }}
COVERALLS_SERVICE_NAME: ${{ github.event_name == 'pull_request' && 'github' || 'github-actions' }}
COVERALLS_PARALLEL: true
From 042118aafdd7e018d0ddedefb90ce66c30753634 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 11 May 2021 10:09:06 +0530
Subject: [PATCH 094/149] ci: Use only 3 containers for now
---
.github/workflows/server-tests.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index bd60081064..6597048bc7 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -10,7 +10,7 @@ jobs:
fail-fast: false
matrix:
- container: [1, 2, 3, 4]
+ container: [1, 2, 3]
name: Server Tests
From b76ebb3f4b0b4f4a975aff0fccfbc0d5c4c81e1e Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 11 May 2021 10:59:16 +0530
Subject: [PATCH 095/149] fix: Use frappe.safe_eval instead of eval
---
erpnext/setup/doctype/email_digest/email_digest.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index 5db54eeee1..340d89bdf8 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -249,7 +249,7 @@ class EmailDigest(Document):
card = cache.get(cache_key)
if card:
- card = eval(card)
+ card = frappe.safe_eval(card)
else:
card = frappe._dict(getattr(self, "get_" + key)())
From dd1822ef58dc24f32d5bf62d634c886a50d7a386 Mon Sep 17 00:00:00 2001
From: Mohammad Hasnain Mohsin Rajan
Date: Wed, 12 May 2021 13:01:53 +0530
Subject: [PATCH 096/149] fix: change links in workspace (#25673)
---
.../workspace/accounting/accounting.json | 29 ++++---------------
1 file changed, 5 insertions(+), 24 deletions(-)
diff --git a/erpnext/accounts/workspace/accounting/accounting.json b/erpnext/accounts/workspace/accounting/accounting.json
index 9ffa481c1c..df68318052 100644
--- a/erpnext/accounts/workspace/accounting/accounting.json
+++ b/erpnext/accounts/workspace/accounting/accounting.json
@@ -15,6 +15,7 @@
"hide_custom": 0,
"icon": "accounting",
"idx": 0,
+ "is_default": 0,
"is_standard": 1,
"label": "Accounting",
"links": [
@@ -625,9 +626,9 @@
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
- "label": "Bank Reconciliation",
- "link_to": "bank-reconciliation",
- "link_type": "Page",
+ "label": "Bank Reconciliation Tool",
+ "link_to": "Bank Reconciliation Tool",
+ "link_type": "DocType",
"onboard": 0,
"type": "Link"
},
@@ -641,26 +642,6 @@
"onboard": 0,
"type": "Link"
},
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Bank Statement Transaction Entry",
- "link_to": "Bank Statement Transaction Entry",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Bank Statement Settings",
- "link_to": "Bank Statement Settings",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
{
"hidden": 0,
"is_query_report": 0,
@@ -1071,7 +1052,7 @@
"type": "Link"
}
],
- "modified": "2021-03-04 00:38:35.349024",
+ "modified": "2021-05-12 11:48:01.905144",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting",
From aaca8335f080dca5078d90212bd810ced5f56d84 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Wed, 12 May 2021 16:36:25 +0530
Subject: [PATCH 097/149] fix: updated modified time to pull new fields
---
erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 24e67febca..d3d3ffa17f 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -1380,7 +1380,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
- "modified": "2021-03-30 22:45:58.334107",
+ "modified": "2021-04-30 22:45:58.334107",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
From 6578c045ca3d7cb40481caf0b4239420d5ab5cbb Mon Sep 17 00:00:00 2001
From: Afshan <33727827+AfshanKhan@users.noreply.github.com>
Date: Wed, 12 May 2021 17:41:50 +0530
Subject: [PATCH 098/149] fix: Dialog variable assignment after definition in
POS (#25680)
---
erpnext/selling/page/point_of_sale/pos_controller.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index 8e0a1e1c18..4f4f1b2240 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -56,10 +56,6 @@ erpnext.PointOfSale.Controller = class {
dialog.fields_dict.balance_details.grid.refresh();
});
}
- const pos_profile_query = {
- query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
- filters: { company: dialog.fields_dict.company.get_value() }
- }
const dialog = new frappe.ui.Dialog({
title: __('Create POS Opening Entry'),
static: true,
@@ -105,6 +101,10 @@ erpnext.PointOfSale.Controller = class {
primary_action_label: __('Submit')
});
dialog.show();
+ const pos_profile_query = {
+ query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
+ filters: { company: dialog.fields_dict.company.get_value() }
+ };
}
async prepare_app_defaults(data) {
From 1f025a84f54669ff6301bca60aa04001f18a5c59 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 12 May 2021 18:14:22 +0530
Subject: [PATCH 099/149] ci: Update frappe branch
---
.github/helper/install.sh | 2 +-
.github/workflows/server-tests.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/helper/install.sh b/.github/helper/install.sh
index 44659f22fa..7b0f944c66 100644
--- a/.github/helper/install.sh
+++ b/.github/helper/install.sh
@@ -12,7 +12,7 @@ sudo apt install npm
pip install frappe-bench
-git clone https://github.com/surajshetty3416/frappe --branch "python-distributed-testing" --depth 1
+git clone https://github.com/frappe/frappe --branch "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}" --depth 1
bench init --skip-assets --frappe-path ~/frappe --python "$(which python)" frappe-bench
mkdir ~/frappe-bench/sites/test_site
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index 6597048bc7..6f831ac3d1 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -12,7 +12,7 @@ jobs:
matrix:
container: [1, 2, 3]
- name: Server Tests
+ name: Python Unit Tests
services:
mysql:
From fe68a0ff80c8d807a5886d46f2d51ad33e6949f1 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Wed, 12 May 2021 19:42:04 +0530
Subject: [PATCH 100/149] fix: Woocommerce order sync issue
---
.../connectors/woocommerce_connection.py | 30 +++++++++----------
1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
index 6dedaa8c53..a505ee09d2 100644
--- a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
+++ b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
@@ -1,6 +1,7 @@
from __future__ import unicode_literals
import frappe, base64, hashlib, hmac, json
+from frappe.utils import cstr
from frappe import _
def verify_request():
@@ -146,22 +147,19 @@ def rename_address(address, customer):
def link_items(items_list, woocommerce_settings, sys_lang):
for item_data in items_list:
- item_woo_com_id = item_data.get("product_id")
+ item_woo_com_id = cstr(item_data.get("product_id"))
- if frappe.get_value("Item", {"woocommerce_id": item_woo_com_id}):
- #Edit Item
- item = frappe.get_doc("Item", {"woocommerce_id": item_woo_com_id})
- else:
+ if not frappe.db.get_value("Item", {"woocommerce_id": item_woo_com_id}, 'name'):
#Create Item
item = frappe.new_doc("Item")
+ item.item_code = _("woocommerce - {0}", sys_lang).format(item_woo_com_id)
+ item.stock_uom = woocommerce_settings.uom or _("Nos", sys_lang)
+ item.item_group = _("WooCommerce Products", sys_lang)
- item.item_name = item_data.get("name")
- item.item_code = _("woocommerce - {0}", sys_lang).format(item_data.get("product_id"))
- item.woocommerce_id = item_data.get("product_id")
- item.item_group = _("WooCommerce Products", sys_lang)
- item.stock_uom = woocommerce_settings.uom or _("Nos", sys_lang)
- item.flags.ignore_mandatory = True
- item.save()
+ item.item_name = item_data.get("name")
+ item.woocommerce_id = item_woo_com_id
+ item.flags.ignore_mandatory = True
+ item.save()
def create_sales_order(order, woocommerce_settings, customer_name, sys_lang):
new_sales_order = frappe.new_doc("Sales Order")
@@ -194,12 +192,12 @@ def set_items_in_sales_order(new_sales_order, woocommerce_settings, order, sys_l
for item in order.get("line_items"):
woocomm_item_id = item.get("product_id")
- found_item = frappe.get_doc("Item", {"woocommerce_id": woocomm_item_id})
+ found_item = frappe.get_doc("Item", {"woocommerce_id": cstr(woocomm_item_id)})
ordered_items_tax = item.get("total_tax")
- new_sales_order.append("items",{
- "item_code": found_item.item_code,
+ new_sales_order.append("items", {
+ "item_code": found_item.name,
"item_name": found_item.item_name,
"description": found_item.item_name,
"delivery_date": new_sales_order.delivery_date,
@@ -207,7 +205,7 @@ def set_items_in_sales_order(new_sales_order, woocommerce_settings, order, sys_l
"qty": item.get("quantity"),
"rate": item.get("price"),
"warehouse": woocommerce_settings.warehouse or default_warehouse
- })
+ })
add_tax_details(new_sales_order, ordered_items_tax, "Ordered Item tax", woocommerce_settings.tax_account)
From 28fdb2e6fae00abae6df5df5e3dbe4fba0430f31 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 12 May 2021 23:13:11 +0530
Subject: [PATCH 101/149] ci: Update Python version to 3.7
---
.github/workflows/server-tests.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index 6f831ac3d1..92685e2177 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -30,7 +30,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v2
with:
- python-version: 3.6
+ python-version: 3.7
- name: Add to Hosts
run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
From c55aa295fcfc90dd79a72cd38db4396e8f1f4485 Mon Sep 17 00:00:00 2001
From: David Angulo
Date: Thu, 13 May 2021 01:46:04 -0500
Subject: [PATCH 102/149] fix: Translate weekday when getting weekly off dates
(#25691)
---
erpnext/hr/doctype/holiday_list/holiday_list.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/hr/doctype/holiday_list/holiday_list.py b/erpnext/hr/doctype/holiday_list/holiday_list.py
index 8af8cea605..f65e6e1207 100644
--- a/erpnext/hr/doctype/holiday_list/holiday_list.py
+++ b/erpnext/hr/doctype/holiday_list/holiday_list.py
@@ -23,7 +23,7 @@ class HolidayList(Document):
last_idx = max([cint(d.idx) for d in self.get("holidays")] or [0,])
for i, d in enumerate(date_list):
ch = self.append('holidays', {})
- ch.description = self.weekly_off
+ ch.description = _(self.weekly_off)
ch.holiday_date = d
ch.weekly_off = 1
ch.idx = last_idx + i + 1
From 0eb3a38c9d9fc0094183259b9950ae03b9c727c8 Mon Sep 17 00:00:00 2001
From: Prssanna Desai
Date: Thu, 13 May 2021 12:17:28 +0530
Subject: [PATCH 103/149] fix: quiz evalutation issue (#25671)
---
erpnext/public/js/education/lms/quiz.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/public/js/education/lms/quiz.js b/erpnext/public/js/education/lms/quiz.js
index 32fa4ab1ec..5683f73d1b 100644
--- a/erpnext/public/js/education/lms/quiz.js
+++ b/erpnext/public/js/education/lms/quiz.js
@@ -118,7 +118,7 @@ class Quiz {
quiz_response: this.get_selected(),
course: this.course,
program: this.program,
- time_taken: this.is_time_bound ? this.time_taken : ""
+ time_taken: this.is_time_bound ? this.time_taken : 0
}).then(res => {
this.submit_btn.remove()
if (!res.message) {
From ab1ae418ccac57709c6feb4b0f53375eba271997 Mon Sep 17 00:00:00 2001
From: Anuja P
Date: Thu, 13 May 2021 14:26:27 +0530
Subject: [PATCH 104/149] fix: Process SOA enhancement
---
.../process_statement_of_accounts.html | 118 +++++++++++-------
.../process_statement_of_accounts.json | 19 ++-
.../process_statement_of_accounts.py | 8 +-
3 files changed, 93 insertions(+), 52 deletions(-)
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
index b623898829..b3aca53139 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
@@ -1,24 +1,43 @@
-{{ filters.party[0] }}
-{{ _("Statement of Accounts") }}
+
+
+
-
- {{ frappe.format(filters.from_date, 'Date')}}
- {{ _("to") }}
- {{ frappe.format(filters.to_date, 'Date')}}
-
+
{{ _("STATEMENTS OF ACCOUNTS") }}
+
+
{{ _("Customer: ") }} {{filters.party[0] }}
+
+ {{ _("Date: ") }}
+ {{ frappe.format(filters.from_date, 'Date')}}
+ {{ _("to") }}
+ {{ frappe.format(filters.to_date, 'Date')}}
+
+
+
-
-
-
- {{ _("Date") }}
- {{ _("Ref") }}
- {{ _("Party") }}
- {{ _("Debit") }}
- {{ _("Credit") }}
- {{ _("Balance (Dr - Cr)") }}
-
-
-
+
+
+
+ {{ _("Date") }}
+ {{ _("Reference") }}
+ {{ _("Remarks") }}
+ {{ _("Debit") }}
+ {{ _("Credit") }}
+ {{ _("Balance (Dr - Cr)") }}
+
+
+
{% for row in data %}
{% if(row.posting_date) %}
@@ -58,32 +77,35 @@
{% endfor %}
-
-
-{% if aging %}
-{{ _("Ageing Report Based On ") }} {{ aging.ageing_based_on }}
-
- {{ _("Up to " ) }} {{ frappe.format(filters.to_date, 'Date')}}
-
-
-
-
-
-
- 30 Days
- 60 Days
- 90 Days
- 120 Days
-
-
-
-
- {{ frappe.utils.fmt_money(aging.range1, currency=filters.presentation_currency) }}
- {{ frappe.utils.fmt_money(aging.range2, currency=filters.presentation_currency) }}
- {{ frappe.utils.fmt_money(aging.range3, currency=filters.presentation_currency) }}
- {{ frappe.utils.fmt_money(aging.range4, currency=filters.presentation_currency) }}
-
-
-
-{% endif %}
-Printed On {{ frappe.format(frappe.utils.get_datetime(), 'Datetime') }}
\ No newline at end of file
+
+
+ {% if aging %}
+
{{ _("Ageing Report based on ") }} {{ aging.ageing_based_on }}
+ {{ _("up to " ) }} {{ frappe.format(filters.to_date, 'Date')}}
+
+
+
+
+ 30 Days
+ 60 Days
+ 90 Days
+ 120 Days
+
+
+
+
+ {{ frappe.utils.fmt_money(aging.range1, currency=filters.presentation_currency) }}
+ {{ frappe.utils.fmt_money(aging.range2, currency=filters.presentation_currency) }}
+ {{ frappe.utils.fmt_money(aging.range3, currency=filters.presentation_currency) }}
+ {{ frappe.utils.fmt_money(aging.range4, currency=filters.presentation_currency) }}
+
+
+
+ {% endif %}
+
+ {% if terms_and_conditions %}
+
+ {{ terms_and_conditions }}
+
+ {% endif %}
+
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
index 4be0e2ec06..922f6367df 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
@@ -1,6 +1,5 @@
{
"actions": [],
- "allow_workflow": 1,
"autoname": "Prompt",
"creation": "2020-05-22 16:46:18.712954",
"doctype": "DocType",
@@ -28,9 +27,11 @@
"customers",
"preferences",
"orientation",
- "section_break_14",
"include_ageing",
"ageing_based_on",
+ "section_break_14",
+ "letter_head",
+ "terms_and_conditions",
"section_break_1",
"enable_auto_email",
"section_break_18",
@@ -270,10 +271,22 @@
"fieldname": "body",
"fieldtype": "Text Editor",
"label": "Body"
+ },
+ {
+ "fieldname": "letter_head",
+ "fieldtype": "Link",
+ "label": "Letter Head",
+ "options": "Letter Head"
+ },
+ {
+ "fieldname": "terms_and_conditions",
+ "fieldtype": "Link",
+ "label": "Terms and Conditions",
+ "options": "Terms and Conditions"
}
],
"links": [],
- "modified": "2020-08-08 08:47:09.185728",
+ "modified": "2021-05-13 12:44:19.574844",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index b6149e89f5..c388669592 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -62,6 +62,9 @@ def get_report_pdf(doc, consolidated=True):
tax_id = frappe.get_doc('Customer', entry.customer).tax_id
presentation_currency = get_party_account_currency('Customer', entry.customer, doc.company) \
or doc.currency or get_company_currency(doc.company)
+ if doc.letter_head:
+ from frappe.www.printview import get_letter_head
+ letter_head = get_letter_head(doc, 0)
filters= frappe._dict({
'from_date': doc.from_date,
@@ -88,7 +91,10 @@ def get_report_pdf(doc, consolidated=True):
if len(res) == 3:
continue
html = frappe.render_template(template_path, \
- {"filters": filters, "data": res, "aging": aging[0] if doc.include_ageing else None})
+ {"filters": filters, "data": res, "aging": aging[0] if doc.include_ageing else None,
+ "letter_head": letter_head if doc.letter_head else None,
+ "terms_and_conditions": frappe.db.get_value('Terms and Conditions', doc.terms_and_conditions, 'terms')
+ if doc.terms_and_conditions else None})
html = frappe.render_template(base_template_path, {"body": html, \
"css": get_print_style(), "title": "Statement For " + entry.customer})
statement_dict[entry.customer] = html
From e90a2a346b9de9efe1a0abd13c804568dfc27343 Mon Sep 17 00:00:00 2001
From: Anuja P
Date: Thu, 13 May 2021 15:15:47 +0530
Subject: [PATCH 105/149] fix: update new changes
---
.../process_statement_of_accounts.html | 12 ++++++------
.../process_statement_of_accounts.py | 2 +-
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
index f44d595332..db1fea192e 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
@@ -79,8 +79,8 @@
- {% if aging %}
- {{ _("Ageing Report based on ") }} {{ aging.ageing_based_on }}
+ {% if ageing %}
+ {{ _("Ageing Report based on ") }} {{ ageing.ageing_based_on }}
{{ _("up to " ) }} {{ frappe.format(filters.to_date, 'Date')}}
@@ -94,10 +94,10 @@
- {{ frappe.utils.fmt_money(aging.range1, currency=filters.presentation_currency) }}
- {{ frappe.utils.fmt_money(aging.range2, currency=filters.presentation_currency) }}
- {{ frappe.utils.fmt_money(aging.range3, currency=filters.presentation_currency) }}
- {{ frappe.utils.fmt_money(aging.range4, currency=filters.presentation_currency) }}
+ {{ frappe.utils.fmt_money(ageing.range1, currency=filters.presentation_currency) }}
+ {{ frappe.utils.fmt_money(ageing.range2, currency=filters.presentation_currency) }}
+ {{ frappe.utils.fmt_money(ageing.range3, currency=filters.presentation_currency) }}
+ {{ frappe.utils.fmt_money(ageing.range4, currency=filters.presentation_currency) }}
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index 01157d6eaf..cf79c03935 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -94,7 +94,7 @@ def get_report_pdf(doc, consolidated=True):
continue
html = frappe.render_template(template_path, \
- {"filters": filters, "data": res, "aging": aging[0] if doc.include_ageing else None,
+ {"filters": filters, "data": res, "ageing": ageing[0] if doc.include_ageing else None,
"letter_head": letter_head if doc.letter_head else None,
"terms_and_conditions": frappe.db.get_value('Terms and Conditions', doc.terms_and_conditions, 'terms')
if doc.terms_and_conditions else None})
From 8e748f8451db11e08cc0a920e1d0eea7c75e6a56 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Thu, 13 May 2021 14:59:28 +0530
Subject: [PATCH 106/149] fix: Parameter for
get_filtered_list_for_consolidated_report in consolidated balance sheet
---
erpnext/accounts/report/balance_sheet/balance_sheet.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py
index 287b8a7484..26bb44f4f7 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.py
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py
@@ -135,7 +135,7 @@ def get_report_summary(period_list, asset, liability, equity, provisional_profit
# from consolidated financial statement
if filters.get('accumulated_in_group_company'):
- period_list = get_filtered_list_for_consolidated_report(period_list)
+ period_list = get_filtered_list_for_consolidated_report(filters, period_list)
for period in period_list:
key = period if consolidated else period.key
From 7c6de1a8ac2ec818a796fe54268d0650d71ffb9b Mon Sep 17 00:00:00 2001
From: Mohammad Hasnain Mohsin Rajan
Date: Thu, 13 May 2021 17:28:49 +0530
Subject: [PATCH 107/149] fix: bank statement import via google sheet (#25677)
* fix: change links in workspace
* fix: google sheet bank statement import
* chore: quotes
* fix: capitalization
* fix: typo
* chore: add translation
---
.../bank_statement_import.js | 1 +
.../bank_statement_import.json | 6 +++---
.../bank_statement_import.py | 18 ++++++++++++++----
3 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
index 3dbd605344..016f29a7b5 100644
--- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
@@ -239,6 +239,7 @@ frappe.ui.form.on("Bank Statement Import", {
"withdrawal",
"description",
"reference_number",
+ "bank_account"
],
},
});
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json
index 5e913cc2aa..7ffff02850 100644
--- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json
@@ -146,7 +146,7 @@
},
{
"depends_on": "eval:!doc.__islocal && !doc.import_file\n",
- "description": "Must be a publicly accessible Google Sheets URL",
+ "description": "Must be a publicly accessible Google Sheets URL and adding Bank Account column is necessary for importing via Google Sheets",
"fieldname": "google_sheets_url",
"fieldtype": "Data",
"label": "Import from Google Sheets"
@@ -202,7 +202,7 @@
],
"hide_toolbar": 1,
"links": [],
- "modified": "2021-02-10 19:29:59.027325",
+ "modified": "2021-05-12 14:17:37.777246",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Statement Import",
@@ -224,4 +224,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
index 9f41b13f4b..5f110e2727 100644
--- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
@@ -47,6 +47,13 @@ class BankStatementImport(DataImport):
def start_import(self):
+ preview = frappe.get_doc("Bank Statement Import", self.name).get_preview_from_template(
+ self.import_file, self.google_sheets_url
+ )
+
+ if 'Bank Account' not in json.dumps(preview):
+ frappe.throw(_("Please add the Bank Account column"))
+
from frappe.core.page.background_jobs.background_jobs import get_info
from frappe.utils.scheduler import is_scheduler_inactive
@@ -67,6 +74,7 @@ class BankStatementImport(DataImport):
data_import=self.name,
bank_account=self.bank_account,
import_file_path=self.import_file,
+ google_sheets_url=self.google_sheets_url,
bank=self.bank,
template_options=self.template_options,
now=frappe.conf.developer_mode or frappe.flags.in_test,
@@ -90,18 +98,20 @@ def download_errored_template(data_import_name):
data_import = frappe.get_doc("Bank Statement Import", data_import_name)
data_import.export_errored_rows()
-def start_import(data_import, bank_account, import_file_path, bank, template_options):
+def start_import(data_import, bank_account, import_file_path, google_sheets_url, bank, template_options):
"""This method runs in background job"""
update_mapping_db(bank, template_options)
data_import = frappe.get_doc("Bank Statement Import", data_import)
+ file = import_file_path if import_file_path else google_sheets_url
- import_file = ImportFile("Bank Transaction", file = import_file_path, import_type="Insert New Records")
+ import_file = ImportFile("Bank Transaction", file = file, import_type="Insert New Records")
data = import_file.raw_data
- add_bank_account(data, bank_account)
- write_files(import_file, data)
+ if import_file_path:
+ add_bank_account(data, bank_account)
+ write_files(import_file, data)
try:
i = Importer(data_import.reference_doctype, data_import=data_import)
From aca8c34c4dfb8e9e8b97b5f5130f884dab266b34 Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Thu, 13 May 2021 12:11:41 +0000
Subject: [PATCH 108/149] fix: filter for Indian workspace card
---
erpnext/accounts/workspace/accounting/accounting.json | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/accounts/workspace/accounting/accounting.json b/erpnext/accounts/workspace/accounting/accounting.json
index df68318052..27c55cc176 100644
--- a/erpnext/accounts/workspace/accounting/accounting.json
+++ b/erpnext/accounts/workspace/accounting/accounting.json
@@ -684,6 +684,7 @@
"is_query_report": 0,
"label": "Goods and Services Tax (GST India)",
"onboard": 0,
+ "only_for": "India",
"type": "Card Break"
},
{
From a0a88a710ebd989eae8c2918a286961c79e4f65d Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Thu, 13 May 2021 17:42:06 +0530
Subject: [PATCH 109/149] fix: change today to now to get data for reposting
---
.../doctype/repost_item_valuation/repost_item_valuation.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index 3f83780569..63c71891e4 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe, erpnext
from frappe.model.document import Document
-from frappe.utils import cint, get_link_to_form, add_to_date, today
+from frappe.utils import cint, get_link_to_form, add_to_date, now, today
from erpnext.stock.stock_ledger import repost_future_sle
from erpnext.accounts.utils import update_gl_entries_after, check_if_stock_and_account_balance_synced
from frappe.utils.user import get_users_with_role
@@ -127,7 +127,7 @@ def repost_entries():
check_if_stock_and_account_balance_synced(today(), d.name)
def get_repost_item_valuation_entries():
- date = add_to_date(today(), hours=-3)
+ date = add_to_date(now(), hours=-3)
return frappe.db.sql(""" SELECT name from `tabRepost Item Valuation`
WHERE status != 'Completed' and creation <= %s and docstatus = 1
From 3503598735de13b8a87984ca66f187432770dab8 Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Tue, 23 Feb 2021 18:57:52 +0000
Subject: [PATCH 110/149] Initial commit of Tax Detail report and report
builder
---
.../accounts/report/tax_detail/__init__.py | 0
.../accounts/report/tax_detail/tax_detail.js | 165 +++++++++++++++++
.../report/tax_detail/tax_detail.json | 32 ++++
.../accounts/report/tax_detail/tax_detail.py | 169 ++++++++++++++++++
4 files changed, 366 insertions(+)
create mode 100644 erpnext/accounts/report/tax_detail/__init__.py
create mode 100644 erpnext/accounts/report/tax_detail/tax_detail.js
create mode 100644 erpnext/accounts/report/tax_detail/tax_detail.json
create mode 100644 erpnext/accounts/report/tax_detail/tax_detail.py
diff --git a/erpnext/accounts/report/tax_detail/__init__.py b/erpnext/accounts/report/tax_detail/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.js b/erpnext/accounts/report/tax_detail/tax_detail.js
new file mode 100644
index 0000000000..1ac11409e3
--- /dev/null
+++ b/erpnext/accounts/report/tax_detail/tax_detail.js
@@ -0,0 +1,165 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+// Contributed by Case Solved and sponsored by Nulight Studios
+/* eslint-disable */
+
+frappe.query_reports["Tax Detail"] = {
+ "filters": [
+ {
+ "fieldname":"company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "default": frappe.defaults.get_user_default("company"),
+ "reqd": 1
+ },
+ {
+ "fieldname":"from_date",
+ "label": __("From Date"),
+ "fieldtype": "Date",
+ "default": frappe.datetime.month_start(frappe.datetime.get_today()),
+ "reqd": 1,
+ "width": "60px"
+ },
+ {
+ "fieldname":"to_date",
+ "label": __("To Date"),
+ "fieldtype": "Date",
+ "default": frappe.datetime.month_end(frappe.datetime.get_today()),
+ "reqd": 1,
+ "width": "60px"
+ },
+ ],
+ onload: function(report) {
+ report.page.add_inner_button(__("New Report"), () => new_report(), __("Custom Report"));
+ report.page.add_inner_button(__("Load Report"), () => load_report(), __("Custom Report"));
+ load_page_report();
+ }
+};
+
+class TaxReport {
+ constructor() {
+ this.report = frappe.query_reports["Tax Detail"]
+ this.qr = frappe.query_report
+ this.page = frappe.query_report.page
+ this.create_controls()
+ }
+ save_report() {
+ frappe.call({
+ method:'erpnext.accounts.report.tax_detail.tax_detail.new_custom_report',
+ args: {'name': values.report_name},
+ freeze: true
+ }).then((r) => {
+ frappe.set_route("query-report", values.report_name);
+ });
+ }
+ create_controls() {
+ this.section_name = this.page.add_field({
+ label: 'Section',
+ fieldtype: 'Select',
+ fieldname: 'section_name',
+ change() {
+ this.taxreport.set_section()
+ }
+ });
+ this.new_section = this.page.add_field({
+ label: 'New Section',
+ fieldtype: 'Button',
+ fieldname: 'new_section'
+ });
+ this.delete_section = this.page.add_field({
+ label: 'Delete Section',
+ fieldtype: 'Button',
+ fieldname: 'delete_section'
+ });
+ this.page.add_field({
+ label: 'Filter',
+ fieldtype: 'Select',
+ fieldname: 'filter_index'
+ });
+ this.page.add_field({
+ label: 'Add Filter',
+ fieldtype: 'Button',
+ fieldname: 'add_filter'
+ });
+ this.page.add_field({
+ label: 'Delete Filter',
+ fieldtype: 'Button',
+ fieldname: 'delete_filter'
+ });
+ this.page.add_field({
+ label: 'Value Column',
+ fieldtype: 'Select',
+ fieldname: 'value_field',
+ });
+ this.page.add_field({
+ label: 'Save',
+ fieldtype: 'Button',
+ fieldname: 'save'
+ });
+ }
+}
+
+function get_reports(cb) {
+ frappe.call({
+ method: 'erpnext.accounts.report.tax_detail.tax_detail.get_custom_reports',
+ freeze: true
+ }).then((r) => {
+ cb(r.message);
+ })
+}
+
+function new_report() {
+ const dialog = new frappe.ui.Dialog({
+ title: __("New Report"),
+ fields: [
+ {
+ fieldname: 'report_name',
+ label: 'Report Name',
+ fieldtype: 'Data',
+ default: 'VAT Return'
+ }
+ ],
+ primary_action_label: __('Create'),
+ primary_action: function new_report_pa(values) {
+ frappe.call({
+ method:'erpnext.accounts.report.tax_detail.tax_detail.new_custom_report',
+ args: {'name': values.report_name},
+ freeze: true
+ }).then((r) => {
+ frappe.set_route("query-report", values.report_name);
+ });
+ dialog.hide();
+ }
+ });
+ dialog.show();
+}
+
+function load_page_report() {
+ if (frappe.query_report.report_name === 'Tax Detail') {
+ return;
+ }
+ this.taxreport = new TaxReport();
+}
+
+function load_report() {
+ get_reports(function load_report_cb(reports) {
+ const dialog = new frappe.ui.Dialog({
+ title: __("Load Report"),
+ fields: [
+ {
+ fieldname: 'report_name',
+ label: 'Report Name',
+ fieldtype: 'Select',
+ options: Object.keys(reports)
+ }
+ ],
+ primary_action_label: __('Load'),
+ primary_action: function load_report_pa(values) {
+ dialog.hide();
+ frappe.set_route("query-report", values.report_name);
+ }
+ });
+ dialog.show();
+ });
+}
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.json b/erpnext/accounts/report/tax_detail/tax_detail.json
new file mode 100644
index 0000000000..d52ffd05ac
--- /dev/null
+++ b/erpnext/accounts/report/tax_detail/tax_detail.json
@@ -0,0 +1,32 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2021-02-19 16:44:21.175113",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2021-02-19 16:44:21.175113",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Tax Detail",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "GL Entry",
+ "report_name": "Tax Detail",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Accounts User"
+ },
+ {
+ "role": "Accounts Manager"
+ },
+ {
+ "role": "Auditor"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py
new file mode 100644
index 0000000000..46e7ae08e9
--- /dev/null
+++ b/erpnext/accounts/report/tax_detail/tax_detail.py
@@ -0,0 +1,169 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+# Contributed by Case Solved and sponsored by Nulight Studios
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+
+# field lists in multiple doctypes will be coalesced
+required_sql_fields = {
+ "GL Entry": ["posting_date", "voucher_type", "voucher_no", "account", "account_currency", "debit", "credit"],
+ "Account": ["account_type"],
+ ("Purchase Invoice", "Sales Invoice"): ["taxes_and_charges", "tax_category"],
+ ("Purchase Invoice Item", "Sales Invoice Item"): ["item_tax_template", "item_name", "base_net_amount", "item_tax_rate"],
+# "Journal Entry": ["total_amount_currency"],
+# "Journal Entry Account": ["debit_in_account_currency", "credit_in_account_currency"]
+}
+
+@frappe.whitelist()
+def get_required_fieldlist():
+ """For overriding the fieldlist from the client"""
+ return required_sql_fields
+
+def execute(filters=None, fieldlist=required_sql_fields):
+ if not filters:
+ return [], []
+
+ fieldstr = get_fieldstr(fieldlist)
+
+ gl_entries = frappe.db.sql("""
+ select {fieldstr}
+ from `tabGL Entry` ge
+ inner join `tabAccount` a on
+ ge.account=a.name and ge.company=a.company
+ left join `tabSales Invoice` si on
+ a.account_type='Tax' and ge.company=si.company and ge.voucher_type='Sales Invoice' and ge.voucher_no=si.name
+ left join `tabSales Invoice Item` sii on
+ si.name=sii.parent
+ left join `tabPurchase Invoice` pi on
+ a.account_type='Tax' and ge.company=pi.company and ge.voucher_type='Purchase Invoice' and ge.voucher_no=pi.name
+ left join `tabPurchase Invoice Item` pii on
+ pi.name=pii.parent
+/* left outer join `tabJournal Entry` je on
+ ge.voucher_no=je.name and ge.company=je.company
+ left outer join `tabJournal Entry Account` jea on
+ je.name=jea.parent and a.account_type='Tax' */
+ where (ge.voucher_type, ge.voucher_no) in (
+ select ge.voucher_type, ge.voucher_no
+ from `tabGL Entry` ge
+ join `tabAccount` a on ge.account=a.name and ge.company=a.company
+ where
+ a.account_type='Tax' and
+ ge.company=%(company)s and
+ ge.posting_date>=%(from_date)s and
+ ge.posting_date<=%(to_date)s
+ )
+ order by ge.posting_date, ge.voucher_no
+ """.format(fieldstr=fieldstr), filters, as_dict=1)
+
+ gl_entries = modify_report_data(gl_entries)
+
+ return get_columns(fieldlist), gl_entries
+
+
+abbrev = lambda dt: ''.join(l[0].lower() for l in dt.split(' ')) + '.'
+doclist = lambda dt, dfs: [abbrev(dt) + f for f in dfs]
+coalesce = lambda dts, dfs: ['coalesce(' + ', '.join(abbrev(dt) + f for dt in dts) + ') ' + f for f in dfs]
+
+def get_fieldstr(fieldlist):
+ fields = []
+ for doctypes, docfields in fieldlist.items():
+ if isinstance(doctypes, str):
+ fields += doclist(doctypes, docfields)
+ if isinstance(doctypes, tuple):
+ fields += coalesce(doctypes, docfields)
+ return ', '.join(fields)
+
+def get_columns(fieldlist):
+ columns = {}
+ for doctypes, docfields in fieldlist.items():
+ if isinstance(doctypes, str):
+ doctypes = [doctypes]
+ for doctype in doctypes:
+ meta = frappe.get_meta(doctype)
+ # get column field metadata from the db
+ fieldmeta = {}
+ for field in meta.get('fields'):
+ if field.fieldname in docfields:
+ fieldmeta[field.fieldname] = {
+ "label": _(field.label),
+ "fieldname": field.fieldname,
+ "fieldtype": field.fieldtype,
+ "options": field.options
+ }
+ # edit the columns to match the modified data
+ for field in docfields:
+ col = modify_report_columns(doctype, field, fieldmeta[field])
+ if col:
+ columns[col["fieldname"]] = col
+ # use of a dict ensures duplicate columns are removed
+ return list(columns.values())
+
+def modify_report_columns(doctype, field, column):
+ "Because data is rearranged into other columns"
+ if doctype in ["Sales Invoice Item", "Purchase Invoice Item"] and field == "item_tax_rate":
+ return None
+ if doctype == "Sales Invoice Item" and field == "base_net_amount":
+ column.update({"label": _("Credit Net Amount"), "fieldname": "credit_net_amount"})
+ if doctype == "Purchase Invoice Item" and field == "base_net_amount":
+ column.update({"label": _("Debit Net Amount"), "fieldname": "debit_net_amount"})
+ if field == "taxes_and_charges":
+ column.update({"label": _("Taxes and Charges Template")})
+ return column
+
+def modify_report_data(data):
+ import json
+ for line in data:
+ if line.account_type == "Tax" and line.item_tax_rate:
+ tax_rates = json.loads(line.item_tax_rate)
+ for account, rate in tax_rates.items():
+ if account == line.account:
+ if line.voucher_type == "Sales Invoice":
+ line.credit = line.base_net_amount * (rate / 100)
+ line.credit_net_amount = line.base_net_amount
+ if line.voucher_type == "Purchase Invoice":
+ line.debit = line.base_net_amount * (rate / 100)
+ line.debit_net_amount = line.base_net_amount
+ return data
+
+####### JS client utilities
+
+custom_report_dict = {
+ 'ref_doctype': 'GL Entry',
+ 'report_type': 'Custom Report',
+ 'reference_report': 'Tax Detail'
+}
+
+@frappe.whitelist()
+def get_custom_reports():
+ reports = frappe.get_list('Report',
+ filters = custom_report_dict,
+ fields = ['name', 'json'],
+ as_list=False
+ )
+ reports_dict = {rep.pop('name'): rep for rep in reports}
+ # Prevent custom reports with the same name
+ reports_dict['Tax Detail'] = {'json': None}
+ return reports_dict
+
+@frappe.whitelist()
+def new_custom_report(name=None):
+ if name == 'Tax Detail':
+ frappe.throw("The parent report cannot be overwritten.")
+ if not name:
+ frappe.throw("The report name must be supplied.")
+ doc = {
+ 'doctype': 'Report',
+ 'report_name': name,
+ 'is_standard': 'No',
+ 'module': 'Accounts'
+ }
+ doc.update(custom_report_dict)
+ doc = frappe.get_doc(doc)
+ doc.insert()
+ return True
+
+@frappe.whitelist()
+def save_custom_report(data):
+ return None
From a5d47f70b8864c67bddbb20e913116a01a901dfb Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Fri, 5 Mar 2021 06:46:38 +0000
Subject: [PATCH 111/149] Fleshed out report setup functionality
---
.../accounts/report/tax_detail/tax_detail.js | 320 ++++++++++++++----
1 file changed, 255 insertions(+), 65 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.js b/erpnext/accounts/report/tax_detail/tax_detail.js
index 1ac11409e3..0b0026028f 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.js
+++ b/erpnext/accounts/report/tax_detail/tax_detail.js
@@ -4,47 +4,79 @@
/* eslint-disable */
frappe.query_reports["Tax Detail"] = {
- "filters": [
+ filters: [
{
- "fieldname":"company",
- "label": __("Company"),
- "fieldtype": "Link",
- "options": "Company",
- "default": frappe.defaults.get_user_default("company"),
- "reqd": 1
+ fieldname: "company",
+ label: __("Company"),
+ fieldtype: "Link",
+ options: "Company",
+ default: frappe.defaults.get_user_default("company"),
+ reqd: 1
},
{
- "fieldname":"from_date",
- "label": __("From Date"),
- "fieldtype": "Date",
- "default": frappe.datetime.month_start(frappe.datetime.get_today()),
- "reqd": 1,
- "width": "60px"
+ fieldname: "from_date",
+ label: __("From Date"),
+ fieldtype: "Date",
+ default: frappe.datetime.month_start(frappe.datetime.get_today()),
+ reqd: 1,
+ width: "60px"
},
{
- "fieldname":"to_date",
- "label": __("To Date"),
- "fieldtype": "Date",
- "default": frappe.datetime.month_end(frappe.datetime.get_today()),
- "reqd": 1,
- "width": "60px"
+ fieldname: "to_date",
+ label: __("To Date"),
+ fieldtype: "Date",
+ default: frappe.datetime.month_end(frappe.datetime.get_today()),
+ reqd: 1,
+ width: "60px"
},
],
- onload: function(report) {
- report.page.add_inner_button(__("New Report"), () => new_report(), __("Custom Report"));
- report.page.add_inner_button(__("Load Report"), () => load_report(), __("Custom Report"));
- load_page_report();
+ onload: function onload(report) {
+ // Remove Add Column and Save from menu
+ report.page.add_inner_button(__("New Report"), () => new_report, __("Custom Report"));
+ report.page.add_inner_button(__("Load Report"), () => load_report, __("Custom Report"));
+ },
+ after_datatable_render: (datatable) => {
+ if (frappe.query_report.report_name == 'Tax Detail') {
+ return;
+ }
+ if (this.taxreport) {
+ this.taxreport.load_report();
+ } else {
+ this.taxreport = new TaxReport();
+ }
}
};
class TaxReport {
+ // construct after datatable is loaded
constructor() {
- this.report = frappe.query_reports["Tax Detail"]
- this.qr = frappe.query_report
- this.page = frappe.query_report.page
- this.create_controls()
+ this.report = frappe.query_reports["Tax Detail"];
+ this.qr = frappe.query_report;
+ this.page = frappe.query_report.page;
+ this.create_controls();
+ this.sections = {};
+ this.mode = 'run';
+ this.load_report();
+ }
+ load_report() {
+ // TODO
+ this.setup_menu();
+ // this.qr.refresh_report()
+ }
+ setup_menu() {
+ this.qr.menu_items.forEach((item, idx) => {
+ if (item['label'] == __('Save')) {
+ delete this.qr.menu_items[idx];
+ }
+ })
+ this.qr.menu_items.push({
+ label: __('Save'),
+ action: this.save_report
+ })
+ this.qr.set_menu_items();
}
save_report() {
+ // TODO
frappe.call({
method:'erpnext.accounts.report.tax_detail.tax_detail.new_custom_report',
args: {'name': values.report_name},
@@ -53,53 +85,218 @@ class TaxReport {
frappe.set_route("query-report", values.report_name);
});
}
- create_controls() {
- this.section_name = this.page.add_field({
- label: 'Section',
- fieldtype: 'Select',
- fieldname: 'section_name',
- change() {
- this.taxreport.set_section()
+ set_value_options() {
+ let curcols = [];
+ let options = [];
+ this.qr.columns.forEach((col, index) => {
+ if (col['fieldtype'] == "Currency") {
+ curcols.push(index);
+ options.push(col['label']);
}
});
- this.new_section = this.page.add_field({
- label: 'New Section',
- fieldtype: 'Button',
- fieldname: 'new_section'
+ this.currency_cols = curcols;
+ this.controls['value_field'].$wrapper.find("select").empty().add_options(options);
+ this.controls['value_field'].set_input(options[0]);
+ }
+ add_value_field_to_filters(filters) {
+ const curlabel = this.controls['value_field'].value;
+ this.currency_cols.forEach(index => {
+ if (this.qr.columns[index]['label'] == curlabel) {
+ filters['fieldname'] = this.qr.columns[index]['fieldname'];
+ }
});
- this.delete_section = this.page.add_field({
- label: 'Delete Section',
- fieldtype: 'Button',
- fieldname: 'delete_section'
+ return filters;
+ }
+ new_section(label) {
+ const dialog = new frappe.ui.Dialog({
+ title: label,
+ fields: [{
+ fieldname: 'data',
+ label: label,
+ fieldtype: 'Data'
+ }],
+ primary_action_label: label,
+ primary_action: (values) => {
+ dialog.hide();
+ this.set_section(values.data);
+ }
});
- this.page.add_field({
- label: 'Filter',
+ dialog.show();
+ }
+ set_section(name) {
+ this.mode = 'edit';
+ if (name && !this.sections[name]) {
+ this.sections[name] = {};
+ this.controls['section_name'].$wrapper.find("select").empty().add_options(Object.keys(this.sections));
+ }
+ if (name) {
+ this.controls['section_name'].set_input(name);
+ }
+ this.reload();
+ }
+ reload() {
+ if (this.mode == 'edit') {
+ const section_name = this.controls['section_name'].value;
+ let filters = {};
+ if (section_name) {
+ let fidx = this.controls['filter_index'].value;
+ let section = this.sections[section_name];
+ let fidxs = Object.keys(section);
+ fidxs.unshift('');
+ this.controls['filter_index'].$wrapper.find("select").empty().add_options(fidxs);
+ this.controls['filter_index'].set_input(fidx);
+ if (fidx != '') {
+ filters = section[fidx];
+ }
+ } else {
+ this.controls['filter_index'].$wrapper.find("select").empty();
+ }
+ // Set filters
+ // reload datatable
+ } else {
+ this.controls['filter_index'].$wrapper.find("select").empty();
+ // Query the result from the server & render
+ }
+ }
+ get_select(label, list, type) {
+ const dialog = new frappe.ui.Dialog({
+ title: label,
+ fields: [{
+ fieldname: 'select',
+ label: label,
+ fieldtype: 'Select',
+ options: list
+ }],
+ primary_action_label: label,
+ primary_action: (values) => {
+ dialog.hide();
+ this.exec_select(values.select, type);
+ }
+ });
+ dialog.show();
+ }
+ delete(name, type) {
+ if (type === 'section') {
+ delete this.sections[name];
+ this.controls['section_name'].$wrapper.find("select").empty().add_options(Object.keys(this.sections));
+ this.controls['section_name'].set_input(Object.keys(this.sections)[0] || '');
+ this.controls['filter_index'].set_input('');
+ }
+ if (type === 'filter') {
+ let cur_section = this.controls['section_name'].value;
+ delete this.sections[cur_section][name];
+ this.controls['filter_index'].set_input('');
+ }
+ this.reload();
+ }
+ create_controls() {
+ if (this.controls) {
+ return;
+ }
+ let controls = {};
+ // SELECT in data.js
+ controls['section_name'] = this.page.add_field({
+ label: __('Section'),
fieldtype: 'Select',
- fieldname: 'filter_index'
+ fieldname: 'section_name',
+ change: (e) => {
+ this.set_section();
+ }
});
- this.page.add_field({
- label: 'Add Filter',
+ // BUTTON in button.js
+ controls['new_section'] = this.page.add_field({
+ label: __('New Section'),
fieldtype: 'Button',
- fieldname: 'add_filter'
+ fieldname: 'new_section',
+ click: () => {
+ this.new_section(__('New Section'));
+ }
});
- this.page.add_field({
- label: 'Delete Filter',
+ controls['delete_section'] = this.page.add_field({
+ label: __('Delete Section'),
fieldtype: 'Button',
- fieldname: 'delete_filter'
+ fieldname: 'delete_section',
+ click: () => {
+ let cur_section = this.controls['section_name'].value;
+ if (cur_section) {
+ frappe.confirm(__('Are you sure you want to delete section ') + cur_section + '?',
+ () => {this.delete(cur_section, 'section')});
+ }
+ }
});
- this.page.add_field({
- label: 'Value Column',
+ controls['filter_index'] = this.page.add_field({
+ label: __('Filter'),
+ fieldtype: 'Select',
+ fieldname: 'filter_index',
+ change: (e) => {
+ // TODO
+ }
+ });
+ controls['add_filter'] = this.page.add_field({
+ label: __('Add Filter'),
+ fieldtype: 'Button',
+ fieldname: 'add_filter',
+ click: () => {
+ let section_name = this.controls['section_name'].value;
+ if (section_name) {
+ let prefix = 'Filter';
+ let filters = this.qr.datatable.columnmanager.getAppliedFilters();
+ filters = this.add_value_field_to_filters(filters);
+ const fidxs = Object.keys(this.sections[section_name]);
+ let new_idx = prefix + '0';
+ if (fidxs.length > 0) {
+ const fiidxs = fidxs.map((key) => parseInt(key.replace(prefix, '')));
+ new_idx = prefix + (Math.max(...fiidxs) + 1).toString();
+ }
+ this.sections[section_name][new_idx] = filters;
+ this.controls['filter_index'].set_input(new_idx);
+ this.reload();
+ } else {
+ frappe.throw(__('Please add or select the Section first'));
+ }
+ }
+ });
+ controls['delete_filter'] = this.page.add_field({
+ label: __('Delete Filter'),
+ fieldtype: 'Button',
+ fieldname: 'delete_filter',
+ click: () => {
+ let cur_filter = this.controls['filter_index'].value;
+ if (cur_filter) {
+ frappe.confirm(__('Are you sure you want to delete filter ') + cur_filter + '?',
+ () => {this.delete(cur_filter, 'filter')});
+ }
+ }
+ });
+ controls['value_field'] = this.page.add_field({
+ label: __('Value Column'),
fieldtype: 'Select',
fieldname: 'value_field',
+ change: (e) => {
+ // TODO
+ }
});
- this.page.add_field({
- label: 'Save',
+ controls['save'] = this.page.add_field({
+ label: __('Save & Run'),
fieldtype: 'Button',
- fieldname: 'save'
+ fieldname: 'save',
+ click: () => {
+ // TODO: Save to db
+ this.mode = 'run';
+ this.reload();
+ }
});
+ this.controls = controls;
+ this.set_value_options();
+ this.show_help();
+ }
+ show_help() {
+ const help = __('You can add multiple sections to your custom report using the New Section button above. To specify what data goes in each section, specify column filters below, then save with Add Filter. Each section can have multiple filters added. You can specify which Currency column will be summed for each filter in the final report with the Value Column select box.');
+ this.qr.show_status(help);
}
}
+
function get_reports(cb) {
frappe.call({
method: 'erpnext.accounts.report.tax_detail.tax_detail.get_custom_reports',
@@ -115,7 +312,7 @@ function new_report() {
fields: [
{
fieldname: 'report_name',
- label: 'Report Name',
+ label: __('Report Name'),
fieldtype: 'Data',
default: 'VAT Return'
}
@@ -135,13 +332,6 @@ function new_report() {
dialog.show();
}
-function load_page_report() {
- if (frappe.query_report.report_name === 'Tax Detail') {
- return;
- }
- this.taxreport = new TaxReport();
-}
-
function load_report() {
get_reports(function load_report_cb(reports) {
const dialog = new frappe.ui.Dialog({
@@ -149,7 +339,7 @@ function load_report() {
fields: [
{
fieldname: 'report_name',
- label: 'Report Name',
+ label: __('Report Name'),
fieldtype: 'Select',
options: Object.keys(reports)
}
From ef8ab135c9ebafaf3f5d9a8a7c4698935ef2eef8 Mon Sep 17 00:00:00 2001
From: Richard Case
Date: Sun, 14 Mar 2021 06:05:02 +0000
Subject: [PATCH 112/149] develop: progress tax detail report
---
.../accounts/report/tax_detail/tax_detail.js | 290 ++++++++++++------
.../accounts/report/tax_detail/tax_detail.py | 54 ++--
2 files changed, 224 insertions(+), 120 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.js b/erpnext/accounts/report/tax_detail/tax_detail.js
index 0b0026028f..894db9e55c 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.js
+++ b/erpnext/accounts/report/tax_detail/tax_detail.js
@@ -29,11 +29,28 @@ frappe.query_reports["Tax Detail"] = {
reqd: 1,
width: "60px"
},
+ {
+ fieldname: "report_name",
+ label: __("Report Name"),
+ fieldtype: "Read Only",
+ default: frappe.query_report.report_name,
+ hidden: 1,
+ reqd: 1
+ },
+ {
+ fieldname: "mode",
+ label: __("Mode"),
+ fieldtype: "Read Only",
+ default: "run",
+ hidden: 1,
+ reqd: 1
+ }
],
onload: function onload(report) {
// Remove Add Column and Save from menu
- report.page.add_inner_button(__("New Report"), () => new_report, __("Custom Report"));
- report.page.add_inner_button(__("Load Report"), () => load_report, __("Custom Report"));
+ report.page.add_inner_button(__("New Report"), () => new_report(), __("Custom Report"));
+ report.page.add_inner_button(__("Load Report"), () => load_report(), __("Custom Report"));
+ hide_filters();
},
after_datatable_render: (datatable) => {
if (frappe.query_report.report_name == 'Tax Detail') {
@@ -47,65 +64,83 @@ frappe.query_reports["Tax Detail"] = {
}
};
+function hide_filters() {
+ frappe.query_report.page.page_form[0].querySelectorAll('.form-group.frappe-control').forEach(function setHidden(field) {
+ if (field.dataset.fieldtype == "Read Only") {
+ field.classList.add("hidden");
+ }
+ });
+}
+
class TaxReport {
// construct after datatable is loaded
constructor() {
- this.report = frappe.query_reports["Tax Detail"];
this.qr = frappe.query_report;
this.page = frappe.query_report.page;
this.create_controls();
- this.sections = {};
- this.mode = 'run';
this.load_report();
}
load_report() {
- // TODO
- this.setup_menu();
- // this.qr.refresh_report()
- }
- setup_menu() {
- this.qr.menu_items.forEach((item, idx) => {
- if (item['label'] == __('Save')) {
- delete this.qr.menu_items[idx];
- }
- })
- this.qr.menu_items.push({
- label: __('Save'),
- action: this.save_report
- })
- this.qr.set_menu_items();
- }
- save_report() {
- // TODO
+ if (this.loaded) {
+ return;
+ }
+ const report_name = this.qr.report_name;
+ this.report_name.value = report_name;
frappe.call({
- method:'erpnext.accounts.report.tax_detail.tax_detail.new_custom_report',
- args: {'name': values.report_name},
+ method: 'erpnext.accounts.report.tax_detail.tax_detail.get_custom_reports',
+ args: {name: report_name},
freeze: true
}).then((r) => {
- frappe.set_route("query-report", values.report_name);
+ const data = JSON.parse(r.message[report_name]['json']);
+ if (data && data['sections']) {
+ this.sections = data['sections'];
+ } else {
+ this.sections = {};
+ }
+ this.set_section();
+ })
+ this.loaded = 1;
+ }
+ save_report() {
+ frappe.call({
+ method:'erpnext.accounts.report.tax_detail.tax_detail.save_custom_report',
+ args: {
+ reference_report: 'Tax Detail',
+ report_name: this.qr.report_name,
+ columns: this.qr.get_visible_columns(),
+ sections: this.sections
+ },
+ freeze: true
+ }).then((r) => {
+ this.reload();
});
}
set_value_options() {
- let curcols = [];
- let options = [];
+ this.fieldname_lookup = {};
+ this.label_lookup = {};
this.qr.columns.forEach((col, index) => {
if (col['fieldtype'] == "Currency") {
- curcols.push(index);
- options.push(col['label']);
+ this.fieldname_lookup[col['label']] = col['fieldname'];
+ this.label_lookup[col['fieldname']] = col['label'];
}
});
- this.currency_cols = curcols;
+ const options = Object.keys(this.fieldname_lookup);
this.controls['value_field'].$wrapper.find("select").empty().add_options(options);
this.controls['value_field'].set_input(options[0]);
}
- add_value_field_to_filters(filters) {
+ set_value_label_from_filter() {
+ const section_name = this.controls['section_name'].value;
+ const fidx = this.controls['filter_index'].value;
+ if (section_name && fidx) {
+ const fieldname = this.sections[section_name][fidx]['fieldname'];
+ this.controls['value_field'].set_input(this.label_lookup[fieldname]);
+ } else {
+ this.controls['value_field'].set_input(Object.keys(this.fieldname_lookup)[0]);
+ }
+ }
+ get_value_fieldname() {
const curlabel = this.controls['value_field'].value;
- this.currency_cols.forEach(index => {
- if (this.qr.columns[index]['label'] == curlabel) {
- filters['fieldname'] = this.qr.columns[index]['fieldname'];
- }
- });
- return filters;
+ return this.fieldname_lookup[curlabel];
}
new_section(label) {
const dialog = new frappe.ui.Dialog({
@@ -123,57 +158,87 @@ class TaxReport {
});
dialog.show();
}
- set_section(name) {
- this.mode = 'edit';
- if (name && !this.sections[name]) {
- this.sections[name] = {};
- this.controls['section_name'].$wrapper.find("select").empty().add_options(Object.keys(this.sections));
- }
- if (name) {
- this.controls['section_name'].set_input(name);
- }
- this.reload();
- }
- reload() {
- if (this.mode == 'edit') {
- const section_name = this.controls['section_name'].value;
- let filters = {};
- if (section_name) {
- let fidx = this.controls['filter_index'].value;
- let section = this.sections[section_name];
- let fidxs = Object.keys(section);
- fidxs.unshift('');
- this.controls['filter_index'].$wrapper.find("select").empty().add_options(fidxs);
- this.controls['filter_index'].set_input(fidx);
- if (fidx != '') {
- filters = section[fidx];
- }
- } else {
- this.controls['filter_index'].$wrapper.find("select").empty();
+ get_filter_controls() {
+ this.qr.filters.forEach(filter => {
+ if (filter['fieldname'] == 'mode') {
+ this.mode = filter;
}
- // Set filters
- // reload datatable
- } else {
- this.controls['filter_index'].$wrapper.find("select").empty();
- // Query the result from the server & render
- }
- }
- get_select(label, list, type) {
- const dialog = new frappe.ui.Dialog({
- title: label,
- fields: [{
- fieldname: 'select',
- label: label,
- fieldtype: 'Select',
- options: list
- }],
- primary_action_label: label,
- primary_action: (values) => {
- dialog.hide();
- this.exec_select(values.select, type);
+ if (filter['fieldname'] == 'report_name') {
+ this.report_name = filter;
}
});
- dialog.show();
+ }
+ set_mode(mode) {
+ this.mode.value = mode;
+ }
+ edit_mode() {
+ return this.mode.value == 'edit';
+ }
+ set_section(name) {
+ if (name && !this.sections[name]) {
+ this.sections[name] = {};
+ }
+ let options = Object.keys(this.sections);
+ options.unshift('');
+ this.controls['section_name'].$wrapper.find("select").empty().add_options(options);
+ if (name) {
+ this.controls['section_name'].set_input(name);
+ } else {
+ this.controls['section_name'].set_input('');
+ }
+ if (this.controls['section_name'].value) {
+ this.set_mode('edit');
+ } else {
+ this.set_mode('run');
+ }
+ this.controls['filter_index'].set_input('');
+ this.reload();
+ }
+ reload_filter() {
+ const section_name = this.controls['section_name'].value;
+ if (section_name) {
+ let fidx = this.controls['filter_index'].value;
+ let section = this.sections[section_name];
+ let fidxs = Object.keys(section);
+ fidxs.unshift('');
+ this.controls['filter_index'].$wrapper.find("select").empty().add_options(fidxs);
+ this.controls['filter_index'].set_input(fidx);
+ } else {
+ this.controls['filter_index'].$wrapper.find("select").empty();
+ this.controls['filter_index'].set_input('');
+ }
+ this.set_filters();
+ }
+ set_filters() {
+ let filters = {};
+ const section_name = this.controls['section_name'].value;
+ const fidx = this.controls['filter_index'].value;
+ if (section_name && fidx) {
+ filters = this.sections[section_name][fidx]['filters'];
+ }
+ this.setAppliedFilters(filters);
+ this.qr.datatable.columnmanager.applyFilter(filters);
+ this.set_value_label_from_filter();
+ }
+ setAppliedFilters(filters) {
+ Array.from(this.qr.datatable.header.querySelectorAll('.dt-filter')).map(function setFilters(input) {
+ let idx = input.dataset.colIndex;
+ if (filters[idx]) {
+ input.value = filters[idx];
+ } else {
+ input.value = null;
+ }
+ });
+ }
+ reload() {
+ // Reloads the data. When the datatable is reloaded, load_report()
+ // will be run by the after_datatable_render event.
+ this.qr.refresh();
+ if (this.edit_mode()) {
+ this.reload_filter();
+ } else {
+ this.controls['filter_index'].$wrapper.find("select").empty();
+ }
}
delete(name, type) {
if (type === 'section') {
@@ -200,7 +265,7 @@ class TaxReport {
fieldtype: 'Select',
fieldname: 'section_name',
change: (e) => {
- this.set_section();
+ this.set_section(this.controls['section_name'].get_input_value());
}
});
// BUTTON in button.js
@@ -229,7 +294,8 @@ class TaxReport {
fieldtype: 'Select',
fieldname: 'filter_index',
change: (e) => {
- // TODO
+ this.controls['filter_index'].set_input(this.controls['filter_index'].get_input_value());
+ this.set_filters();
}
});
controls['add_filter'] = this.page.add_field({
@@ -240,17 +306,19 @@ class TaxReport {
let section_name = this.controls['section_name'].value;
if (section_name) {
let prefix = 'Filter';
- let filters = this.qr.datatable.columnmanager.getAppliedFilters();
- filters = this.add_value_field_to_filters(filters);
+ let data = {
+ filters: this.qr.datatable.columnmanager.getAppliedFilters(),
+ fieldname: this.get_value_fieldname()
+ }
const fidxs = Object.keys(this.sections[section_name]);
let new_idx = prefix + '0';
if (fidxs.length > 0) {
const fiidxs = fidxs.map((key) => parseInt(key.replace(prefix, '')));
new_idx = prefix + (Math.max(...fiidxs) + 1).toString();
}
- this.sections[section_name][new_idx] = filters;
+ this.sections[section_name][new_idx] = data;
this.controls['filter_index'].set_input(new_idx);
- this.reload();
+ this.reload_filter();
} else {
frappe.throw(__('Please add or select the Section first'));
}
@@ -273,7 +341,7 @@ class TaxReport {
fieldtype: 'Select',
fieldname: 'value_field',
change: (e) => {
- // TODO
+ this.controls['value_field'].set_input(this.controls['value_field'].get_input_value());
}
});
controls['save'] = this.page.add_field({
@@ -281,17 +349,22 @@ class TaxReport {
fieldtype: 'Button',
fieldname: 'save',
click: () => {
- // TODO: Save to db
- this.mode = 'run';
- this.reload();
+ this.controls['section_name'].set_input('');
+ this.set_mode('run');
+ this.save_report();
}
});
this.controls = controls;
this.set_value_options();
+ this.get_filter_controls();
this.show_help();
}
show_help() {
- const help = __('You can add multiple sections to your custom report using the New Section button above. To specify what data goes in each section, specify column filters below, then save with Add Filter. Each section can have multiple filters added. You can specify which Currency column will be summed for each filter in the final report with the Value Column select box.');
+ const help = __(`You can add multiple sections to your custom report using the New Section button above.
+ To specify what data goes in each section, specify column filters below, then save with Add Filter.
+ Each section can have multiple filters added.
+ You can specify which Currency column will be summed for each filter in the final report with the Value Column select box.
+ Once you're done, hit Save & Run.`);
this.qr.show_status(help);
}
}
@@ -306,6 +379,20 @@ function get_reports(cb) {
})
}
+function override_menu() {
+ //TODO: Replace save button
+ this.qr.menu_items.forEach((item, idx) => {
+ if (item['label'] == __('Save')) {
+ delete this.qr.menu_items[idx];
+ }
+ })
+ this.qr.menu_items.push({
+ label: __('Save'),
+ action: this.save_report
+ })
+ this.qr.set_menu_items();
+}
+
function new_report() {
const dialog = new frappe.ui.Dialog({
title: __("New Report"),
@@ -320,8 +407,13 @@ function new_report() {
primary_action_label: __('Create'),
primary_action: function new_report_pa(values) {
frappe.call({
- method:'erpnext.accounts.report.tax_detail.tax_detail.new_custom_report',
- args: {'name': values.report_name},
+ method:'erpnext.accounts.report.tax_detail.tax_detail.save_custom_report',
+ args: {
+ reference_report: 'Tax Detail',
+ report_name: values.report_name,
+ columns: frappe.query_report.get_visible_columns(),
+ sections: {}
+ },
freeze: true
}).then((r) => {
frappe.set_route("query-report", values.report_name);
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py
index 46e7ae08e9..2ea782eb7a 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/tax_detail.py
@@ -3,7 +3,7 @@
# Contributed by Case Solved and sponsored by Nulight Studios
from __future__ import unicode_literals
-import frappe
+import frappe, json
from frappe import _
# field lists in multiple doctypes will be coalesced
@@ -16,15 +16,12 @@ required_sql_fields = {
# "Journal Entry Account": ["debit_in_account_currency", "credit_in_account_currency"]
}
-@frappe.whitelist()
-def get_required_fieldlist():
- """For overriding the fieldlist from the client"""
- return required_sql_fields
-def execute(filters=None, fieldlist=required_sql_fields):
+def execute(filters=None):
if not filters:
return [], []
+ fieldlist = required_sql_fields
fieldstr = get_fieldstr(fieldlist)
gl_entries = frappe.db.sql("""
@@ -136,9 +133,12 @@ custom_report_dict = {
}
@frappe.whitelist()
-def get_custom_reports():
+def get_custom_reports(name=None):
+ filters = custom_report_dict.copy()
+ if name:
+ filters['name'] = name
reports = frappe.get_list('Report',
- filters = custom_report_dict,
+ filters = filters,
fields = ['name', 'json'],
as_list=False
)
@@ -148,22 +148,34 @@ def get_custom_reports():
return reports_dict
@frappe.whitelist()
-def new_custom_report(name=None):
- if name == 'Tax Detail':
- frappe.throw("The parent report cannot be overwritten.")
- if not name:
- frappe.throw("The report name must be supplied.")
+def save_custom_report(reference_report, report_name, columns, sections):
+ import pymysql
+ if reference_report != 'Tax Detail':
+ frappe.throw(_("The wrong report is referenced."))
+ if report_name == 'Tax Detail':
+ frappe.throw(_("The parent report cannot be overwritten."))
+
+ data = {
+ 'columns': json.loads(columns),
+ 'sections': json.loads(sections)
+ }
+
doc = {
'doctype': 'Report',
- 'report_name': name,
+ 'report_name': report_name,
'is_standard': 'No',
- 'module': 'Accounts'
+ 'module': 'Accounts',
+ 'json': json.dumps(data, separators=(',', ':'))
}
doc.update(custom_report_dict)
- doc = frappe.get_doc(doc)
- doc.insert()
- return True
-@frappe.whitelist()
-def save_custom_report(data):
- return None
+ try:
+ newdoc = frappe.get_doc(doc)
+ newdoc.insert()
+ frappe.msgprint(_("Report created successfully"))
+ except (frappe.exceptions.DuplicateEntryError, pymysql.err.IntegrityError):
+ dbdoc = frappe.get_doc('Report', report_name)
+ dbdoc.update(doc)
+ dbdoc.save()
+ frappe.msgprint(_("Report updated successfully"))
+ return report_name
From dba4b3cd13e12e3db1233cbf707744773fff62e1 Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Fri, 19 Mar 2021 23:05:19 +0000
Subject: [PATCH 113/149] feat: add run mode, add tests, various fixes
---
.../accounts/report/tax_detail/tax_detail.js | 22 +++--
.../accounts/report/tax_detail/tax_detail.py | 95 ++++++++++++++++---
.../report/tax_detail/test_tax_detail.py | 67 +++++++++++++
3 files changed, 166 insertions(+), 18 deletions(-)
create mode 100644 erpnext/accounts/report/tax_detail/test_tax_detail.py
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.js b/erpnext/accounts/report/tax_detail/tax_detail.js
index 894db9e55c..8cdce54852 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.js
+++ b/erpnext/accounts/report/tax_detail/tax_detail.js
@@ -92,11 +92,8 @@ class TaxReport {
freeze: true
}).then((r) => {
const data = JSON.parse(r.message[report_name]['json']);
- if (data && data['sections']) {
- this.sections = data['sections'];
- } else {
- this.sections = {};
- }
+ this.sections = data.sections || {};
+ this.controls['show_detail'].set_input(data.show_detail);
this.set_section();
})
this.loaded = 1;
@@ -107,8 +104,11 @@ class TaxReport {
args: {
reference_report: 'Tax Detail',
report_name: this.qr.report_name,
- columns: this.qr.get_visible_columns(),
- sections: this.sections
+ data: {
+ columns: this.qr.get_visible_columns(),
+ sections: this.sections,
+ show_detail: this.controls['show_detail'].get_input_value()
+ }
},
freeze: true
}).then((r) => {
@@ -233,7 +233,9 @@ class TaxReport {
reload() {
// Reloads the data. When the datatable is reloaded, load_report()
// will be run by the after_datatable_render event.
+ // TODO: why does this trigger multiple reloads?
this.qr.refresh();
+ this.show_help();
if (this.edit_mode()) {
this.reload_filter();
} else {
@@ -354,6 +356,12 @@ class TaxReport {
this.save_report();
}
});
+ controls['show_detail'] = this.page.add_field({
+ label: __('Show Detail'),
+ fieldtype: 'Check',
+ fieldname: 'show_detail',
+ default: 1
+ });
this.controls = controls;
this.set_value_options();
this.get_filter_controls();
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py
index 2ea782eb7a..6bed89841c 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/tax_detail.py
@@ -54,10 +54,89 @@ def execute(filters=None):
order by ge.posting_date, ge.voucher_no
""".format(fieldstr=fieldstr), filters, as_dict=1)
- gl_entries = modify_report_data(gl_entries)
+ report_data = modify_report_data(gl_entries)
+ summary = None
+ if filters['mode'] == 'run' and filters['report_name'] != 'Tax Detail':
+ report_data, summary = run_report(filters['report_name'], report_data)
- return get_columns(fieldlist), gl_entries
+ # return columns, data, message, chart, report_summary
+ return get_columns(fieldlist), report_data, None, None, summary
+def run_report(report_name, data):
+ "Applies the sections and filters saved in the custom report"
+ report_config = json.loads(frappe.get_doc('Report', report_name).json)
+ # Columns indexed from 1 wrt colno
+ columns = report_config.get('columns')
+ sections = report_config.get('sections', {})
+ show_detail = report_config.get('show_detail', 1)
+ new_data = []
+ summary = []
+ for section_name, section in sections.items():
+ section_total = 0.0
+ for filt_name, filt in section.items():
+ value_field = filt['fieldname']
+ rmidxs = []
+ for colno, filter_string in filt['filters'].items():
+ filter_field = columns[int(colno) - 1]['fieldname']
+ for i, row in enumerate(data):
+ if not filter_match(row[filter_field], filter_string):
+ rmidxs += [i]
+ rows = [row for i, row in enumerate(data) if i not in rmidxs]
+ section_total += subtotal(rows, value_field)
+ if show_detail: new_data += rows
+ new_data += [ {columns[1]['fieldname']: section_name, columns[2]['fieldname']: section_total} ]
+ summary += [ {'label': section_name, 'datatype': 'Currency', 'value': section_total} ]
+ if show_detail: new_data += [ {} ]
+ return new_data if new_data else data, summary
+
+def filter_match(value, string):
+ "Approximation to datatable filters"
+ import datetime
+ if string == '': return True
+ if value is None: value = -999999999999999
+ elif isinstance(value, datetime.date): return True
+
+ if isinstance(value, str):
+ value = value.lower()
+ string = string.lower()
+ if string[0] == '<': return True if string[1:].strip() else False
+ elif string[0] == '>': return False if string[1:].strip() else True
+ elif string[0] == '=': return string[1:] in value if string[1:] else False
+ elif string[0:2] == '!=': return string[2:] not in value
+ elif len(string.split(':')) == 2:
+ pre, post = string.split(':')
+ return (True if not pre.strip() and post.strip() in value else False)
+ else:
+ return string in value
+ else:
+ if string[0] in ['<', '>', '=']:
+ operator = string[0]
+ if operator == '=': operator = '=='
+ string = string[1:].strip()
+ elif string[0:2] == '!=':
+ operator = '!='
+ string = string[2:].strip()
+ elif len(string.split(':')) == 2:
+ pre, post = string.split(':')
+ try:
+ return (True if float(pre) <= value and float(post) >= value else False)
+ except ValueError:
+ return (False if pre.strip() else True)
+ else:
+ return string in str(value)
+
+ try:
+ num = float(string) if string.strip() else 0
+ return eval(f'{value} {operator} {num}')
+ except ValueError:
+ if operator == '<': return True
+ return False
+
+def subtotal(data, field):
+ subtotal = 0.0
+ for row in data:
+ subtotal += row[field]
+ return subtotal
abbrev = lambda dt: ''.join(l[0].lower() for l in dt.split(' ')) + '.'
doclist = lambda dt, dfs: [abbrev(dt) + f for f in dfs]
@@ -148,24 +227,18 @@ def get_custom_reports(name=None):
return reports_dict
@frappe.whitelist()
-def save_custom_report(reference_report, report_name, columns, sections):
- import pymysql
+def save_custom_report(reference_report, report_name, data):
if reference_report != 'Tax Detail':
frappe.throw(_("The wrong report is referenced."))
if report_name == 'Tax Detail':
frappe.throw(_("The parent report cannot be overwritten."))
- data = {
- 'columns': json.loads(columns),
- 'sections': json.loads(sections)
- }
-
doc = {
'doctype': 'Report',
'report_name': report_name,
'is_standard': 'No',
'module': 'Accounts',
- 'json': json.dumps(data, separators=(',', ':'))
+ 'json': data
}
doc.update(custom_report_dict)
@@ -173,7 +246,7 @@ def save_custom_report(reference_report, report_name, columns, sections):
newdoc = frappe.get_doc(doc)
newdoc.insert()
frappe.msgprint(_("Report created successfully"))
- except (frappe.exceptions.DuplicateEntryError, pymysql.err.IntegrityError):
+ except frappe.exceptions.DuplicateEntryError:
dbdoc = frappe.get_doc('Report', report_name)
dbdoc.update(doc)
dbdoc.save()
diff --git a/erpnext/accounts/report/tax_detail/test_tax_detail.py b/erpnext/accounts/report/tax_detail/test_tax_detail.py
new file mode 100644
index 0000000000..dfd8d9e121
--- /dev/null
+++ b/erpnext/accounts/report/tax_detail/test_tax_detail.py
@@ -0,0 +1,67 @@
+from __future__ import unicode_literals
+
+import frappe, unittest, datetime
+from frappe.utils import getdate
+from .tax_detail import execute, filter_match
+
+class TestTaxDetail(unittest.TestCase):
+ def setup(self):
+ pass
+
+ def test_filter_match(self):
+ # None - treated as -inf number except range
+ self.assertTrue(filter_match(None, '!='))
+ self.assertTrue(filter_match(None, '<'))
+ self.assertTrue(filter_match(None, '3.4'))
+ self.assertFalse(filter_match(None, ' <'))
+ self.assertFalse(filter_match(None, 'ew'))
+ self.assertFalse(filter_match(None, ' '))
+ self.assertFalse(filter_match(None, ' f :'))
+
+ # Numbers
+ self.assertTrue(filter_match(3.4, '3.4'))
+ self.assertTrue(filter_match(3.4, '.4'))
+ self.assertTrue(filter_match(3.4, '3'))
+ self.assertTrue(filter_match(-3.4, '< -3'))
+ self.assertTrue(filter_match(-3.4, '> -4'))
+ self.assertTrue(filter_match(3.4, '= 3.4 '))
+ self.assertTrue(filter_match(3.4, '!=4.5'))
+ self.assertTrue(filter_match(3.4, ' 3 : 4 '))
+ self.assertTrue(filter_match(0.0, ' : '))
+ self.assertFalse(filter_match(3.4, '=4.5'))
+ self.assertFalse(filter_match(3.4, ' = 3.4 '))
+ self.assertFalse(filter_match(3.4, '!=3.4'))
+ self.assertFalse(filter_match(3.4, '>6'))
+ self.assertFalse(filter_match(3.4, '<-4.5'))
+ self.assertFalse(filter_match(3.4, '4.5'))
+ self.assertFalse(filter_match(3.4, '5:9'))
+
+ # Strings
+ self.assertTrue(filter_match('ACC-SINV-2021-00001', 'SINV'))
+ self.assertTrue(filter_match('ACC-SINV-2021-00001', 'sinv'))
+ self.assertTrue(filter_match('ACC-SINV-2021-00001', '-2021'))
+ self.assertTrue(filter_match(' ACC-SINV-2021-00001', ' acc'))
+ self.assertTrue(filter_match('ACC-SINV-2021-00001', '=2021'))
+ self.assertTrue(filter_match('ACC-SINV-2021-00001', '!=zz'))
+ self.assertTrue(filter_match('ACC-SINV-2021-00001', '< zzz '))
+ self.assertTrue(filter_match('ACC-SINV-2021-00001', ' : sinv '))
+ self.assertFalse(filter_match('ACC-SINV-2021-00001', ' sinv :'))
+ self.assertFalse(filter_match('ACC-SINV-2021-00001', ' acc'))
+ self.assertFalse(filter_match('ACC-SINV-2021-00001', '= 2021 '))
+ self.assertFalse(filter_match('ACC-SINV-2021-00001', '!=sinv'))
+ self.assertFalse(filter_match('ACC-SINV-2021-00001', ' >'))
+ self.assertFalse(filter_match('ACC-SINV-2021-00001', '>aa'))
+ self.assertFalse(filter_match('ACC-SINV-2021-00001', ' <'))
+ self.assertFalse(filter_match('ACC-SINV-2021-00001', '< '))
+ self.assertFalse(filter_match('ACC-SINV-2021-00001', ' ='))
+ self.assertFalse(filter_match('ACC-SINV-2021-00001', '='))
+
+ # Date - always match
+ self.assertTrue(filter_match(datetime.date(2021, 3, 19), ' kdsjkldfs '))
From 8e413651c2b4cfc9c7754a482f353996393cd507 Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Wed, 24 Mar 2021 02:56:30 +0000
Subject: [PATCH 114/149] fix: major refactor to monkey-patch into the
QueryReport class
---
.../accounts/report/tax_detail/tax_detail.js | 300 +++++++++---------
1 file changed, 153 insertions(+), 147 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.js b/erpnext/accounts/report/tax_detail/tax_detail.js
index 8cdce54852..6049000404 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.js
+++ b/erpnext/accounts/report/tax_detail/tax_detail.js
@@ -3,6 +3,8 @@
// Contributed by Case Solved and sponsored by Nulight Studios
/* eslint-disable */
+frappe.provide('frappe.query_reports');
+
frappe.query_reports["Tax Detail"] = {
filters: [
{
@@ -50,83 +52,124 @@ frappe.query_reports["Tax Detail"] = {
// Remove Add Column and Save from menu
report.page.add_inner_button(__("New Report"), () => new_report(), __("Custom Report"));
report.page.add_inner_button(__("Load Report"), () => load_report(), __("Custom Report"));
- hide_filters();
- },
- after_datatable_render: (datatable) => {
- if (frappe.query_report.report_name == 'Tax Detail') {
- return;
- }
- if (this.taxreport) {
- this.taxreport.load_report();
- } else {
- this.taxreport = new TaxReport();
- }
+ hide_filters(report);
}
};
-function hide_filters() {
- frappe.query_report.page.page_form[0].querySelectorAll('.form-group.frappe-control').forEach(function setHidden(field) {
+function hide_filters(report) {
+ report.page.page_form[0].querySelectorAll('.form-group.frappe-control').forEach(function setHidden(field) {
if (field.dataset.fieldtype == "Read Only") {
field.classList.add("hidden");
}
});
}
-class TaxReport {
- // construct after datatable is loaded
+erpnext.TaxDetail = class TaxDetail {
constructor() {
- this.qr = frappe.query_report;
- this.page = frappe.query_report.page;
- this.create_controls();
+ this.patch();
this.load_report();
}
- load_report() {
- if (this.loaded) {
- return;
+ // Monkey patch the QueryReport class
+ patch() {
+ this.qr = frappe.query_report;
+ this.super = {
+ refresh_report: this.qr.refresh_report,
+ show_footer_message: this.qr.show_footer_message
}
- const report_name = this.qr.report_name;
- this.report_name.value = report_name;
- frappe.call({
- method: 'erpnext.accounts.report.tax_detail.tax_detail.get_custom_reports',
- args: {name: report_name},
- freeze: true
- }).then((r) => {
- const data = JSON.parse(r.message[report_name]['json']);
- this.sections = data.sections || {};
- this.controls['show_detail'].set_input(data.show_detail);
- this.set_section();
- })
- this.loaded = 1;
+ this.qr.refresh_report = () => this.refresh_report();
+ this.qr.show_footer_message = () => this.show_footer_message();
+ }
+ show_footer_message() {
+ // The last thing to run after datatable_render in refresh()
+ console.log('show_footer_message');
+ this.super.show_footer_message.apply(this.qr);
+ if (this.qr.report_name !== 'Tax Detail') {
+ this.set_value_options();
+ this.show_help();
+ if (this.loading) {
+ this.set_section('');
+ }
+ this.reload_filter();
+ }
+ this.loading = false;
+ }
+ refresh_report() {
+ // Infrequent report build (onload), load filters & data
+ // super function runs a refresh() serially
+ // already run within frappe.run_serially
+ console.log('refresh_report');
+ this.loading = true;
+ this.super.refresh_report.apply(this.qr);
+ if (this.qr.report_name !== 'Tax Detail') {
+ frappe.call({
+ method: 'erpnext.accounts.report.tax_detail.tax_detail.get_custom_reports',
+ args: {name: this.qr.report_name}
+ }).then((r) => {
+ const data = JSON.parse(r.message[this.qr.report_name]['json']);
+ this.create_controls();
+ this.sections = data.sections || {};
+ this.controls['show_detail'].set_input(data.show_detail);
+ });
+ }
+ }
+ load_report() {
+ // One-off report build like titles, menu, etc
+ // Run when this object is created which happens in qr.load_report
+ console.log('load_report');
+ this.qr.menu_items = this.get_menu_items();
+ }
+ get_menu_items() {
+ // Replace save button
+ let new_items = [];
+ const label = __('Save');
+
+ for (let item of this.qr.menu_items) {
+ if (item.label === label) {
+ new_items.push({
+ label: label,
+ action: this.save_report,
+ standard: false
+ });
+ } else {
+ new_items.push(item);
+ }
+ }
+ return new_items;
}
save_report() {
- frappe.call({
- method:'erpnext.accounts.report.tax_detail.tax_detail.save_custom_report',
- args: {
- reference_report: 'Tax Detail',
- report_name: this.qr.report_name,
- data: {
- columns: this.qr.get_visible_columns(),
- sections: this.sections,
- show_detail: this.controls['show_detail'].get_input_value()
- }
- },
- freeze: true
- }).then((r) => {
- this.reload();
- });
+ if (this.qr.report_name !== 'Tax Detail') {
+ frappe.call({
+ method:'erpnext.accounts.report.tax_detail.tax_detail.save_custom_report',
+ args: {
+ reference_report: 'Tax Detail',
+ report_name: this.qr.report_name,
+ data: {
+ columns: this.qr.get_visible_columns(),
+ sections: this.sections,
+ show_detail: this.controls['show_detail'].get_input_value()
+ }
+ },
+ freeze: true
+ }).then((r) => {
+ this.set_section('');
+ });
+ }
}
set_value_options() {
- this.fieldname_lookup = {};
- this.label_lookup = {};
- this.qr.columns.forEach((col, index) => {
- if (col['fieldtype'] == "Currency") {
- this.fieldname_lookup[col['label']] = col['fieldname'];
- this.label_lookup[col['fieldname']] = col['label'];
- }
- });
- const options = Object.keys(this.fieldname_lookup);
- this.controls['value_field'].$wrapper.find("select").empty().add_options(options);
- this.controls['value_field'].set_input(options[0]);
+ // May be run with no columns or data
+ if (this.qr.columns) {
+ this.fieldname_lookup = {};
+ this.label_lookup = {};
+ this.qr.columns.forEach((col, index) => {
+ if (col['fieldtype'] == "Currency") {
+ this.fieldname_lookup[col['label']] = col['fieldname'];
+ this.label_lookup[col['fieldname']] = col['label'];
+ }
+ });
+ const options = Object.keys(this.fieldname_lookup);
+ this.controls['value_field'].$wrapper.find("select").empty().add_options(options);
+ this.controls['value_field'].set_input(options[0]);
+ }
}
set_value_label_from_filter() {
const section_name = this.controls['section_name'].value;
@@ -158,46 +201,38 @@ class TaxReport {
});
dialog.show();
}
- get_filter_controls() {
- this.qr.filters.forEach(filter => {
- if (filter['fieldname'] == 'mode') {
- this.mode = filter;
- }
- if (filter['fieldname'] == 'report_name') {
- this.report_name = filter;
- }
- });
- }
- set_mode(mode) {
- this.mode.value = mode;
- }
- edit_mode() {
- return this.mode.value == 'edit';
- }
set_section(name) {
+ // Sets the given section name and then reloads the data
if (name && !this.sections[name]) {
this.sections[name] = {};
}
let options = Object.keys(this.sections);
options.unshift('');
this.controls['section_name'].$wrapper.find("select").empty().add_options(options);
+ const org_mode = this.qr.get_filter_value('mode');
+ let refresh = false;
if (name) {
this.controls['section_name'].set_input(name);
+ this.qr.set_filter_value('mode', 'edit');
+ if (org_mode === 'run') {
+ refresh = true;
+ }
} else {
this.controls['section_name'].set_input('');
+ this.qr.set_filter_value('mode', 'run');
+ if (org_mode === 'edit') {
+ refresh = true;
+ }
}
- if (this.controls['section_name'].value) {
- this.set_mode('edit');
- } else {
- this.set_mode('run');
+ this.reload_filter();
+ if (refresh) {
+ this.qr.refresh();
}
- this.controls['filter_index'].set_input('');
- this.reload();
}
reload_filter() {
- const section_name = this.controls['section_name'].value;
+ const section_name = this.controls['section_name'].get_input_value();
if (section_name) {
- let fidx = this.controls['filter_index'].value;
+ let fidx = this.controls['filter_index'].get_input_value();
let section = this.sections[section_name];
let fidxs = Object.keys(section);
fidxs.unshift('');
@@ -207,17 +242,16 @@ class TaxReport {
this.controls['filter_index'].$wrapper.find("select").empty();
this.controls['filter_index'].set_input('');
}
- this.set_filters();
+ this.set_table_filters();
}
- set_filters() {
+ set_table_filters() {
let filters = {};
- const section_name = this.controls['section_name'].value;
- const fidx = this.controls['filter_index'].value;
+ const section_name = this.controls['section_name'].get_input_value();
+ const fidx = this.controls['filter_index'].get_input_value();
if (section_name && fidx) {
filters = this.sections[section_name][fidx]['filters'];
}
this.setAppliedFilters(filters);
- this.qr.datatable.columnmanager.applyFilter(filters);
this.set_value_label_from_filter();
}
setAppliedFilters(filters) {
@@ -229,32 +263,20 @@ class TaxReport {
input.value = null;
}
});
- }
- reload() {
- // Reloads the data. When the datatable is reloaded, load_report()
- // will be run by the after_datatable_render event.
- // TODO: why does this trigger multiple reloads?
- this.qr.refresh();
- this.show_help();
- if (this.edit_mode()) {
- this.reload_filter();
- } else {
- this.controls['filter_index'].$wrapper.find("select").empty();
- }
+ this.qr.datatable.columnmanager.applyFilter(filters);
}
delete(name, type) {
if (type === 'section') {
delete this.sections[name];
- this.controls['section_name'].$wrapper.find("select").empty().add_options(Object.keys(this.sections));
- this.controls['section_name'].set_input(Object.keys(this.sections)[0] || '');
- this.controls['filter_index'].set_input('');
+ const new_section = Object.keys(this.sections)[0] || '';
+ this.set_section(new_section);
}
if (type === 'filter') {
- let cur_section = this.controls['section_name'].value;
+ const cur_section = this.controls['section_name'].get_input_value();
delete this.sections[cur_section][name];
this.controls['filter_index'].set_input('');
+ this.reload_filter();
}
- this.reload();
}
create_controls() {
if (this.controls) {
@@ -262,7 +284,7 @@ class TaxReport {
}
let controls = {};
// SELECT in data.js
- controls['section_name'] = this.page.add_field({
+ controls['section_name'] = this.qr.page.add_field({
label: __('Section'),
fieldtype: 'Select',
fieldname: 'section_name',
@@ -271,7 +293,7 @@ class TaxReport {
}
});
// BUTTON in button.js
- controls['new_section'] = this.page.add_field({
+ controls['new_section'] = this.qr.page.add_field({
label: __('New Section'),
fieldtype: 'Button',
fieldname: 'new_section',
@@ -279,33 +301,33 @@ class TaxReport {
this.new_section(__('New Section'));
}
});
- controls['delete_section'] = this.page.add_field({
+ controls['delete_section'] = this.qr.page.add_field({
label: __('Delete Section'),
fieldtype: 'Button',
fieldname: 'delete_section',
click: () => {
- let cur_section = this.controls['section_name'].value;
+ let cur_section = this.controls['section_name'].get_input_value();
if (cur_section) {
frappe.confirm(__('Are you sure you want to delete section ') + cur_section + '?',
() => {this.delete(cur_section, 'section')});
}
}
});
- controls['filter_index'] = this.page.add_field({
+ controls['filter_index'] = this.qr.page.add_field({
label: __('Filter'),
fieldtype: 'Select',
fieldname: 'filter_index',
change: (e) => {
this.controls['filter_index'].set_input(this.controls['filter_index'].get_input_value());
- this.set_filters();
+ this.set_table_filters();
}
});
- controls['add_filter'] = this.page.add_field({
+ controls['add_filter'] = this.qr.page.add_field({
label: __('Add Filter'),
fieldtype: 'Button',
fieldname: 'add_filter',
click: () => {
- let section_name = this.controls['section_name'].value;
+ let section_name = this.controls['section_name'].get_input_value();
if (section_name) {
let prefix = 'Filter';
let data = {
@@ -326,19 +348,19 @@ class TaxReport {
}
}
});
- controls['delete_filter'] = this.page.add_field({
+ controls['delete_filter'] = this.qr.page.add_field({
label: __('Delete Filter'),
fieldtype: 'Button',
fieldname: 'delete_filter',
click: () => {
- let cur_filter = this.controls['filter_index'].value;
+ let cur_filter = this.controls['filter_index'].get_input_value();
if (cur_filter) {
frappe.confirm(__('Are you sure you want to delete filter ') + cur_filter + '?',
() => {this.delete(cur_filter, 'filter')});
}
}
});
- controls['value_field'] = this.page.add_field({
+ controls['value_field'] = this.qr.page.add_field({
label: __('Value Column'),
fieldtype: 'Select',
fieldname: 'value_field',
@@ -346,37 +368,35 @@ class TaxReport {
this.controls['value_field'].set_input(this.controls['value_field'].get_input_value());
}
});
- controls['save'] = this.page.add_field({
+ controls['save'] = this.qr.page.add_field({
label: __('Save & Run'),
fieldtype: 'Button',
fieldname: 'save',
click: () => {
- this.controls['section_name'].set_input('');
- this.set_mode('run');
this.save_report();
}
});
- controls['show_detail'] = this.page.add_field({
+ controls['show_detail'] = this.qr.page.add_field({
label: __('Show Detail'),
fieldtype: 'Check',
fieldname: 'show_detail',
default: 1
});
this.controls = controls;
- this.set_value_options();
- this.get_filter_controls();
- this.show_help();
}
show_help() {
const help = __(`You can add multiple sections to your custom report using the New Section button above.
- To specify what data goes in each section, specify column filters below, then save with Add Filter.
- Each section can have multiple filters added.
- You can specify which Currency column will be summed for each filter in the final report with the Value Column select box.
- Once you're done, hit Save & Run.`);
- this.qr.show_status(help);
+ To specify what data goes in each section, specify column filters in the data table, then save with Add Filter.
+ Each section can have multiple filters added but be careful with the duplicated data rows.
+ You can specify which Currency column will be summed for each filter in the final report with the Value Column
+ select box. Once you're done, hit Save & Run.`);
+ this.qr.$report_footer.append(`${help}
`);
}
}
+if (!window.taxdetail) {
+ window.taxdetail = new erpnext.TaxDetail();
+}
function get_reports(cb) {
frappe.call({
@@ -387,23 +407,9 @@ function get_reports(cb) {
})
}
-function override_menu() {
- //TODO: Replace save button
- this.qr.menu_items.forEach((item, idx) => {
- if (item['label'] == __('Save')) {
- delete this.qr.menu_items[idx];
- }
- })
- this.qr.menu_items.push({
- label: __('Save'),
- action: this.save_report
- })
- this.qr.set_menu_items();
-}
-
function new_report() {
const dialog = new frappe.ui.Dialog({
- title: __("New Report"),
+ title: __('New Report'),
fields: [
{
fieldname: 'report_name',
@@ -424,7 +430,7 @@ function new_report() {
},
freeze: true
}).then((r) => {
- frappe.set_route("query-report", values.report_name);
+ frappe.set_route('query-report', values.report_name);
});
dialog.hide();
}
@@ -435,7 +441,7 @@ function new_report() {
function load_report() {
get_reports(function load_report_cb(reports) {
const dialog = new frappe.ui.Dialog({
- title: __("Load Report"),
+ title: __('Load Report'),
fields: [
{
fieldname: 'report_name',
@@ -447,7 +453,7 @@ function load_report() {
primary_action_label: __('Load'),
primary_action: function load_report_pa(values) {
dialog.hide();
- frappe.set_route("query-report", values.report_name);
+ frappe.set_route('query-report', values.report_name);
}
});
dialog.show();
From 5d9217ab29d2f335b862a06f17f07151c8684051 Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Wed, 24 Mar 2021 04:01:18 +0000
Subject: [PATCH 115/149] fix: minor bugs and improvements
---
.../accounts/report/tax_detail/tax_detail.js | 22 +++++++++----------
.../accounts/report/tax_detail/tax_detail.py | 4 +++-
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.js b/erpnext/accounts/report/tax_detail/tax_detail.js
index 6049000404..5da63dec57 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.js
+++ b/erpnext/accounts/report/tax_detail/tax_detail.js
@@ -81,7 +81,6 @@ erpnext.TaxDetail = class TaxDetail {
}
show_footer_message() {
// The last thing to run after datatable_render in refresh()
- console.log('show_footer_message');
this.super.show_footer_message.apply(this.qr);
if (this.qr.report_name !== 'Tax Detail') {
this.set_value_options();
@@ -97,7 +96,6 @@ erpnext.TaxDetail = class TaxDetail {
// Infrequent report build (onload), load filters & data
// super function runs a refresh() serially
// already run within frappe.run_serially
- console.log('refresh_report');
this.loading = true;
this.super.refresh_report.apply(this.qr);
if (this.qr.report_name !== 'Tax Detail') {
@@ -115,21 +113,23 @@ erpnext.TaxDetail = class TaxDetail {
load_report() {
// One-off report build like titles, menu, etc
// Run when this object is created which happens in qr.load_report
- console.log('load_report');
this.qr.menu_items = this.get_menu_items();
}
get_menu_items() {
- // Replace save button
+ // Replace Save, remove Add Column
let new_items = [];
- const label = __('Save');
+ const save = __('Save');
+ const addColumn = __('Add Column');
for (let item of this.qr.menu_items) {
- if (item.label === label) {
+ if (item.label === save) {
new_items.push({
- label: label,
- action: this.save_report,
+ label: save,
+ action: () => this.save_report(),
standard: false
});
+ } else if (item.label === addColumn) {
+ // Don't add
} else {
new_items.push(item);
}
@@ -279,9 +279,6 @@ erpnext.TaxDetail = class TaxDetail {
}
}
create_controls() {
- if (this.controls) {
- return;
- }
let controls = {};
// SELECT in data.js
controls['section_name'] = this.qr.page.add_field({
@@ -389,7 +386,8 @@ erpnext.TaxDetail = class TaxDetail {
To specify what data goes in each section, specify column filters in the data table, then save with Add Filter.
Each section can have multiple filters added but be careful with the duplicated data rows.
You can specify which Currency column will be summed for each filter in the final report with the Value Column
- select box. Once you're done, hit Save & Run.`);
+ select box. Use the Show Detail box to see the data rows included in each section in the final report.
+ Once you're done, hit Save & Run.`);
this.qr.$report_footer.append(`${help}
`);
}
}
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py
index 6bed89841c..db1bf5b678 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/tax_detail.py
@@ -6,6 +6,8 @@ from __future__ import unicode_literals
import frappe, json
from frappe import _
+# NOTE: Not compatible with the frappe custom report feature of adding arbitrary doctype columns to the report
+
# field lists in multiple doctypes will be coalesced
required_sql_fields = {
"GL Entry": ["posting_date", "voucher_type", "voucher_no", "account", "account_currency", "debit", "credit"],
@@ -87,7 +89,7 @@ def run_report(report_name, data):
new_data += [ {columns[1]['fieldname']: section_name, columns[2]['fieldname']: section_total} ]
summary += [ {'label': section_name, 'datatype': 'Currency', 'value': section_total} ]
if show_detail: new_data += [ {} ]
- return new_data if new_data else data, summary
+ return new_data or data, summary or None
def filter_match(value, string):
"Approximation to datatable filters"
From 3027cc7da61c81b8b99ea672917766e5c0530fc7 Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Wed, 24 Mar 2021 04:30:28 +0000
Subject: [PATCH 116/149] fix: minor bug and tidy
---
erpnext/accounts/report/tax_detail/tax_detail.js | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.js b/erpnext/accounts/report/tax_detail/tax_detail.js
index 5da63dec57..391aacf391 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.js
+++ b/erpnext/accounts/report/tax_detail/tax_detail.js
@@ -172,8 +172,8 @@ erpnext.TaxDetail = class TaxDetail {
}
}
set_value_label_from_filter() {
- const section_name = this.controls['section_name'].value;
- const fidx = this.controls['filter_index'].value;
+ const section_name = this.controls['section_name'].get_input_value();
+ const fidx = this.controls['filter_index'].get_input_value();
if (section_name && fidx) {
const fieldname = this.sections[section_name][fidx]['fieldname'];
this.controls['value_field'].set_input(this.label_lookup[fieldname]);
@@ -182,7 +182,7 @@ erpnext.TaxDetail = class TaxDetail {
}
}
get_value_fieldname() {
- const curlabel = this.controls['value_field'].value;
+ const curlabel = this.controls['value_field'].get_input_value();
return this.fieldname_lookup[curlabel];
}
new_section(label) {
@@ -203,6 +203,7 @@ erpnext.TaxDetail = class TaxDetail {
}
set_section(name) {
// Sets the given section name and then reloads the data
+ this.controls['filter_index'].set_input('');
if (name && !this.sections[name]) {
this.sections[name] = {};
}
@@ -224,10 +225,10 @@ erpnext.TaxDetail = class TaxDetail {
refresh = true;
}
}
- this.reload_filter();
if (refresh) {
this.qr.refresh();
}
+ this.reload_filter();
}
reload_filter() {
const section_name = this.controls['section_name'].get_input_value();
From ece00287eadf326e68945c4221ee20429306cb9a Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Sat, 27 Mar 2021 03:02:30 +0000
Subject: [PATCH 117/149] Refactor for Journal Entries (payroll)
---
.../accounts/report/tax_detail/tax_detail.py | 90 ++++++++++++++-----
1 file changed, 69 insertions(+), 21 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py
index db1bf5b678..b08e796807 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/tax_detail.py
@@ -7,15 +7,18 @@ import frappe, json
from frappe import _
# NOTE: Not compatible with the frappe custom report feature of adding arbitrary doctype columns to the report
+# NOTE: Payroll is implemented using Journal Entries
# field lists in multiple doctypes will be coalesced
required_sql_fields = {
- "GL Entry": ["posting_date", "voucher_type", "voucher_no", "account", "account_currency", "debit", "credit"],
- "Account": ["account_type"],
+ "GL Entry": ["posting_date", "voucher_type", "voucher_no", "account as tax_account", "account_currency", "debit", "credit"],
+# "Account": ["account_type"],
+ "Journal Entry Account": ["account_type", "account", "debit_in_account_currency", "credit_in_account_currency"],
+ ("Purchase Invoice Item", "Sales Invoice Item"): ["base_net_amount", "item_tax_rate", "item_tax_template", "item_name"],
("Purchase Invoice", "Sales Invoice"): ["taxes_and_charges", "tax_category"],
- ("Purchase Invoice Item", "Sales Invoice Item"): ["item_tax_template", "item_name", "base_net_amount", "item_tax_rate"],
# "Journal Entry": ["total_amount_currency"],
-# "Journal Entry Account": ["debit_in_account_currency", "credit_in_account_currency"]
+ "Purchase Invoice Item": ["expense_account"],
+ "Sales Invoice Item": ["income_account"]
}
@@ -40,9 +43,9 @@ def execute(filters=None):
left join `tabPurchase Invoice Item` pii on
pi.name=pii.parent
/* left outer join `tabJournal Entry` je on
- ge.voucher_no=je.name and ge.company=je.company
+ ge.voucher_no=je.name and ge.company=je.company */
left outer join `tabJournal Entry Account` jea on
- je.name=jea.parent and a.account_type='Tax' */
+ ge.voucher_type=jea.parenttype and ge.voucher_no=jea.parent
where (ge.voucher_type, ge.voucher_no) in (
select ge.voucher_type, ge.voucher_no
from `tabGL Entry` ge
@@ -142,7 +145,18 @@ def subtotal(data, field):
abbrev = lambda dt: ''.join(l[0].lower() for l in dt.split(' ')) + '.'
doclist = lambda dt, dfs: [abbrev(dt) + f for f in dfs]
-coalesce = lambda dts, dfs: ['coalesce(' + ', '.join(abbrev(dt) + f for dt in dts) + ') ' + f for f in dfs]
+
+def as_split(fields):
+ for field in fields:
+ split = field.split(' as ')
+ yield (split[0], split[1] if len(split) > 1 else split[0])
+
+def coalesce(doctypes, fields):
+ coalesce = []
+ for name, new_name in as_split(fields):
+ sharedfields = ', '.join(abbrev(dt) + name for dt in doctypes)
+ coalesce += [f'coalesce({sharedfields}) as {new_name}']
+ return coalesce
def get_fieldstr(fieldlist):
fields = []
@@ -158,20 +172,22 @@ def get_columns(fieldlist):
for doctypes, docfields in fieldlist.items():
if isinstance(doctypes, str):
doctypes = [doctypes]
+ fieldmap = {name: new_name for name, new_name in as_split(docfields)}
for doctype in doctypes:
meta = frappe.get_meta(doctype)
# get column field metadata from the db
fieldmeta = {}
for field in meta.get('fields'):
- if field.fieldname in docfields:
- fieldmeta[field.fieldname] = {
+ if field.fieldname in fieldmap.keys():
+ new_name = fieldmap[field.fieldname]
+ fieldmeta[new_name] = {
"label": _(field.label),
- "fieldname": field.fieldname,
+ "fieldname": new_name,
"fieldtype": field.fieldtype,
"options": field.options
}
# edit the columns to match the modified data
- for field in docfields:
+ for field in fieldmap.values():
col = modify_report_columns(doctype, field, fieldmeta[field])
if col:
columns[col["fieldname"]] = col
@@ -182,10 +198,28 @@ def modify_report_columns(doctype, field, column):
"Because data is rearranged into other columns"
if doctype in ["Sales Invoice Item", "Purchase Invoice Item"] and field == "item_tax_rate":
return None
+ if doctype == "GL Entry" and field == "tax_account":
+ column.update({"label": _("Tax Account")})
+ if doctype == "GL Entry" and field == "debit":
+ column.update({"label": _("Tax Debit")})
+ if doctype == "GL Entry" and field == "credit":
+ column.update({"label": _("Tax Credit")})
+
+ if doctype == "Journal Entry Account" and field == "debit_in_account_currency":
+ column.update({"label": _("Debit Net Amount"), "fieldname": "debit_net_amount"})
+ if doctype == "Journal Entry Account" and field == "credit_in_account_currency":
+ column.update({"label": _("Credit Net Amount"), "fieldname": "credit_net_amount"})
+
if doctype == "Sales Invoice Item" and field == "base_net_amount":
column.update({"label": _("Credit Net Amount"), "fieldname": "credit_net_amount"})
+ if doctype == "Sales Invoice Item" and field == "income_account":
+ column.update({"label": _("Account"), "fieldname": "account"})
+
if doctype == "Purchase Invoice Item" and field == "base_net_amount":
column.update({"label": _("Debit Net Amount"), "fieldname": "debit_net_amount"})
+ if doctype == "Purchase Invoice Item" and field == "expense_account":
+ column.update({"label": _("Account"), "fieldname": "account"})
+
if field == "taxes_and_charges":
column.update({"label": _("Taxes and Charges Template")})
return column
@@ -193,16 +227,30 @@ def modify_report_columns(doctype, field, column):
def modify_report_data(data):
import json
for line in data:
- if line.account_type == "Tax" and line.item_tax_rate:
- tax_rates = json.loads(line.item_tax_rate)
- for account, rate in tax_rates.items():
- if account == line.account:
- if line.voucher_type == "Sales Invoice":
- line.credit = line.base_net_amount * (rate / 100)
- line.credit_net_amount = line.base_net_amount
- if line.voucher_type == "Purchase Invoice":
- line.debit = line.base_net_amount * (rate / 100)
- line.debit_net_amount = line.base_net_amount
+ # Transform Invoice lines
+ if "Invoice" in line.voucher_type:
+ if line.income_account:
+ line.account = line.income_account
+ line.account_type = "Income Account"
+ if line.expense_account:
+ line.account = line.expense_account
+ line.account_type = "Expense Account"
+ if line.item_tax_rate:
+ tax_rates = json.loads(line.item_tax_rate)
+ for account, rate in tax_rates.items():
+ if account == line.account:
+ if line.voucher_type == "Sales Invoice":
+ line.credit = line.base_net_amount * (rate / 100)
+ line.credit_net_amount = line.base_net_amount
+ if line.voucher_type == "Purchase Invoice":
+ line.debit = line.base_net_amount * (rate / 100)
+ line.debit_net_amount = line.base_net_amount
+ # Transform Journal Entry lines
+ if "Journal" in line.voucher_type:
+ if line.debit_in_account_currency:
+ line.debit_net_amount = line.debit_in_account_currency
+ if line.credit_in_account_currency:
+ line.credit_net_amount = line.credit_in_account_currency
return data
####### JS client utilities
From 442a0de09496a843c33f24e98c59ffa0ec5138df Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Sat, 27 Mar 2021 04:02:59 +0000
Subject: [PATCH 118/149] fix: finalise query, fix bugs, put Add Columns back
---
.../accounts/report/tax_detail/tax_detail.js | 12 +++----
.../accounts/report/tax_detail/tax_detail.py | 31 +++++++------------
2 files changed, 18 insertions(+), 25 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.js b/erpnext/accounts/report/tax_detail/tax_detail.js
index 391aacf391..56694fbec2 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.js
+++ b/erpnext/accounts/report/tax_detail/tax_detail.js
@@ -116,10 +116,9 @@ erpnext.TaxDetail = class TaxDetail {
this.qr.menu_items = this.get_menu_items();
}
get_menu_items() {
- // Replace Save, remove Add Column
+ // Replace Save action
let new_items = [];
const save = __('Save');
- const addColumn = __('Add Column');
for (let item of this.qr.menu_items) {
if (item.label === save) {
@@ -128,8 +127,6 @@ erpnext.TaxDetail = class TaxDetail {
action: () => this.save_report(),
standard: false
});
- } else if (item.label === addColumn) {
- // Don't add
} else {
new_items.push(item);
}
@@ -424,8 +421,11 @@ function new_report() {
args: {
reference_report: 'Tax Detail',
report_name: values.report_name,
- columns: frappe.query_report.get_visible_columns(),
- sections: {}
+ data: {
+ columns: [],
+ sections: {},
+ show_detail: 1
+ }
},
freeze: true
}).then((r) => {
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py
index b08e796807..c4ec1374ce 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/tax_detail.py
@@ -6,17 +6,14 @@ from __future__ import unicode_literals
import frappe, json
from frappe import _
-# NOTE: Not compatible with the frappe custom report feature of adding arbitrary doctype columns to the report
# NOTE: Payroll is implemented using Journal Entries
# field lists in multiple doctypes will be coalesced
required_sql_fields = {
"GL Entry": ["posting_date", "voucher_type", "voucher_no", "account as tax_account", "account_currency", "debit", "credit"],
-# "Account": ["account_type"],
"Journal Entry Account": ["account_type", "account", "debit_in_account_currency", "credit_in_account_currency"],
("Purchase Invoice Item", "Sales Invoice Item"): ["base_net_amount", "item_tax_rate", "item_tax_template", "item_name"],
("Purchase Invoice", "Sales Invoice"): ["taxes_and_charges", "tax_category"],
-# "Journal Entry": ["total_amount_currency"],
"Purchase Invoice Item": ["expense_account"],
"Sales Invoice Item": ["income_account"]
}
@@ -35,27 +32,20 @@ def execute(filters=None):
inner join `tabAccount` a on
ge.account=a.name and ge.company=a.company
left join `tabSales Invoice` si on
- a.account_type='Tax' and ge.company=si.company and ge.voucher_type='Sales Invoice' and ge.voucher_no=si.name
+ ge.company=si.company and ge.voucher_type='Sales Invoice' and ge.voucher_no=si.name
left join `tabSales Invoice Item` sii on
si.name=sii.parent
left join `tabPurchase Invoice` pi on
- a.account_type='Tax' and ge.company=pi.company and ge.voucher_type='Purchase Invoice' and ge.voucher_no=pi.name
+ ge.company=pi.company and ge.voucher_type='Purchase Invoice' and ge.voucher_no=pi.name
left join `tabPurchase Invoice Item` pii on
pi.name=pii.parent
-/* left outer join `tabJournal Entry` je on
- ge.voucher_no=je.name and ge.company=je.company */
- left outer join `tabJournal Entry Account` jea on
+ left join `tabJournal Entry Account` jea on
ge.voucher_type=jea.parenttype and ge.voucher_no=jea.parent
- where (ge.voucher_type, ge.voucher_no) in (
- select ge.voucher_type, ge.voucher_no
- from `tabGL Entry` ge
- join `tabAccount` a on ge.account=a.name and ge.company=a.company
- where
- a.account_type='Tax' and
- ge.company=%(company)s and
- ge.posting_date>=%(from_date)s and
- ge.posting_date<=%(to_date)s
- )
+ where
+ a.account_type='Tax' and
+ ge.company=%(company)s and
+ ge.posting_date>=%(from_date)s and
+ ge.posting_date<=%(to_date)s
order by ge.posting_date, ge.voucher_no
""".format(fieldstr=fieldstr), filters, as_dict=1)
@@ -238,7 +228,7 @@ def modify_report_data(data):
if line.item_tax_rate:
tax_rates = json.loads(line.item_tax_rate)
for account, rate in tax_rates.items():
- if account == line.account:
+ if account == line.tax_account:
if line.voucher_type == "Sales Invoice":
line.credit = line.base_net_amount * (rate / 100)
line.credit_net_amount = line.base_net_amount
@@ -247,6 +237,9 @@ def modify_report_data(data):
line.debit_net_amount = line.base_net_amount
# Transform Journal Entry lines
if "Journal" in line.voucher_type:
+ if line.account_type != 'Tax':
+ line.debit = 0.0
+ line.credit = 0.0
if line.debit_in_account_currency:
line.debit_net_amount = line.debit_in_account_currency
if line.credit_in_account_currency:
From 1c37390899724d152a2152d50e2e0c543368471e Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Tue, 30 Mar 2021 17:03:16 +0000
Subject: [PATCH 119/149] fix: Change & simplify query to cater for zero rate
tax entries
---
.../accounts/report/tax_detail/tax_detail.py | 94 ++++++-------------
1 file changed, 31 insertions(+), 63 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py
index c4ec1374ce..1f4d1ba8a0 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/tax_detail.py
@@ -6,16 +6,15 @@ from __future__ import unicode_literals
import frappe, json
from frappe import _
-# NOTE: Payroll is implemented using Journal Entries
+# NOTE: Payroll is implemented using Journal Entries which translate directly to GL Entries
# field lists in multiple doctypes will be coalesced
required_sql_fields = {
- "GL Entry": ["posting_date", "voucher_type", "voucher_no", "account as tax_account", "account_currency", "debit", "credit"],
- "Journal Entry Account": ["account_type", "account", "debit_in_account_currency", "credit_in_account_currency"],
- ("Purchase Invoice Item", "Sales Invoice Item"): ["base_net_amount", "item_tax_rate", "item_tax_template", "item_name"],
+ ("GL Entry", 1): ["posting_date"],
+ ("Account",): ["account_type"],
+ ("GL Entry", 2): ["account", "voucher_type", "voucher_no", "debit", "credit"],
+ ("Purchase Invoice Item", "Sales Invoice Item"): ["base_net_amount", "item_tax_rate", "item_tax_template", "item_group", "item_name"],
("Purchase Invoice", "Sales Invoice"): ["taxes_and_charges", "tax_category"],
- "Purchase Invoice Item": ["expense_account"],
- "Sales Invoice Item": ["income_account"]
}
@@ -34,15 +33,12 @@ def execute(filters=None):
left join `tabSales Invoice` si on
ge.company=si.company and ge.voucher_type='Sales Invoice' and ge.voucher_no=si.name
left join `tabSales Invoice Item` sii on
- si.name=sii.parent
+ a.root_type='Income' and si.name=sii.parent
left join `tabPurchase Invoice` pi on
ge.company=pi.company and ge.voucher_type='Purchase Invoice' and ge.voucher_no=pi.name
left join `tabPurchase Invoice Item` pii on
- pi.name=pii.parent
- left join `tabJournal Entry Account` jea on
- ge.voucher_type=jea.parenttype and ge.voucher_no=jea.parent
+ a.root_type='Expense' and pi.name=pii.parent
where
- a.account_type='Tax' and
ge.company=%(company)s and
ge.posting_date>=%(from_date)s and
ge.posting_date<=%(to_date)s
@@ -151,19 +147,18 @@ def coalesce(doctypes, fields):
def get_fieldstr(fieldlist):
fields = []
for doctypes, docfields in fieldlist.items():
- if isinstance(doctypes, str):
- fields += doclist(doctypes, docfields)
- if isinstance(doctypes, tuple):
+ if len(doctypes) == 1 or isinstance(doctypes[1], int):
+ fields += doclist(doctypes[0], docfields)
+ else:
fields += coalesce(doctypes, docfields)
return ', '.join(fields)
def get_columns(fieldlist):
columns = {}
for doctypes, docfields in fieldlist.items():
- if isinstance(doctypes, str):
- doctypes = [doctypes]
fieldmap = {name: new_name for name, new_name in as_split(docfields)}
for doctype in doctypes:
+ if isinstance(doctype, int): break
meta = frappe.get_meta(doctype)
# get column field metadata from the db
fieldmeta = {}
@@ -186,29 +181,9 @@ def get_columns(fieldlist):
def modify_report_columns(doctype, field, column):
"Because data is rearranged into other columns"
- if doctype in ["Sales Invoice Item", "Purchase Invoice Item"] and field == "item_tax_rate":
- return None
- if doctype == "GL Entry" and field == "tax_account":
- column.update({"label": _("Tax Account")})
- if doctype == "GL Entry" and field == "debit":
- column.update({"label": _("Tax Debit")})
- if doctype == "GL Entry" and field == "credit":
- column.update({"label": _("Tax Credit")})
-
- if doctype == "Journal Entry Account" and field == "debit_in_account_currency":
- column.update({"label": _("Debit Net Amount"), "fieldname": "debit_net_amount"})
- if doctype == "Journal Entry Account" and field == "credit_in_account_currency":
- column.update({"label": _("Credit Net Amount"), "fieldname": "credit_net_amount"})
-
- if doctype == "Sales Invoice Item" and field == "base_net_amount":
- column.update({"label": _("Credit Net Amount"), "fieldname": "credit_net_amount"})
- if doctype == "Sales Invoice Item" and field == "income_account":
- column.update({"label": _("Account"), "fieldname": "account"})
-
- if doctype == "Purchase Invoice Item" and field == "base_net_amount":
- column.update({"label": _("Debit Net Amount"), "fieldname": "debit_net_amount"})
- if doctype == "Purchase Invoice Item" and field == "expense_account":
- column.update({"label": _("Account"), "fieldname": "account"})
+ if doctype in ["Sales Invoice Item", "Purchase Invoice Item"]:
+ if field in ["item_tax_rate", "base_net_amount"]:
+ return None
if field == "taxes_and_charges":
column.update({"label": _("Taxes and Charges Template")})
@@ -216,35 +191,28 @@ def modify_report_columns(doctype, field, column):
def modify_report_data(data):
import json
+ new_data = []
for line in data:
- # Transform Invoice lines
+ # Remove Invoice GL Tax Entries and generate Tax entries from the invoice lines
if "Invoice" in line.voucher_type:
- if line.income_account:
- line.account = line.income_account
- line.account_type = "Income Account"
- if line.expense_account:
- line.account = line.expense_account
- line.account_type = "Expense Account"
+ if line.account_type != "Tax":
+ new_data += [line]
if line.item_tax_rate:
tax_rates = json.loads(line.item_tax_rate)
for account, rate in tax_rates.items():
- if account == line.tax_account:
- if line.voucher_type == "Sales Invoice":
- line.credit = line.base_net_amount * (rate / 100)
- line.credit_net_amount = line.base_net_amount
- if line.voucher_type == "Purchase Invoice":
- line.debit = line.base_net_amount * (rate / 100)
- line.debit_net_amount = line.base_net_amount
- # Transform Journal Entry lines
- if "Journal" in line.voucher_type:
- if line.account_type != 'Tax':
- line.debit = 0.0
- line.credit = 0.0
- if line.debit_in_account_currency:
- line.debit_net_amount = line.debit_in_account_currency
- if line.credit_in_account_currency:
- line.credit_net_amount = line.credit_in_account_currency
- return data
+ tax_line = line.copy()
+ tax_line.account_type = "Tax"
+ tax_line.account = account
+ if line.voucher_type == "Sales Invoice":
+ line.credit = line.base_net_amount
+ tax_line.credit = line.base_net_amount * (rate / 100)
+ if line.voucher_type == "Purchase Invoice":
+ line.debit = line.base_net_amount
+ tax_line.debit = line.base_net_amount * (rate / 100)
+ new_data += [tax_line]
+ else:
+ new_data += [line]
+ return new_data
####### JS client utilities
From 2cb0da8780cedb4b13d76a40766427f9f2632e8d Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Thu, 1 Apr 2021 22:31:24 +0000
Subject: [PATCH 120/149] fix: rewrite to allow referring to existing sections
and reduce to single amount column
---
.../accounts/report/tax_detail/tax_detail.js | 235 +++++++++---------
.../accounts/report/tax_detail/tax_detail.py | 60 +++--
2 files changed, 153 insertions(+), 142 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.js b/erpnext/accounts/report/tax_detail/tax_detail.js
index 56694fbec2..0c0397ab04 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.js
+++ b/erpnext/accounts/report/tax_detail/tax_detail.js
@@ -43,7 +43,7 @@ frappe.query_reports["Tax Detail"] = {
fieldname: "mode",
label: __("Mode"),
fieldtype: "Read Only",
- default: "run",
+ default: "edit",
hidden: 1,
reqd: 1
}
@@ -83,12 +83,12 @@ erpnext.TaxDetail = class TaxDetail {
// The last thing to run after datatable_render in refresh()
this.super.show_footer_message.apply(this.qr);
if (this.qr.report_name !== 'Tax Detail') {
- this.set_value_options();
this.show_help();
if (this.loading) {
this.set_section('');
+ } else {
+ this.reload_component('');
}
- this.reload_filter();
}
this.loading = false;
}
@@ -134,6 +134,7 @@ erpnext.TaxDetail = class TaxDetail {
return new_items;
}
save_report() {
+ this.check_datatable();
if (this.qr.report_name !== 'Tax Detail') {
frappe.call({
method:'erpnext.accounts.report.tax_detail.tax_detail.save_custom_report',
@@ -152,55 +153,13 @@ erpnext.TaxDetail = class TaxDetail {
});
}
}
- set_value_options() {
- // May be run with no columns or data
- if (this.qr.columns) {
- this.fieldname_lookup = {};
- this.label_lookup = {};
- this.qr.columns.forEach((col, index) => {
- if (col['fieldtype'] == "Currency") {
- this.fieldname_lookup[col['label']] = col['fieldname'];
- this.label_lookup[col['fieldname']] = col['label'];
- }
- });
- const options = Object.keys(this.fieldname_lookup);
- this.controls['value_field'].$wrapper.find("select").empty().add_options(options);
- this.controls['value_field'].set_input(options[0]);
+ check_datatable() {
+ if (!this.qr.datatable) {
+ frappe.throw(__('Please change the date range to load data first'));
}
}
- set_value_label_from_filter() {
- const section_name = this.controls['section_name'].get_input_value();
- const fidx = this.controls['filter_index'].get_input_value();
- if (section_name && fidx) {
- const fieldname = this.sections[section_name][fidx]['fieldname'];
- this.controls['value_field'].set_input(this.label_lookup[fieldname]);
- } else {
- this.controls['value_field'].set_input(Object.keys(this.fieldname_lookup)[0]);
- }
- }
- get_value_fieldname() {
- const curlabel = this.controls['value_field'].get_input_value();
- return this.fieldname_lookup[curlabel];
- }
- new_section(label) {
- const dialog = new frappe.ui.Dialog({
- title: label,
- fields: [{
- fieldname: 'data',
- label: label,
- fieldtype: 'Data'
- }],
- primary_action_label: label,
- primary_action: (values) => {
- dialog.hide();
- this.set_section(values.data);
- }
- });
- dialog.show();
- }
set_section(name) {
// Sets the given section name and then reloads the data
- this.controls['filter_index'].set_input('');
if (name && !this.sections[name]) {
this.sections[name] = {};
}
@@ -225,43 +184,49 @@ erpnext.TaxDetail = class TaxDetail {
if (refresh) {
this.qr.refresh();
}
- this.reload_filter();
+ this.reload_component('');
}
- reload_filter() {
+ reload_component(component_name) {
const section_name = this.controls['section_name'].get_input_value();
if (section_name) {
- let fidx = this.controls['filter_index'].get_input_value();
- let section = this.sections[section_name];
- let fidxs = Object.keys(section);
- fidxs.unshift('');
- this.controls['filter_index'].$wrapper.find("select").empty().add_options(fidxs);
- this.controls['filter_index'].set_input(fidx);
+ const section = this.sections[section_name];
+ const component_names = Object.keys(section);
+ component_names.unshift('');
+ this.controls['component'].$wrapper.find("select").empty().add_options(component_names);
+ this.controls['component'].set_input(component_name);
+ if (component_name) {
+ this.controls['component_type'].set_input(section[component_name].type);
+ }
} else {
- this.controls['filter_index'].$wrapper.find("select").empty();
- this.controls['filter_index'].set_input('');
+ this.controls['component'].$wrapper.find("select").empty();
+ this.controls['component'].set_input('');
}
this.set_table_filters();
}
set_table_filters() {
let filters = {};
const section_name = this.controls['section_name'].get_input_value();
- const fidx = this.controls['filter_index'].get_input_value();
- if (section_name && fidx) {
- filters = this.sections[section_name][fidx]['filters'];
+ const component_name = this.controls['component'].get_input_value();
+ if (section_name && component_name) {
+ const component_type = this.sections[section_name][component_name].type;
+ if (component_type === 'filter') {
+ filters = this.sections[section_name][component_name]['filters'];
+ }
}
this.setAppliedFilters(filters);
- this.set_value_label_from_filter();
}
setAppliedFilters(filters) {
- Array.from(this.qr.datatable.header.querySelectorAll('.dt-filter')).map(function setFilters(input) {
- let idx = input.dataset.colIndex;
- if (filters[idx]) {
- input.value = filters[idx];
- } else {
- input.value = null;
- }
- });
- this.qr.datatable.columnmanager.applyFilter(filters);
+ if (this.qr.datatable) {
+ Array.from(this.qr.datatable.header.querySelectorAll('.dt-filter')).map(function setFilters(input) {
+ let idx = input.dataset.colIndex;
+ if (filters[idx]) {
+ input.value = filters[idx];
+ } else {
+ input.value = null;
+ }
+ });
+ this.qr.datatable.columnmanager.applyFilter(filters);
+ }
}
delete(name, type) {
if (type === 'section') {
@@ -269,11 +234,10 @@ erpnext.TaxDetail = class TaxDetail {
const new_section = Object.keys(this.sections)[0] || '';
this.set_section(new_section);
}
- if (type === 'filter') {
+ if (type === 'component') {
const cur_section = this.controls['section_name'].get_input_value();
delete this.sections[cur_section][name];
- this.controls['filter_index'].set_input('');
- this.reload_filter();
+ this.reload_component('');
}
}
create_controls() {
@@ -293,7 +257,13 @@ erpnext.TaxDetail = class TaxDetail {
fieldtype: 'Button',
fieldname: 'new_section',
click: () => {
- this.new_section(__('New Section'));
+ frappe.prompt({
+ label: __('Section Name'),
+ fieldname: 'name',
+ fieldtype: 'Data'
+ }, (values) => {
+ this.set_section(values.name);
+ });
}
});
controls['delete_section'] = this.qr.page.add_field({
@@ -308,61 +278,87 @@ erpnext.TaxDetail = class TaxDetail {
}
}
});
- controls['filter_index'] = this.qr.page.add_field({
- label: __('Filter'),
+ controls['component'] = this.qr.page.add_field({
+ label: __('Component'),
fieldtype: 'Select',
- fieldname: 'filter_index',
+ fieldname: 'component',
change: (e) => {
- this.controls['filter_index'].set_input(this.controls['filter_index'].get_input_value());
- this.set_table_filters();
+ this.reload_component(this.controls['component'].get_input_value());
}
});
- controls['add_filter'] = this.qr.page.add_field({
- label: __('Add Filter'),
+ controls['component_type'] = this.qr.page.add_field({
+ label: __('Component Type'),
+ fieldtype: 'Select',
+ fieldname: 'component_type',
+ default: 'filter',
+ options: [
+ {label: __('Filtered Row Subtotal'), value: 'filter'},
+ {label: __('Section Subtotal'), value: 'section'}
+ ]
+ });
+ controls['add_component'] = this.qr.page.add_field({
+ label: __('Add Component'),
fieldtype: 'Button',
- fieldname: 'add_filter',
+ fieldname: 'add_component',
click: () => {
+ this.check_datatable();
let section_name = this.controls['section_name'].get_input_value();
if (section_name) {
- let prefix = 'Filter';
- let data = {
- filters: this.qr.datatable.columnmanager.getAppliedFilters(),
- fieldname: this.get_value_fieldname()
+ const component_type = this.controls['component_type'].get_input_value();
+ let idx = 0;
+ const names = Object.keys(this.sections[section_name]);
+ if (names.length > 0) {
+ const idxs = names.map((key) => parseInt(key.match(/\d+$/)) || 0);
+ idx = Math.max(...idxs) + 1;
}
- const fidxs = Object.keys(this.sections[section_name]);
- let new_idx = prefix + '0';
- if (fidxs.length > 0) {
- const fiidxs = fidxs.map((key) => parseInt(key.replace(prefix, '')));
- new_idx = prefix + (Math.max(...fiidxs) + 1).toString();
+ const filters = this.qr.datatable.columnmanager.getAppliedFilters();
+ if (component_type === 'filter') {
+ const name = 'Filter' + idx.toString();
+ let data = {
+ type: component_type,
+ filters: filters
+ }
+ this.sections[section_name][name] = data;
+ this.reload_component(name);
+ } else if (component_type === 'section') {
+ if (filters && Object.keys(filters).length !== 0) {
+ frappe.show_alert({
+ message: __('Column filters ignored'),
+ indicator: 'yellow'
+ });
+ }
+ let data = {
+ type: component_type
+ }
+ frappe.prompt({
+ label: __('Section'),
+ fieldname: 'section',
+ fieldtype: 'Select',
+ options: Object.keys(this.sections)
+ }, (values) => {
+ this.sections[section_name][values.section] = data;
+ this.reload_component(values.section);
+ });
+ } else {
+ frappe.throw(__('Please select the Component Type first'));
}
- this.sections[section_name][new_idx] = data;
- this.controls['filter_index'].set_input(new_idx);
- this.reload_filter();
} else {
- frappe.throw(__('Please add or select the Section first'));
+ frappe.throw(__('Please select the Section first'));
}
}
});
- controls['delete_filter'] = this.qr.page.add_field({
- label: __('Delete Filter'),
+ controls['delete_component'] = this.qr.page.add_field({
+ label: __('Delete Component'),
fieldtype: 'Button',
- fieldname: 'delete_filter',
+ fieldname: 'delete_component',
click: () => {
- let cur_filter = this.controls['filter_index'].get_input_value();
- if (cur_filter) {
- frappe.confirm(__('Are you sure you want to delete filter ') + cur_filter + '?',
- () => {this.delete(cur_filter, 'filter')});
+ const component = this.controls['component'].get_input_value();
+ if (component) {
+ frappe.confirm(__('Are you sure you want to delete component ') + component + '?',
+ () => {this.delete(component, 'component')});
}
}
});
- controls['value_field'] = this.qr.page.add_field({
- label: __('Value Column'),
- fieldtype: 'Select',
- fieldname: 'value_field',
- change: (e) => {
- this.controls['value_field'].set_input(this.controls['value_field'].get_input_value());
- }
- });
controls['save'] = this.qr.page.add_field({
label: __('Save & Run'),
fieldtype: 'Button',
@@ -380,13 +376,16 @@ erpnext.TaxDetail = class TaxDetail {
this.controls = controls;
}
show_help() {
- const help = __(`You can add multiple sections to your custom report using the New Section button above.
- To specify what data goes in each section, specify column filters in the data table, then save with Add Filter.
- Each section can have multiple filters added but be careful with the duplicated data rows.
- You can specify which Currency column will be summed for each filter in the final report with the Value Column
- select box. Use the Show Detail box to see the data rows included in each section in the final report.
- Once you're done, hit Save & Run.`);
- this.qr.$report_footer.append(`${help}
`);
+ const help = __(`Help: Your custom report is built from General Ledger Entries within the date range.
+ You can add multiple sections to the report using the New Section button.
+ Each component added to a section adds a subset of the data into the specified section.
+ Beware of duplicated data rows.
+ The Filtered Row component type saves the datatable column filters to specify the added data.
+ The Section component type refers to the data in a previously defined section, but it cannot refer to its parent section.
+ The Amount column is summed to give the section subtotal.
+ Use the Show Detail box to see the data rows included in each section in the final report.
+ Once finished, hit Save & Run. Report contributed by`);
+ this.qr.$report_footer.append(``);
}
}
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py
index 1f4d1ba8a0..426e8d4aec 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/tax_detail.py
@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe, json
from frappe import _
-# NOTE: Payroll is implemented using Journal Entries which translate directly to GL Entries
+# NOTE: Payroll is implemented using Journal Entries which are included as GL Entries
# field lists in multiple doctypes will be coalesced
required_sql_fields = {
@@ -60,23 +60,35 @@ def run_report(report_name, data):
columns = report_config.get('columns')
sections = report_config.get('sections', {})
show_detail = report_config.get('show_detail', 1)
+ report = {}
new_data = []
summary = []
for section_name, section in sections.items():
- section_total = 0.0
- for filt_name, filt in section.items():
- value_field = filt['fieldname']
- rmidxs = []
- for colno, filter_string in filt['filters'].items():
- filter_field = columns[int(colno) - 1]['fieldname']
- for i, row in enumerate(data):
- if not filter_match(row[filter_field], filter_string):
- rmidxs += [i]
- rows = [row for i, row in enumerate(data) if i not in rmidxs]
- section_total += subtotal(rows, value_field)
- if show_detail: new_data += rows
- new_data += [ {columns[1]['fieldname']: section_name, columns[2]['fieldname']: section_total} ]
- summary += [ {'label': section_name, 'datatype': 'Currency', 'value': section_total} ]
+ report[section_name] = {'rows': [], 'subtotal': 0.0}
+ for component_name, component in section.items():
+ if component['type'] == 'filter':
+ for row in data:
+ matched = True
+ for colno, filter_string in component['filters'].items():
+ filter_field = columns[int(colno) - 1]['fieldname']
+ if not filter_match(row[filter_field], filter_string):
+ matched = False
+ break
+ if matched:
+ report[section_name]['rows'] += [row]
+ report[section_name]['subtotal'] += row['amount']
+ if component['type'] == 'section':
+ if component_name == section_name:
+ frappe.throw(_("A report component cannot refer to its parent section: ") + section_name)
+ try:
+ report[section_name]['rows'] += report[component_name]['rows']
+ report[section_name]['subtotal'] += report[component_name]['subtotal']
+ except KeyError:
+ frappe.throw(_("A report component can only refer to an earlier section: ") + section_name)
+
+ if show_detail: new_data += report[section_name]['rows']
+ new_data += [ {'voucher_no': section_name, 'amount': report[section_name]['subtotal']} ]
+ summary += [ {'label': section_name, 'datatype': 'Currency', 'value': report[section_name]['subtotal']} ]
if show_detail: new_data += [ {} ]
return new_data or data, summary or None
@@ -123,11 +135,6 @@ def filter_match(value, string):
if operator == '<': return True
return False
-def subtotal(data, field):
- subtotal = 0.0
- for row in data:
- subtotal += row[field]
- return subtotal
abbrev = lambda dt: ''.join(l[0].lower() for l in dt.split(' ')) + '.'
doclist = lambda dt, dfs: [abbrev(dt) + f for f in dfs]
@@ -185,6 +192,9 @@ def modify_report_columns(doctype, field, column):
if field in ["item_tax_rate", "base_net_amount"]:
return None
+ if doctype == "GL Entry" and field in ["debit", "credit"]:
+ column.update({"label": _("Amount"), "fieldname": "amount"})
+
if field == "taxes_and_charges":
column.update({"label": _("Taxes and Charges Template")})
return column
@@ -193,6 +203,8 @@ def modify_report_data(data):
import json
new_data = []
for line in data:
+ if line.debit: line.amount = -line.debit
+ else: line.amount = line.credit
# Remove Invoice GL Tax Entries and generate Tax entries from the invoice lines
if "Invoice" in line.voucher_type:
if line.account_type != "Tax":
@@ -204,11 +216,11 @@ def modify_report_data(data):
tax_line.account_type = "Tax"
tax_line.account = account
if line.voucher_type == "Sales Invoice":
- line.credit = line.base_net_amount
- tax_line.credit = line.base_net_amount * (rate / 100)
+ line.amount = line.base_net_amount
+ tax_line.amount = line.base_net_amount * (rate / 100)
if line.voucher_type == "Purchase Invoice":
- line.debit = line.base_net_amount
- tax_line.debit = line.base_net_amount * (rate / 100)
+ line.amount = -line.base_net_amount
+ tax_line.amount = -line.base_net_amount * (rate / 100)
new_data += [tax_line]
else:
new_data += [line]
From 77ffa6b1f67a4ee69066f749ce14b4e1ff29711a Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Thu, 8 Apr 2021 22:19:31 +0000
Subject: [PATCH 121/149] feat: add test case for report output
---
.../accounts/report/tax_detail/tax_detail.py | 2 +-
.../report/tax_detail/test_tax_detail.json | 755 ++++++++++++++++++
.../report/tax_detail/test_tax_detail.py | 96 ++-
3 files changed, 847 insertions(+), 6 deletions(-)
create mode 100644 erpnext/accounts/report/tax_detail/test_tax_detail.json
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py
index 426e8d4aec..fb7791f7e1 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/tax_detail.py
@@ -11,7 +11,7 @@ from frappe import _
# field lists in multiple doctypes will be coalesced
required_sql_fields = {
("GL Entry", 1): ["posting_date"],
- ("Account",): ["account_type"],
+ ("Account",): ["root_type", "account_type"],
("GL Entry", 2): ["account", "voucher_type", "voucher_no", "debit", "credit"],
("Purchase Invoice Item", "Sales Invoice Item"): ["base_net_amount", "item_tax_rate", "item_tax_template", "item_group", "item_name"],
("Purchase Invoice", "Sales Invoice"): ["taxes_and_charges", "tax_category"],
diff --git a/erpnext/accounts/report/tax_detail/test_tax_detail.json b/erpnext/accounts/report/tax_detail/test_tax_detail.json
new file mode 100644
index 0000000000..17248d0320
--- /dev/null
+++ b/erpnext/accounts/report/tax_detail/test_tax_detail.json
@@ -0,0 +1,755 @@
+[
+ {
+ "abbr": "_T",
+ "company_name": "_T",
+ "country": "United Kingdom",
+ "default_currency": "GBP",
+ "doctype": "Company",
+ "name": "_T"
+ },{
+ "account_currency": "GBP",
+ "account_name": "Debtors",
+ "account_number": "",
+ "account_type": "Receivable",
+ "balance_must_be": "",
+ "company": "_T",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Account",
+ "freeze_account": "No",
+ "include_in_gross": 0,
+ "inter_company_account": 0,
+ "is_group": 0,
+ "lft": 58,
+ "modified": "2021-03-26 04:44:19.955468",
+ "name": "Debtors - _T",
+ "old_parent": null,
+ "parent": null,
+ "parent_account": "Application of Funds (Assets) - _T",
+ "parentfield": null,
+ "parenttype": null,
+ "report_type": "Balance Sheet",
+ "rgt": 59,
+ "root_type": "Asset",
+ "tax_rate": 0.0
+ },{
+ "account_currency": "GBP",
+ "account_name": "Sales",
+ "account_number": "",
+ "account_type": "Income Account",
+ "balance_must_be": "",
+ "company": "_T",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Account",
+ "freeze_account": "No",
+ "include_in_gross": 0,
+ "inter_company_account": 0,
+ "is_group": 0,
+ "lft": 291,
+ "modified": "2021-03-26 04:50:21.697703",
+ "name": "Sales - _T",
+ "old_parent": null,
+ "parent": null,
+ "parent_account": "Income - _T",
+ "parentfield": null,
+ "parenttype": null,
+ "report_type": "Profit and Loss",
+ "rgt": 292,
+ "root_type": "Income",
+ "tax_rate": 0.0
+ },{
+ "account_currency": "GBP",
+ "account_name": "VAT on Sales",
+ "account_number": "",
+ "account_type": "Tax",
+ "balance_must_be": "",
+ "company": "_T",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Account",
+ "freeze_account": "No",
+ "include_in_gross": 0,
+ "inter_company_account": 0,
+ "is_group": 0,
+ "lft": 317,
+ "modified": "2021-03-26 04:50:21.697703",
+ "name": "VAT on Sales - _T",
+ "old_parent": null,
+ "parent": null,
+ "parent_account": "Source of Funds (Liabilities) - _T",
+ "parentfield": null,
+ "parenttype": null,
+ "report_type": "Balance Sheet",
+ "rgt": 318,
+ "root_type": "Liability",
+ "tax_rate": 0.0
+ },{
+ "account_currency": "GBP",
+ "account_name": "Cost of Goods Sold",
+ "account_number": "",
+ "account_type": "Cost of Goods Sold",
+ "balance_must_be": "",
+ "company": "_T",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Account",
+ "freeze_account": "No",
+ "include_in_gross": 0,
+ "inter_company_account": 0,
+ "is_group": 0,
+ "lft": 171,
+ "modified": "2021-03-26 04:44:19.994857",
+ "name": "Cost of Goods Sold - _T",
+ "old_parent": null,
+ "parent": null,
+ "parent_account": "Expenses - _T",
+ "parentfield": null,
+ "parenttype": null,
+ "report_type": "Profit and Loss",
+ "rgt": 172,
+ "root_type": "Expense",
+ "tax_rate": 0.0
+ },{
+ "account_currency": "GBP",
+ "account_name": "VAT on Purchases",
+ "account_number": "",
+ "account_type": "Tax",
+ "balance_must_be": "",
+ "company": "_T",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Account",
+ "freeze_account": "No",
+ "include_in_gross": 0,
+ "inter_company_account": 0,
+ "is_group": 0,
+ "lft": 80,
+ "modified": "2021-03-26 04:44:19.961983",
+ "name": "VAT on Purchases - _T",
+ "old_parent": null,
+ "parent": null,
+ "parent_account": "Application of Funds (Assets) - _T",
+ "parentfield": null,
+ "parenttype": null,
+ "report_type": "Balance Sheet",
+ "rgt": 81,
+ "root_type": "Asset",
+ "tax_rate": 0.0
+ },{
+ "account_currency": "GBP",
+ "account_name": "Creditors",
+ "account_number": "",
+ "account_type": "Payable",
+ "balance_must_be": "",
+ "company": "_T",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Account",
+ "freeze_account": "No",
+ "include_in_gross": 0,
+ "inter_company_account": 0,
+ "is_group": 0,
+ "lft": 302,
+ "modified": "2021-03-26 04:50:21.697703",
+ "name": "Creditors - _T",
+ "old_parent": null,
+ "parent": null,
+ "parent_account": "Source of Funds (Liabilities) - _T",
+ "parentfield": null,
+ "parenttype": null,
+ "report_type": "Balance Sheet",
+ "rgt": 303,
+ "root_type": "Liability",
+ "tax_rate": 0.0
+ },{
+ "additional_discount_percentage": 0.0,
+ "address_display": null,
+ "adjust_advance_taxes": 0,
+ "advances": [],
+ "against_expense_account": "Cost of Goods Sold - _T",
+ "allocate_advances_automatically": 0,
+ "amended_from": null,
+ "apply_discount_on": "Grand Total",
+ "apply_tds": 0,
+ "auto_repeat": null,
+ "base_discount_amount": 0.0,
+ "base_grand_total": 511.68,
+ "base_in_words": "GBP Five Hundred And Eleven and Sixty Eight Pence only.",
+ "base_net_total": 426.4,
+ "base_paid_amount": 0.0,
+ "base_rounded_total": 511.68,
+ "base_rounding_adjustment": 0.0,
+ "base_taxes_and_charges_added": 85.28,
+ "base_taxes_and_charges_deducted": 0.0,
+ "base_total": 426.4,
+ "base_total_taxes_and_charges": 85.28,
+ "base_write_off_amount": 0.0,
+ "bill_date": null,
+ "bill_no": null,
+ "billing_address": null,
+ "billing_address_display": null,
+ "buying_price_list": "Standard Buying",
+ "cash_bank_account": null,
+ "clearance_date": null,
+ "company": "_T",
+ "contact_display": null,
+ "contact_email": null,
+ "contact_mobile": null,
+ "contact_person": null,
+ "conversion_rate": 1.0,
+ "cost_center": null,
+ "credit_to": "Creditors - _T",
+ "currency": "GBP",
+ "disable_rounded_total": 0,
+ "discount_amount": 0.0,
+ "docstatus": 0,
+ "doctype": "Purchase Invoice",
+ "due_date": "2021-04-30",
+ "from_date": null,
+ "grand_total": 511.68,
+ "group_same_items": 0,
+ "hold_comment": null,
+ "ignore_pricing_rule": 0,
+ "in_words": "GBP Five Hundred And Eleven and Sixty Eight Pence only.",
+ "inter_company_invoice_reference": null,
+ "is_internal_supplier": 0,
+ "is_opening": "No",
+ "is_paid": 0,
+ "is_return": 0,
+ "is_subcontracted": "No",
+ "items": [
+ {
+ "allow_zero_valuation_rate": 0,
+ "amount": 426.4,
+ "asset_category": null,
+ "asset_location": null,
+ "base_amount": 426.4,
+ "base_net_amount": 426.4,
+ "base_net_rate": 5.33,
+ "base_price_list_rate": 5.33,
+ "base_rate": 5.33,
+ "base_rate_with_margin": 0.0,
+ "batch_no": null,
+ "bom": null,
+ "brand": null,
+ "conversion_factor": 0.0,
+ "cost_center": "Main - _T",
+ "deferred_expense_account": null,
+ "description": "",
+ "discount_amount": 0.0,
+ "discount_percentage": 0.0,
+ "enable_deferred_expense": 0,
+ "expense_account": "Cost of Goods Sold - _T",
+ "from_warehouse": null,
+ "image": null,
+ "include_exploded_items": 0,
+ "is_fixed_asset": 0,
+ "is_free_item": 0,
+ "item_code": null,
+ "item_group": null,
+ "item_name": "Widget Fluid 1Litre",
+ "item_tax_amount": 0.0,
+ "item_tax_rate": "{\"VAT on Purchases - _T\": 20.0}",
+ "item_tax_template": "Purchase - Standard VAT",
+ "landed_cost_voucher_amount": 0.0,
+ "manufacturer": null,
+ "manufacturer_part_no": null,
+ "margin_rate_or_amount": 0.0,
+ "margin_type": "",
+ "net_amount": 426.4,
+ "net_rate": 5.33,
+ "page_break": 0,
+ "parent": null,
+ "parentfield": "items",
+ "parenttype": "Purchase Invoice",
+ "po_detail": null,
+ "pr_detail": null,
+ "price_list_rate": 5.33,
+ "pricing_rules": null,
+ "project": null,
+ "purchase_invoice_item": null,
+ "purchase_order": null,
+ "purchase_receipt": null,
+ "qty": 80.0,
+ "quality_inspection": null,
+ "rate": 5.33,
+ "rate_with_margin": 0.0,
+ "received_qty": 0.0,
+ "rejected_qty": 0.0,
+ "rejected_serial_no": null,
+ "rejected_warehouse": null,
+ "rm_supp_cost": 0.0,
+ "sales_invoice_item": null,
+ "serial_no": null,
+ "service_end_date": null,
+ "service_start_date": null,
+ "service_stop_date": null,
+ "stock_qty": 0.0,
+ "stock_uom": "Nos",
+ "stock_uom_rate": 0.0,
+ "total_weight": 0.0,
+ "uom": "Nos",
+ "valuation_rate": 0.0,
+ "warehouse": null,
+ "weight_per_unit": 0.0,
+ "weight_uom": null
+ }
+ ],
+ "language": "en",
+ "letter_head": null,
+ "mode_of_payment": null,
+ "modified": "2021-04-03 03:33:09.180453",
+ "name": null,
+ "naming_series": "ACC-PINV-.YYYY.-",
+ "net_total": 426.4,
+ "on_hold": 0,
+ "other_charges_calculation": "\n\t
\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tItem \n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tTaxable Amount \n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tVAT on Purchases \n\t\t\t\t\t\n\t\t\t\t\n\t\t\t \n\t\t \n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tWidget Fluid 1Litre \n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\u00a3 426.40\n\t\t\t\t\t\t\n\t\t\t\t\t \n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t(20.0%)\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\u00a3 85.28\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t \n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t \n\t\t\t\n\t\t \n\t
\n
",
+ "outstanding_amount": 511.68,
+ "paid_amount": 0.0,
+ "parent": null,
+ "parentfield": null,
+ "parenttype": null,
+ "party_account_currency": "GBP",
+ "payment_schedule": [],
+ "payment_terms_template": null,
+ "plc_conversion_rate": 1.0,
+ "posting_date": null,
+ "posting_time": "16:59:56.789522",
+ "price_list_currency": "GBP",
+ "pricing_rules": [],
+ "project": null,
+ "rejected_warehouse": null,
+ "release_date": null,
+ "remarks": "No Remarks",
+ "represents_company": null,
+ "return_against": null,
+ "rounded_total": 511.68,
+ "rounding_adjustment": 0.0,
+ "scan_barcode": null,
+ "select_print_heading": null,
+ "set_from_warehouse": null,
+ "set_posting_time": 0,
+ "set_warehouse": null,
+ "shipping_address": null,
+ "shipping_address_display": "",
+ "shipping_rule": null,
+ "status": "Unpaid",
+ "supplied_items": [],
+ "supplier": "Raw Materials Inc",
+ "supplier_address": null,
+ "supplier_name": "Raw Materials Inc",
+ "supplier_warehouse": "Stores - _T",
+ "tax_category": "Other Supplier",
+ "tax_id": null,
+ "tax_withholding_category": null,
+ "taxes": [
+ {
+ "account_head": "VAT on Purchases - _T",
+ "add_deduct_tax": "Add",
+ "base_tax_amount": 85.28,
+ "base_tax_amount_after_discount_amount": 85.28,
+ "base_total": 511.68,
+ "category": "Total",
+ "charge_type": "On Net Total",
+ "cost_center": "Main - _T",
+ "description": "VAT on Purchases",
+ "included_in_print_rate": 0,
+ "item_wise_tax_detail": "{\"Widget Fluid 1Litre\":[20.0,85.28]}",
+ "parent": null,
+ "parentfield": "taxes",
+ "parenttype": "Purchase Invoice",
+ "rate": 0.0,
+ "row_id": null,
+ "tax_amount": 85.28,
+ "tax_amount_after_discount_amount": 85.28,
+ "total": 511.68
+ }
+ ],
+ "taxes_and_charges": null,
+ "taxes_and_charges_added": 85.28,
+ "taxes_and_charges_deducted": 0.0,
+ "tc_name": null,
+ "terms": null,
+ "title": "Raw Materials Inc",
+ "to_date": null,
+ "total": 426.4,
+ "total_advance": 0.0,
+ "total_net_weight": 0.0,
+ "total_qty": 80.0,
+ "total_taxes_and_charges": 85.28,
+ "unrealized_profit_loss_account": null,
+ "update_stock": 0,
+ "write_off_account": null,
+ "write_off_amount": 0.0,
+ "write_off_cost_center": null
+ },{
+ "account_for_change_amount": null,
+ "additional_discount_percentage": 0.0,
+ "address_display": null,
+ "advances": [],
+ "against_income_account": "Sales - _T",
+ "allocate_advances_automatically": 0,
+ "amended_from": null,
+ "apply_discount_on": "Grand Total",
+ "auto_repeat": null,
+ "base_change_amount": 0.0,
+ "base_discount_amount": 0.0,
+ "base_grand_total": 868.25,
+ "base_in_words": "GBP Eight Hundred And Sixty Eight and Twenty Five Pence only.",
+ "base_net_total": 825.0,
+ "base_paid_amount": 0.0,
+ "base_rounded_total": 868.25,
+ "base_rounding_adjustment": 0.0,
+ "base_total": 825.0,
+ "base_total_taxes_and_charges": 43.25,
+ "base_write_off_amount": 0.0,
+ "c_form_applicable": "No",
+ "c_form_no": null,
+ "campaign": null,
+ "cash_bank_account": null,
+ "change_amount": 0.0,
+ "commission_rate": 0.0,
+ "company": "_T",
+ "company_address": null,
+ "company_address_display": null,
+ "company_tax_id": null,
+ "contact_display": null,
+ "contact_email": null,
+ "contact_mobile": null,
+ "contact_person": null,
+ "conversion_rate": 1.0,
+ "cost_center": null,
+ "currency": "GBP",
+ "customer": "ABC Tyres",
+ "customer_address": null,
+ "customer_group": "All Customer Groups",
+ "customer_name": "ABC Tyres",
+ "debit_to": "Debtors - _T",
+ "discount_amount": 0.0,
+ "docstatus": 0,
+ "doctype": "Sales Invoice",
+ "due_date": "2021-03-31",
+ "from_date": null,
+ "grand_total": 868.25,
+ "group_same_items": 0,
+ "ignore_pricing_rule": 0,
+ "in_words": "GBP Eight Hundred And Sixty Eight and Twenty Five Pence only.",
+ "inter_company_invoice_reference": null,
+ "is_consolidated": 0,
+ "is_discounted": 0,
+ "is_internal_customer": 0,
+ "is_opening": "No",
+ "is_pos": 0,
+ "is_return": 0,
+ "items": [
+ {
+ "actual_batch_qty": 0.0,
+ "actual_qty": 0.0,
+ "allow_zero_valuation_rate": 0,
+ "amount": 200.0,
+ "asset": null,
+ "barcode": null,
+ "base_amount": 200.0,
+ "base_net_amount": 200.0,
+ "base_net_rate": 50.0,
+ "base_price_list_rate": 0.0,
+ "base_rate": 50.0,
+ "base_rate_with_margin": 0.0,
+ "batch_no": null,
+ "brand": null,
+ "conversion_factor": 1.0,
+ "cost_center": "Main - _T",
+ "customer_item_code": null,
+ "deferred_revenue_account": null,
+ "delivered_by_supplier": 0,
+ "delivered_qty": 0.0,
+ "delivery_note": null,
+ "description": "",
+ "discount_amount": 0.0,
+ "discount_percentage": 0.0,
+ "dn_detail": null,
+ "enable_deferred_revenue": 0,
+ "expense_account": null,
+ "finance_book": null,
+ "image": null,
+ "income_account": "Sales - _T",
+ "incoming_rate": 0.0,
+ "is_fixed_asset": 0,
+ "is_free_item": 0,
+ "item_code": null,
+ "item_group": null,
+ "item_name": "Dunlop tyres",
+ "item_tax_rate": "{\"VAT on Sales - _T\": 20.0}",
+ "item_tax_template": "Sale - Standard VAT",
+ "margin_rate_or_amount": 0.0,
+ "margin_type": "",
+ "net_amount": 200.0,
+ "net_rate": 50.0,
+ "page_break": 0,
+ "parent": null,
+ "parentfield": "items",
+ "parenttype": "Sales Invoice",
+ "price_list_rate": 0.0,
+ "pricing_rules": null,
+ "project": null,
+ "qty": 4.0,
+ "quality_inspection": null,
+ "rate": 50.0,
+ "rate_with_margin": 0.0,
+ "sales_invoice_item": null,
+ "sales_order": null,
+ "serial_no": null,
+ "service_end_date": null,
+ "service_start_date": null,
+ "service_stop_date": null,
+ "so_detail": null,
+ "stock_qty": 4.0,
+ "stock_uom": "Nos",
+ "stock_uom_rate": 50.0,
+ "target_warehouse": null,
+ "total_weight": 0.0,
+ "uom": "Nos",
+ "warehouse": null,
+ "weight_per_unit": 0.0,
+ "weight_uom": null
+ },
+ {
+ "actual_batch_qty": 0.0,
+ "actual_qty": 0.0,
+ "allow_zero_valuation_rate": 0,
+ "amount": 65.0,
+ "asset": null,
+ "barcode": null,
+ "base_amount": 65.0,
+ "base_net_amount": 65.0,
+ "base_net_rate": 65.0,
+ "base_price_list_rate": 0.0,
+ "base_rate": 65.0,
+ "base_rate_with_margin": 0.0,
+ "batch_no": null,
+ "brand": null,
+ "conversion_factor": 1.0,
+ "cost_center": "Main - _T",
+ "customer_item_code": null,
+ "deferred_revenue_account": null,
+ "delivered_by_supplier": 0,
+ "delivered_qty": 0.0,
+ "delivery_note": null,
+ "description": "",
+ "discount_amount": 0.0,
+ "discount_percentage": 0.0,
+ "dn_detail": null,
+ "enable_deferred_revenue": 0,
+ "expense_account": null,
+ "finance_book": null,
+ "image": null,
+ "income_account": "Sales - _T",
+ "incoming_rate": 0.0,
+ "is_fixed_asset": 0,
+ "is_free_item": 0,
+ "item_code": "",
+ "item_group": null,
+ "item_name": "Continental tyres",
+ "item_tax_rate": "{\"VAT on Sales - _T\": 5.0}",
+ "item_tax_template": "Sale - Reduced VAT",
+ "margin_rate_or_amount": 0.0,
+ "margin_type": "",
+ "net_amount": 65.0,
+ "net_rate": 65.0,
+ "page_break": 0,
+ "parent": null,
+ "parentfield": "items",
+ "parenttype": "Sales Invoice",
+ "price_list_rate": 0.0,
+ "pricing_rules": null,
+ "project": null,
+ "qty": 1.0,
+ "quality_inspection": null,
+ "rate": 65.0,
+ "rate_with_margin": 0.0,
+ "sales_invoice_item": null,
+ "sales_order": null,
+ "serial_no": null,
+ "service_end_date": null,
+ "service_start_date": null,
+ "service_stop_date": null,
+ "so_detail": null,
+ "stock_qty": 1.0,
+ "stock_uom": null,
+ "stock_uom_rate": 65.0,
+ "target_warehouse": null,
+ "total_weight": 0.0,
+ "uom": "Nos",
+ "warehouse": null,
+ "weight_per_unit": 0.0,
+ "weight_uom": null
+ },
+ {
+ "actual_batch_qty": 0.0,
+ "actual_qty": 0.0,
+ "allow_zero_valuation_rate": 0,
+ "amount": 560.0,
+ "asset": null,
+ "barcode": null,
+ "base_amount": 560.0,
+ "base_net_amount": 560.0,
+ "base_net_rate": 70.0,
+ "base_price_list_rate": 0.0,
+ "base_rate": 70.0,
+ "base_rate_with_margin": 0.0,
+ "batch_no": null,
+ "brand": null,
+ "conversion_factor": 1.0,
+ "cost_center": "Main - _T",
+ "customer_item_code": null,
+ "deferred_revenue_account": null,
+ "delivered_by_supplier": 0,
+ "delivered_qty": 0.0,
+ "delivery_note": null,
+ "description": "",
+ "discount_amount": 0.0,
+ "discount_percentage": 0.0,
+ "dn_detail": null,
+ "enable_deferred_revenue": 0,
+ "expense_account": null,
+ "finance_book": null,
+ "image": null,
+ "income_account": "Sales - _T",
+ "incoming_rate": 0.0,
+ "is_fixed_asset": 0,
+ "is_free_item": 0,
+ "item_code": null,
+ "item_group": null,
+ "item_name": "Toyo tyres",
+ "item_tax_rate": "{\"VAT on Sales - _T\": 0.0}",
+ "item_tax_template": "Sale - Zero VAT",
+ "margin_rate_or_amount": 0.0,
+ "margin_type": "",
+ "net_amount": 560.0,
+ "net_rate": 70.0,
+ "page_break": 0,
+ "parent": null,
+ "parentfield": "items",
+ "parenttype": "Sales Invoice",
+ "price_list_rate": 0.0,
+ "pricing_rules": null,
+ "project": null,
+ "qty": 8.0,
+ "quality_inspection": null,
+ "rate": 70.0,
+ "rate_with_margin": 0.0,
+ "sales_invoice_item": null,
+ "sales_order": null,
+ "serial_no": null,
+ "service_end_date": null,
+ "service_start_date": null,
+ "service_stop_date": null,
+ "so_detail": null,
+ "stock_qty": 8.0,
+ "stock_uom": null,
+ "stock_uom_rate": 70.0,
+ "target_warehouse": null,
+ "total_weight": 0.0,
+ "uom": "Nos",
+ "warehouse": null,
+ "weight_per_unit": 0.0,
+ "weight_uom": null
+ }
+ ],
+ "language": "en",
+ "letter_head": null,
+ "loyalty_amount": 0.0,
+ "loyalty_points": 0,
+ "loyalty_program": null,
+ "loyalty_redemption_account": null,
+ "loyalty_redemption_cost_center": null,
+ "modified": "2021-02-16 05:18:59.755144",
+ "name": null,
+ "naming_series": "ACC-SINV-.YYYY.-",
+ "net_total": 825.0,
+ "other_charges_calculation": "\n\t
\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tItem \n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tTaxable Amount \n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tVAT on Sales \n\t\t\t\t\t\n\t\t\t\t\n\t\t\t \n\t\t \n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tDunlop tyres \n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\u00a3 200.00\n\t\t\t\t\t\t\n\t\t\t\t\t \n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t(20.0%)\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\u00a3 40.00\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t \n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t \n\t\t\t\n\t\t\t\t\n\t\t\t\t\tContinental tyres \n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\u00a3 65.00\n\t\t\t\t\t\t\n\t\t\t\t\t \n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t(5.0%)\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\u00a3 3.25\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t \n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t \n\t\t\t\n\t\t\t\t\n\t\t\t\t\tToyo tyres \n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\u00a3 560.00\n\t\t\t\t\t\t\n\t\t\t\t\t \n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t(0.0%)\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\u00a3 0.00\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t \n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t \n\t\t\t\n\t\t \n\t
\n
",
+ "outstanding_amount": 868.25,
+ "packed_items": [],
+ "paid_amount": 0.0,
+ "parent": null,
+ "parentfield": null,
+ "parenttype": null,
+ "party_account_currency": "GBP",
+ "payment_schedule": [],
+ "payment_terms_template": null,
+ "payments": [],
+ "plc_conversion_rate": 1.0,
+ "po_date": null,
+ "po_no": "",
+ "pos_profile": null,
+ "posting_date": null,
+ "posting_time": "5:19:02.994077",
+ "price_list_currency": "GBP",
+ "pricing_rules": [],
+ "project": null,
+ "redeem_loyalty_points": 0,
+ "remarks": "No Remarks",
+ "represents_company": "",
+ "return_against": null,
+ "rounded_total": 868.25,
+ "rounding_adjustment": 0.0,
+ "sales_partner": null,
+ "sales_team": [],
+ "scan_barcode": null,
+ "select_print_heading": null,
+ "selling_price_list": "Standard Selling",
+ "set_posting_time": 0,
+ "set_target_warehouse": null,
+ "set_warehouse": null,
+ "shipping_address": null,
+ "shipping_address_name": "",
+ "shipping_rule": null,
+ "source": null,
+ "status": "Overdue",
+ "tax_category": "",
+ "tax_id": null,
+ "taxes": [
+ {
+ "account_head": "VAT on Sales - _T",
+ "base_tax_amount": 43.25,
+ "base_tax_amount_after_discount_amount": 43.25,
+ "base_total": 868.25,
+ "charge_type": "On Net Total",
+ "cost_center": "Main - _T",
+ "description": "VAT on Sales",
+ "included_in_print_rate": 0,
+ "item_wise_tax_detail": "{\"Dunlop tyres\":[20.0,40.0],\"Continental tyres\":[5.0,3.25],\"Toyo tyres\":[0.0,0.0]}",
+ "parent": null,
+ "parentfield": "taxes",
+ "parenttype": "Sales Invoice",
+ "rate": 0.0,
+ "row_id": null,
+ "tax_amount": 43.25,
+ "tax_amount_after_discount_amount": 43.25,
+ "total": 868.25
+ }
+ ],
+ "taxes_and_charges": null,
+ "tc_name": null,
+ "terms": null,
+ "territory": "All Territories",
+ "timesheets": [],
+ "title": "ABC Tyres",
+ "to_date": null,
+ "total": 825.0,
+ "total_advance": 0.0,
+ "total_billing_amount": 0.0,
+ "total_commission": 0.0,
+ "total_net_weight": 0.0,
+ "total_qty": 13.0,
+ "total_taxes_and_charges": 43.25,
+ "unrealized_profit_loss_account": null,
+ "update_billed_amount_in_sales_order": 0,
+ "update_stock": 0,
+ "write_off_account": null,
+ "write_off_amount": 0.0,
+ "write_off_cost_center": null,
+ "write_off_outstanding_amount_automatically": 0
+ }
+]
\ No newline at end of file
diff --git a/erpnext/accounts/report/tax_detail/test_tax_detail.py b/erpnext/accounts/report/tax_detail/test_tax_detail.py
index dfd8d9e121..c9b8e209e4 100644
--- a/erpnext/accounts/report/tax_detail/test_tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/test_tax_detail.py
@@ -1,12 +1,98 @@
from __future__ import unicode_literals
-import frappe, unittest, datetime
-from frappe.utils import getdate
-from .tax_detail import execute, filter_match
+import frappe, unittest, datetime, json, os
+from frappe.utils import getdate, add_to_date, get_first_day, get_last_day
+from .tax_detail import filter_match, save_custom_report
class TestTaxDetail(unittest.TestCase):
- def setup(self):
- pass
+ def load_testdocs(self):
+ datapath, _ = os.path.splitext(os.path.realpath(__file__))
+ with open(datapath + '.json', 'r') as fp:
+ self.docs = json.load(fp)
+
+ def load_defcols(self):
+ custom_report = frappe.get_doc('Report', 'Tax Detail')
+ self.default_columns, _ = custom_report.run_query_report(
+ filters={
+ 'from_date': '2021-03-01',
+ 'to_date': '2021-03-31',
+ 'company': '_T',
+ 'mode': 'run',
+ 'report_name': 'Tax Detail'
+ }, user=frappe.session.user)
+
+ def setUp(self):
+ "Add Transactions in 01-03-2021 - 31-03-2021"
+ self.load_testdocs()
+ now = getdate()
+ self.from_date = get_first_day(now)
+ self.to_date = get_last_day(now)
+
+ for doc in self.docs:
+ try:
+ db_doc = frappe.get_doc(doc)
+ if 'Invoice' in db_doc.doctype:
+ db_doc.due_date = add_to_date(now, days=1)
+ db_doc.insert()
+ # Create GL Entries:
+ db_doc.submit()
+ else:
+ db_doc.insert()
+ except frappe.exceptions.DuplicateEntryError as e:
+ pass
+ #print(f'Duplicate Entry: {e}')
+ except:
+ print(f'\nError importing {doc["doctype"]}: {doc["name"]}')
+ raise
+
+ self.load_defcols()
+
+ def tearDown(self):
+ "Remove the Company and all data"
+ from erpnext.setup.doctype.company.delete_company_transactions import delete_company_transactions
+ for co in filter(lambda doc: doc['doctype'] == 'Company', self.docs):
+ delete_company_transactions(co['name'])
+ db_co = frappe.get_doc('Company', co['name'])
+ db_co.delete()
+
+ def test_report(self):
+ report_name = save_custom_report(
+ 'Tax Detail',
+ '_Test Tax Detail',
+ json.dumps({
+ 'columns': self.default_columns,
+ 'sections': {
+ 'Box1':{'Filter0':{'type':'filter','filters':{'4':'VAT on Sales'}}},
+ 'Box2':{'Filter0':{'type':'filter','filters':{'4':'Acquisition'}}},
+ 'Box3':{'Box1':{'type':'section'},'Box2':{'type':'section'}},
+ 'Box4':{'Filter0':{'type':'filter','filters':{'4':'VAT on Purchases'}}},
+ 'Box5':{'Box3':{'type':'section'},'Box4':{'type':'section'}},
+ 'Box6':{'Filter0':{'type':'filter','filters':{'3':'!=Tax','4':'Sales'}}},
+ 'Box7':{'Filter0':{'type':'filter','filters':{'2':'Expense','3':'!=Tax'}}},
+ 'Box8':{'Filter0':{'type':'filter','filters':{'3':'!=Tax','4':'Sales','12':'EU'}}},
+ 'Box9':{'Filter0':{'type':'filter','filters':{'2':'Expense','3':'!=Tax','12':'EU'}}}
+ },
+ 'show_detail': 1
+ }))
+ data = frappe.desk.query_report.run(report_name,
+ filters={
+ 'from_date': self.from_date,
+ 'to_date': self.to_date,
+ 'company': '_T',
+ 'mode': 'run',
+ 'report_name': report_name
+ }, user=frappe.session.user)
+
+ self.assertListEqual(data.get('columns'), self.default_columns)
+ expected = (('Box1', 43.25), ('Box2', 0.0), ('Box3', 43.25), ('Box4', -85.28), ('Box5', -42.03),
+ ('Box6', 825.0), ('Box7', -426.40), ('Box8', 0.0), ('Box9', 0.0))
+ exrow = iter(expected)
+ for row in data.get('result'):
+ if row.get('voucher_no') and not row.get('posting_date'):
+ label, value = next(exrow)
+ self.assertDictEqual(row, {'voucher_no': label, 'amount': value})
+ self.assertListEqual(data.get('report_summary'),
+ [{'label': label, 'datatype': 'Currency', 'value': value} for label, value in expected])
def test_filter_match(self):
# None - treated as -inf number except range
From 7555f5f6130c20bfb9d608810a0215752dd7914c Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Thu, 8 Apr 2021 23:54:34 +0000
Subject: [PATCH 122/149] fix: add to workspace and fix lint
---
erpnext/accounts/report/tax_detail/tax_detail.js | 12 ++----------
.../accounts/workspace/accounting/accounting.json | 10 ++++++++++
2 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.js b/erpnext/accounts/report/tax_detail/tax_detail.js
index 0c0397ab04..098096ce0b 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.js
+++ b/erpnext/accounts/report/tax_detail/tax_detail.js
@@ -376,16 +376,8 @@ erpnext.TaxDetail = class TaxDetail {
this.controls = controls;
}
show_help() {
- const help = __(`Help: Your custom report is built from General Ledger Entries within the date range.
- You can add multiple sections to the report using the New Section button.
- Each component added to a section adds a subset of the data into the specified section.
- Beware of duplicated data rows.
- The Filtered Row component type saves the datatable column filters to specify the added data.
- The Section component type refers to the data in a previously defined section, but it cannot refer to its parent section.
- The Amount column is summed to give the section subtotal.
- Use the Show Detail box to see the data rows included in each section in the final report.
- Once finished, hit Save & Run. Report contributed by`);
- this.qr.$report_footer.append(``);
+ const help = __('Your custom report is built from General Ledger Entries within the date range. You can add multiple sections to the report using the New Section button. Each component added to a section adds a subset of the data into the specified section. Beware of duplicated data rows. The Filtered Row component type saves the datatable column filters to specify the added data. The Section component type refers to the data in a previously defined section, but it cannot refer to its parent section. The Amount column is summed to give the section subtotal. Use the Show Detail box to see the data rows included in each section in the final report. Once finished, hit Save & Run. Report contributed by');
+ this.qr.$report_footer.append('`);
}
}
diff --git a/erpnext/accounts/workspace/accounting/accounting.json b/erpnext/accounts/workspace/accounting/accounting.json
index df68318052..cbfba7e31c 100644
--- a/erpnext/accounts/workspace/accounting/accounting.json
+++ b/erpnext/accounts/workspace/accounting/accounting.json
@@ -434,6 +434,16 @@
"onboard": 0,
"type": "Link"
},
+ {
+ "dependencies": "GL Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Tax Detail",
+ "link_to": "Tax Detail",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
{
"dependencies": "GL Entry",
"hidden": 0,
From 391dc45964913d79c3baec434a6692a370d570d3 Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Fri, 9 Apr 2021 00:23:08 +0000
Subject: [PATCH 123/149] chore: fix sider
---
.../accounts/report/tax_detail/tax_detail.py | 59 ++++++++++++-------
.../report/tax_detail/test_tax_detail.py | 12 ++--
2 files changed, 45 insertions(+), 26 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py
index fb7791f7e1..aafcf1297e 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/tax_detail.py
@@ -3,7 +3,8 @@
# Contributed by Case Solved and sponsored by Nulight Studios
from __future__ import unicode_literals
-import frappe, json
+import frappe
+import json
from frappe import _
# NOTE: Payroll is implemented using Journal Entries which are included as GL Entries
@@ -86,26 +87,35 @@ def run_report(report_name, data):
except KeyError:
frappe.throw(_("A report component can only refer to an earlier section: ") + section_name)
- if show_detail: new_data += report[section_name]['rows']
- new_data += [ {'voucher_no': section_name, 'amount': report[section_name]['subtotal']} ]
- summary += [ {'label': section_name, 'datatype': 'Currency', 'value': report[section_name]['subtotal']} ]
- if show_detail: new_data += [ {} ]
+ if show_detail:
+ new_data += report[section_name]['rows']
+ new_data += [{'voucher_no': section_name, 'amount': report[section_name]['subtotal']}]
+ summary += [{'label': section_name, 'datatype': 'Currency', 'value': report[section_name]['subtotal']}]
+ if show_detail:
+ new_data += [{}]
return new_data or data, summary or None
def filter_match(value, string):
"Approximation to datatable filters"
import datetime
- if string == '': return True
- if value is None: value = -999999999999999
- elif isinstance(value, datetime.date): return True
+ if string == '':
+ return True
+ if value is None:
+ value = -999999999999999
+ elif isinstance(value, datetime.date):
+ return True
if isinstance(value, str):
value = value.lower()
string = string.lower()
- if string[0] == '<': return True if string[1:].strip() else False
- elif string[0] == '>': return False if string[1:].strip() else True
- elif string[0] == '=': return string[1:] in value if string[1:] else False
- elif string[0:2] == '!=': return string[2:] not in value
+ if string[0] == '<':
+ return True if string[1:].strip() else False
+ elif string[0] == '>':
+ return False if string[1:].strip() else True
+ elif string[0] == '=':
+ return string[1:] in value if string[1:] else False
+ elif string[0:2] == '!=':
+ return string[2:] not in value
elif len(string.split(':')) == 2:
pre, post = string.split(':')
return (True if not pre.strip() and post.strip() in value else False)
@@ -114,7 +124,8 @@ def filter_match(value, string):
else:
if string[0] in ['<', '>', '=']:
operator = string[0]
- if operator == '=': operator = '=='
+ if operator == '=':
+ operator = '=='
string = string[1:].strip()
elif string[0:2] == '!=':
operator = '!='
@@ -132,12 +143,16 @@ def filter_match(value, string):
num = float(string) if string.strip() else 0
return eval(f'{value} {operator} {num}')
except ValueError:
- if operator == '<': return True
+ if operator == '<':
+ return True
return False
-abbrev = lambda dt: ''.join(l[0].lower() for l in dt.split(' ')) + '.'
-doclist = lambda dt, dfs: [abbrev(dt) + f for f in dfs]
+def abbrev(dt):
+ return ''.join(l[0].lower() for l in dt.split(' ')) + '.'
+
+def doclist(dt, dfs):
+ return [abbrev(dt) + f for f in dfs]
def as_split(fields):
for field in fields:
@@ -165,7 +180,8 @@ def get_columns(fieldlist):
for doctypes, docfields in fieldlist.items():
fieldmap = {name: new_name for name, new_name in as_split(docfields)}
for doctype in doctypes:
- if isinstance(doctype, int): break
+ if isinstance(doctype, int):
+ break
meta = frappe.get_meta(doctype)
# get column field metadata from the db
fieldmeta = {}
@@ -203,8 +219,10 @@ def modify_report_data(data):
import json
new_data = []
for line in data:
- if line.debit: line.amount = -line.debit
- else: line.amount = line.credit
+ if line.debit:
+ line.amount = -line.debit
+ else:
+ line.amount = line.credit
# Remove Invoice GL Tax Entries and generate Tax entries from the invoice lines
if "Invoice" in line.voucher_type:
if line.account_type != "Tax":
@@ -226,7 +244,8 @@ def modify_report_data(data):
new_data += [line]
return new_data
-####### JS client utilities
+
+# JS client utilities
custom_report_dict = {
'ref_doctype': 'GL Entry',
diff --git a/erpnext/accounts/report/tax_detail/test_tax_detail.py b/erpnext/accounts/report/tax_detail/test_tax_detail.py
index c9b8e209e4..614ef8d234 100644
--- a/erpnext/accounts/report/tax_detail/test_tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/test_tax_detail.py
@@ -1,6 +1,10 @@
from __future__ import unicode_literals
-import frappe, unittest, datetime, json, os
+import frappe
+import unittest
+import datetime
+import json
+import os
from frappe.utils import getdate, add_to_date, get_first_day, get_last_day
from .tax_detail import filter_match, save_custom_report
@@ -38,12 +42,8 @@ class TestTaxDetail(unittest.TestCase):
db_doc.submit()
else:
db_doc.insert()
- except frappe.exceptions.DuplicateEntryError as e:
+ except frappe.exceptions.DuplicateEntryError:
pass
- #print(f'Duplicate Entry: {e}')
- except:
- print(f'\nError importing {doc["doctype"]}: {doc["name"]}')
- raise
self.load_defcols()
From 06e31e5d7dd4d453f65b728743a62d782b4a133b Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Sat, 10 Apr 2021 00:31:16 +0000
Subject: [PATCH 124/149] fix: Test data for empty db
---
.../report/tax_detail/test_tax_detail.json | 116 ++++++++++++++++--
.../report/tax_detail/test_tax_detail.py | 50 ++++----
2 files changed, 132 insertions(+), 34 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/test_tax_detail.json b/erpnext/accounts/report/tax_detail/test_tax_detail.json
index 17248d0320..977920a231 100644
--- a/erpnext/accounts/report/tax_detail/test_tax_detail.json
+++ b/erpnext/accounts/report/tax_detail/test_tax_detail.json
@@ -6,6 +6,98 @@
"default_currency": "GBP",
"doctype": "Company",
"name": "_T"
+ },{
+ "account_manager": null,
+ "accounts": [],
+ "companies": [],
+ "credit_limits": [],
+ "customer_details": null,
+ "customer_group": "All Customer Groups",
+ "customer_name": "_Test Customer",
+ "customer_pos_id": null,
+ "customer_primary_address": null,
+ "customer_primary_contact": null,
+ "customer_type": "Company",
+ "default_bank_account": null,
+ "default_commission_rate": 0.0,
+ "default_currency": null,
+ "default_price_list": null,
+ "default_sales_partner": null,
+ "disabled": 0,
+ "dn_required": 0,
+ "docstatus": 0,
+ "doctype": "Customer",
+ "email_id": null,
+ "gender": null,
+ "image": null,
+ "industry": null,
+ "is_frozen": 0,
+ "is_internal_customer": 0,
+ "language": "en",
+ "lead_name": null,
+ "loyalty_program": null,
+ "loyalty_program_tier": null,
+ "market_segment": null,
+ "mobile_no": null,
+ "modified": "2021-02-15 05:18:03.624724",
+ "name": "_Test Customer",
+ "naming_series": "CUST-.YYYY.-",
+ "pan": null,
+ "parent": null,
+ "parentfield": null,
+ "parenttype": null,
+ "payment_terms": null,
+ "primary_address": null,
+ "represents_company": "",
+ "sales_team": [],
+ "salutation": null,
+ "so_required": 0,
+ "tax_category": null,
+ "tax_id": null,
+ "tax_withholding_category": null,
+ "territory": "All Territories",
+ "website": null
+ },{
+ "accounts": [],
+ "allow_purchase_invoice_creation_without_purchase_order": 0,
+ "allow_purchase_invoice_creation_without_purchase_receipt": 0,
+ "companies": [],
+ "country": "United Kingdom",
+ "default_bank_account": null,
+ "default_currency": null,
+ "default_price_list": null,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Supplier",
+ "hold_type": "",
+ "image": null,
+ "is_frozen": 0,
+ "is_internal_supplier": 0,
+ "is_transporter": 0,
+ "language": "en",
+ "modified": "2021-03-31 16:47:10.109316",
+ "name": "_Test Supplier",
+ "naming_series": "SUP-.YYYY.-",
+ "on_hold": 0,
+ "pan": null,
+ "parent": null,
+ "parentfield": null,
+ "parenttype": null,
+ "payment_terms": null,
+ "prevent_pos": 0,
+ "prevent_rfqs": 0,
+ "release_date": null,
+ "represents_company": null,
+ "supplier_details": null,
+ "supplier_group": "Raw Material",
+ "supplier_name": "_Test Supplier",
+ "supplier_type": "Company",
+ "tax_category": null,
+ "tax_id": null,
+ "tax_withholding_category": null,
+ "warn_pos": 0,
+ "warn_rfqs": 0,
+ "website": null
},{
"account_currency": "GBP",
"account_name": "Debtors",
@@ -251,7 +343,7 @@
"item_name": "Widget Fluid 1Litre",
"item_tax_amount": 0.0,
"item_tax_rate": "{\"VAT on Purchases - _T\": 20.0}",
- "item_tax_template": "Purchase - Standard VAT",
+ "item_tax_template": null,
"landed_cost_voucher_amount": 0.0,
"manufacturer": null,
"manufacturer_part_no": null,
@@ -336,11 +428,11 @@
"shipping_rule": null,
"status": "Unpaid",
"supplied_items": [],
- "supplier": "Raw Materials Inc",
+ "supplier": "_Test Supplier",
"supplier_address": null,
- "supplier_name": "Raw Materials Inc",
+ "supplier_name": "_Test Supplier",
"supplier_warehouse": "Stores - _T",
- "tax_category": "Other Supplier",
+ "tax_category": null,
"tax_id": null,
"tax_withholding_category": null,
"taxes": [
@@ -371,7 +463,7 @@
"taxes_and_charges_deducted": 0.0,
"tc_name": null,
"terms": null,
- "title": "Raw Materials Inc",
+ "title": "_Purchase Invoice",
"to_date": null,
"total": 426.4,
"total_advance": 0.0,
@@ -421,10 +513,10 @@
"conversion_rate": 1.0,
"cost_center": null,
"currency": "GBP",
- "customer": "ABC Tyres",
+ "customer": "_Test Customer",
"customer_address": null,
"customer_group": "All Customer Groups",
- "customer_name": "ABC Tyres",
+ "customer_name": "_Test Customer",
"debit_to": "Debtors - _T",
"discount_amount": 0.0,
"docstatus": 0,
@@ -481,7 +573,7 @@
"item_group": null,
"item_name": "Dunlop tyres",
"item_tax_rate": "{\"VAT on Sales - _T\": 20.0}",
- "item_tax_template": "Sale - Standard VAT",
+ "item_tax_template": null,
"margin_rate_or_amount": 0.0,
"margin_type": "",
"net_amount": 200.0,
@@ -552,7 +644,7 @@
"item_group": null,
"item_name": "Continental tyres",
"item_tax_rate": "{\"VAT on Sales - _T\": 5.0}",
- "item_tax_template": "Sale - Reduced VAT",
+ "item_tax_template": null,
"margin_rate_or_amount": 0.0,
"margin_type": "",
"net_amount": 65.0,
@@ -623,7 +715,7 @@
"item_group": null,
"item_name": "Toyo tyres",
"item_tax_rate": "{\"VAT on Sales - _T\": 0.0}",
- "item_tax_template": "Sale - Zero VAT",
+ "item_tax_template": null,
"margin_rate_or_amount": 0.0,
"margin_type": "",
"net_amount": 560.0,
@@ -735,7 +827,7 @@
"terms": null,
"territory": "All Territories",
"timesheets": [],
- "title": "ABC Tyres",
+ "title": "_Sales Invoice",
"to_date": null,
"total": 825.0,
"total_advance": 0.0,
@@ -752,4 +844,4 @@
"write_off_cost_center": null,
"write_off_outstanding_amount_automatically": 0
}
-]
\ No newline at end of file
+]
diff --git a/erpnext/accounts/report/tax_detail/test_tax_detail.py b/erpnext/accounts/report/tax_detail/test_tax_detail.py
index 614ef8d234..21732b9dfd 100644
--- a/erpnext/accounts/report/tax_detail/test_tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/test_tax_detail.py
@@ -5,34 +5,27 @@ import unittest
import datetime
import json
import os
-from frappe.utils import getdate, add_to_date, get_first_day, get_last_day
+from frappe.utils import getdate, add_to_date, get_first_day, get_last_day, get_year_start, get_year_ending
from .tax_detail import filter_match, save_custom_report
class TestTaxDetail(unittest.TestCase):
def load_testdocs(self):
datapath, _ = os.path.splitext(os.path.realpath(__file__))
with open(datapath + '.json', 'r') as fp:
- self.docs = json.load(fp)
+ docs = json.load(fp)
- def load_defcols(self):
- custom_report = frappe.get_doc('Report', 'Tax Detail')
- self.default_columns, _ = custom_report.run_query_report(
- filters={
- 'from_date': '2021-03-01',
- 'to_date': '2021-03-31',
- 'company': '_T',
- 'mode': 'run',
- 'report_name': 'Tax Detail'
- }, user=frappe.session.user)
-
- def setUp(self):
- "Add Transactions in 01-03-2021 - 31-03-2021"
- self.load_testdocs()
now = getdate()
self.from_date = get_first_day(now)
self.to_date = get_last_day(now)
- for doc in self.docs:
+ docs = [{
+ "doctype": "Fiscal Year",
+ "year": "_Test Fiscal",
+ "year_end_date": get_year_ending(now),
+ "year_start_date": get_year_start(now)
+ }] + docs
+
+ for doc in docs:
try:
db_doc = frappe.get_doc(doc)
if 'Invoice' in db_doc.doctype:
@@ -45,15 +38,28 @@ class TestTaxDetail(unittest.TestCase):
except frappe.exceptions.DuplicateEntryError:
pass
+ def load_defcols(self):
+ self.company = frappe.get_doc('Company', '_T')
+ custom_report = frappe.get_doc('Report', 'Tax Detail')
+ self.default_columns, _ = custom_report.run_query_report(
+ filters={
+ 'from_date': '2021-03-01',
+ 'to_date': '2021-03-31',
+ 'company': self.company.name,
+ 'mode': 'run',
+ 'report_name': 'Tax Detail'
+ }, user=frappe.session.user)
+
+ def setUp(self):
+ self.load_testdocs()
self.load_defcols()
def tearDown(self):
"Remove the Company and all data"
from erpnext.setup.doctype.company.delete_company_transactions import delete_company_transactions
- for co in filter(lambda doc: doc['doctype'] == 'Company', self.docs):
- delete_company_transactions(co['name'])
- db_co = frappe.get_doc('Company', co['name'])
- db_co.delete()
+ delete_company_transactions(self.company.name)
+ self.company.delete()
+
def test_report(self):
report_name = save_custom_report(
@@ -78,7 +84,7 @@ class TestTaxDetail(unittest.TestCase):
filters={
'from_date': self.from_date,
'to_date': self.to_date,
- 'company': '_T',
+ 'company': self.company.name,
'mode': 'run',
'report_name': report_name
}, user=frappe.session.user)
From 89fcdf32263e2baaa704fb97f121759e34d87701 Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Sat, 10 Apr 2021 00:32:11 +0000
Subject: [PATCH 125/149] fix: exclude rounding GL Entries from invoice tax
lines
---
.../accounts/report/tax_detail/tax_detail.py | 28 +++++++++----------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py
index aafcf1297e..fdecd269eb 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/tax_detail.py
@@ -225,21 +225,21 @@ def modify_report_data(data):
line.amount = line.credit
# Remove Invoice GL Tax Entries and generate Tax entries from the invoice lines
if "Invoice" in line.voucher_type:
- if line.account_type != "Tax":
+ if line.account_type not in ("Tax", "Round Off"):
new_data += [line]
- if line.item_tax_rate:
- tax_rates = json.loads(line.item_tax_rate)
- for account, rate in tax_rates.items():
- tax_line = line.copy()
- tax_line.account_type = "Tax"
- tax_line.account = account
- if line.voucher_type == "Sales Invoice":
- line.amount = line.base_net_amount
- tax_line.amount = line.base_net_amount * (rate / 100)
- if line.voucher_type == "Purchase Invoice":
- line.amount = -line.base_net_amount
- tax_line.amount = -line.base_net_amount * (rate / 100)
- new_data += [tax_line]
+ if line.item_tax_rate:
+ tax_rates = json.loads(line.item_tax_rate)
+ for account, rate in tax_rates.items():
+ tax_line = line.copy()
+ tax_line.account_type = "Tax"
+ tax_line.account = account
+ if line.voucher_type == "Sales Invoice":
+ line.amount = line.base_net_amount
+ tax_line.amount = line.base_net_amount * (rate / 100)
+ if line.voucher_type == "Purchase Invoice":
+ line.amount = -line.base_net_amount
+ tax_line.amount = -line.base_net_amount * (rate / 100)
+ new_data += [tax_line]
else:
new_data += [line]
return new_data
From 75ebfbdaf392cbb98100291a52d2623a7337618d Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Sat, 10 Apr 2021 02:27:00 +0000
Subject: [PATCH 126/149] fix: fiscal year test case issue
---
.../accounts/report/tax_detail/test_tax_detail.json | 11 ++---------
.../accounts/report/tax_detail/test_tax_detail.py | 13 +++++++++++++
2 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/test_tax_detail.json b/erpnext/accounts/report/tax_detail/test_tax_detail.json
index 977920a231..3a4b175455 100644
--- a/erpnext/accounts/report/tax_detail/test_tax_detail.json
+++ b/erpnext/accounts/report/tax_detail/test_tax_detail.json
@@ -1,12 +1,5 @@
[
{
- "abbr": "_T",
- "company_name": "_T",
- "country": "United Kingdom",
- "default_currency": "GBP",
- "doctype": "Company",
- "name": "_T"
- },{
"account_manager": null,
"accounts": [],
"companies": [],
@@ -297,7 +290,7 @@
"discount_amount": 0.0,
"docstatus": 0,
"doctype": "Purchase Invoice",
- "due_date": "2021-04-30",
+ "due_date": null,
"from_date": null,
"grand_total": 511.68,
"group_same_items": 0,
@@ -521,7 +514,7 @@
"discount_amount": 0.0,
"docstatus": 0,
"doctype": "Sales Invoice",
- "due_date": "2021-03-31",
+ "due_date": null,
"from_date": null,
"grand_total": 868.25,
"group_same_items": 0,
diff --git a/erpnext/accounts/report/tax_detail/test_tax_detail.py b/erpnext/accounts/report/tax_detail/test_tax_detail.py
index 21732b9dfd..dcf0e79064 100644
--- a/erpnext/accounts/report/tax_detail/test_tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/test_tax_detail.py
@@ -19,6 +19,19 @@ class TestTaxDetail(unittest.TestCase):
self.to_date = get_last_day(now)
docs = [{
+ "abbr": "_T",
+ "company_name": "_T",
+ "country": "United Kingdom",
+ "default_currency": "GBP",
+ "doctype": "Company",
+ "name": "_T"
+ },{
+ "companies": [{
+ "company": "_T",
+ "parent": "_Test Fiscal",
+ "parentfield": "companies",
+ "parenttype": "Fiscal Year"
+ }],
"doctype": "Fiscal Year",
"year": "_Test Fiscal",
"year_end_date": get_year_ending(now),
From 68a31d3d0d799608fbf5593f5f7d732d2971eb03 Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Sat, 10 Apr 2021 18:59:57 +0000
Subject: [PATCH 127/149] fix: fiscal year error
---
.../report/tax_detail/test_tax_detail.py | 28 +++++++++++--------
1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/test_tax_detail.py b/erpnext/accounts/report/tax_detail/test_tax_detail.py
index dcf0e79064..772b9a468a 100644
--- a/erpnext/accounts/report/tax_detail/test_tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/test_tax_detail.py
@@ -18,6 +18,23 @@ class TestTaxDetail(unittest.TestCase):
self.from_date = get_first_day(now)
self.to_date = get_last_day(now)
+ for fy in frappe.get_list('Fiscal Year', fields=('year', 'year_start_date', 'year_end_date')):
+ if now >= fy['year_start_date'] and now <= fy['year_end_date']:
+ break
+ else:
+ docs = [{
+ "companies": [{
+ "company": "_T",
+ "parent": "_Test Fiscal",
+ "parentfield": "companies",
+ "parenttype": "Fiscal Year"
+ }],
+ "doctype": "Fiscal Year",
+ "year": "_Test Fiscal",
+ "year_end_date": get_year_ending(now),
+ "year_start_date": get_year_start(now)
+ }] + docs
+
docs = [{
"abbr": "_T",
"company_name": "_T",
@@ -25,17 +42,6 @@ class TestTaxDetail(unittest.TestCase):
"default_currency": "GBP",
"doctype": "Company",
"name": "_T"
- },{
- "companies": [{
- "company": "_T",
- "parent": "_Test Fiscal",
- "parentfield": "companies",
- "parenttype": "Fiscal Year"
- }],
- "doctype": "Fiscal Year",
- "year": "_Test Fiscal",
- "year_end_date": get_year_ending(now),
- "year_start_date": get_year_start(now)
}] + docs
for doc in docs:
From cf5b57bfacff6ffe813c7fcfef1b74d80b545337 Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Sat, 10 Apr 2021 20:32:22 +0000
Subject: [PATCH 128/149] fix: only load data for tests that need it
---
erpnext/accounts/report/tax_detail/test_tax_detail.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/test_tax_detail.py b/erpnext/accounts/report/tax_detail/test_tax_detail.py
index 772b9a468a..78b15b11c5 100644
--- a/erpnext/accounts/report/tax_detail/test_tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/test_tax_detail.py
@@ -69,11 +69,7 @@ class TestTaxDetail(unittest.TestCase):
'report_name': 'Tax Detail'
}, user=frappe.session.user)
- def setUp(self):
- self.load_testdocs()
- self.load_defcols()
-
- def tearDown(self):
+ def rm_testdocs(self):
"Remove the Company and all data"
from erpnext.setup.doctype.company.delete_company_transactions import delete_company_transactions
delete_company_transactions(self.company.name)
@@ -81,6 +77,8 @@ class TestTaxDetail(unittest.TestCase):
def test_report(self):
+ self.load_testdocs()
+ self.load_defcols()
report_name = save_custom_report(
'Tax Detail',
'_Test Tax Detail',
@@ -119,6 +117,8 @@ class TestTaxDetail(unittest.TestCase):
self.assertListEqual(data.get('report_summary'),
[{'label': label, 'datatype': 'Currency', 'value': value} for label, value in expected])
+ self.rm_testdocs()
+
def test_filter_match(self):
# None - treated as -inf number except range
self.assertTrue(filter_match(None, '!='))
From 699878605531f588d9f1afd836cf4b0c6621658f Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Mon, 12 Apr 2021 13:03:09 +0000
Subject: [PATCH 129/149] fix: use correct fiscal year function in testing
---
erpnext/accounts/report/tax_detail/test_tax_detail.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/test_tax_detail.py b/erpnext/accounts/report/tax_detail/test_tax_detail.py
index 78b15b11c5..d3b8de5d19 100644
--- a/erpnext/accounts/report/tax_detail/test_tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/test_tax_detail.py
@@ -10,6 +10,7 @@ from .tax_detail import filter_match, save_custom_report
class TestTaxDetail(unittest.TestCase):
def load_testdocs(self):
+ from erpnext.accounts.utils import get_fiscal_year, FiscalYearError
datapath, _ = os.path.splitext(os.path.realpath(__file__))
with open(datapath + '.json', 'r') as fp:
docs = json.load(fp)
@@ -18,10 +19,9 @@ class TestTaxDetail(unittest.TestCase):
self.from_date = get_first_day(now)
self.to_date = get_last_day(now)
- for fy in frappe.get_list('Fiscal Year', fields=('year', 'year_start_date', 'year_end_date')):
- if now >= fy['year_start_date'] and now <= fy['year_end_date']:
- break
- else:
+ try:
+ get_fiscal_year(now, company="_T")
+ except FiscalYearError:
docs = [{
"companies": [{
"company": "_T",
From d5256b60d48806e5e10442663623959fda7fb570 Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Sun, 18 Apr 2021 22:13:39 +0000
Subject: [PATCH 130/149] fix: lint
---
erpnext/accounts/report/tax_detail/tax_detail.js | 4 ++--
erpnext/accounts/report/tax_detail/tax_detail.py | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.js b/erpnext/accounts/report/tax_detail/tax_detail.js
index 098096ce0b..ed6fac4e60 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.js
+++ b/erpnext/accounts/report/tax_detail/tax_detail.js
@@ -273,7 +273,7 @@ erpnext.TaxDetail = class TaxDetail {
click: () => {
let cur_section = this.controls['section_name'].get_input_value();
if (cur_section) {
- frappe.confirm(__('Are you sure you want to delete section ') + cur_section + '?',
+ frappe.confirm(__('Are you sure you want to delete section') + ' ' + cur_section + '?',
() => {this.delete(cur_section, 'section')});
}
}
@@ -354,7 +354,7 @@ erpnext.TaxDetail = class TaxDetail {
click: () => {
const component = this.controls['component'].get_input_value();
if (component) {
- frappe.confirm(__('Are you sure you want to delete component ') + component + '?',
+ frappe.confirm(__('Are you sure you want to delete component') + ' ' + component + '?',
() => {this.delete(component, 'component')});
}
}
diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py
index fdecd269eb..18436de3d8 100644
--- a/erpnext/accounts/report/tax_detail/tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/tax_detail.py
@@ -80,12 +80,12 @@ def run_report(report_name, data):
report[section_name]['subtotal'] += row['amount']
if component['type'] == 'section':
if component_name == section_name:
- frappe.throw(_("A report component cannot refer to its parent section: ") + section_name)
+ frappe.throw(_("A report component cannot refer to its parent section") + ": " + section_name)
try:
report[section_name]['rows'] += report[component_name]['rows']
report[section_name]['subtotal'] += report[component_name]['subtotal']
except KeyError:
- frappe.throw(_("A report component can only refer to an earlier section: ") + section_name)
+ frappe.throw(_("A report component can only refer to an earlier section") + ": " + section_name)
if show_detail:
new_data += report[section_name]['rows']
@@ -141,7 +141,7 @@ def filter_match(value, string):
try:
num = float(string) if string.strip() else 0
- return eval(f'{value} {operator} {num}')
+ return frappe.safe_eval(f'{value} {operator} {num}')
except ValueError:
if operator == '<':
return True
From 6ab46e288f15e77815c0bd3a67fc0d6ba8e28e03 Mon Sep 17 00:00:00 2001
From: casesolved-co-uk
Date: Thu, 13 May 2021 12:56:02 +0000
Subject: [PATCH 131/149] fix: workspace formatting due to manual edit and
filter tweaks
---
.../workspace/accounting/accounting.json | 22 ++++++++++---------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/erpnext/accounts/workspace/accounting/accounting.json b/erpnext/accounts/workspace/accounting/accounting.json
index cbfba7e31c..148436edaa 100644
--- a/erpnext/accounts/workspace/accounting/accounting.json
+++ b/erpnext/accounts/workspace/accounting/accounting.json
@@ -452,18 +452,20 @@
"link_to": "DATEV",
"link_type": "Report",
"onboard": 0,
+ "only_for": "Germany",
"type": "Link"
},
{
- "dependencies": "GL Entry",
- "hidden": 0,
- "is_query_report": 1,
- "label": "UAE VAT 201",
- "link_to": "UAE VAT 201",
- "link_type": "Report",
- "onboard": 0,
- "type": "Link"
- },
+ "dependencies": "GL Entry",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "UAE VAT 201",
+ "link_to": "UAE VAT 201",
+ "link_type": "Report",
+ "onboard": 0,
+ "only_for": "United Arab Emirates",
+ "type": "Link"
+ },
{
"hidden": 0,
"is_query_report": 0,
@@ -1062,7 +1064,7 @@
"type": "Link"
}
],
- "modified": "2021-05-12 11:48:01.905144",
+ "modified": "2021-05-13 13:44:56.249888",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting",
From e9f6c8cdb19b93fb5c9a96e5f0e920032059e1ed Mon Sep 17 00:00:00 2001
From: rohitwaghchaure
Date: Fri, 14 May 2021 12:34:13 +0530
Subject: [PATCH 132/149] fix: validation message of quality inspection in
purchase receipt (#25667)
---
erpnext/controllers/stock_controller.py | 3 +--
.../doctype/quality_inspection/test_quality_inspection.py | 3 ++-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index b14c274515..41ca404d9b 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -379,8 +379,7 @@ class StockController(AccountsController):
link = frappe.utils.get_link_to_form('Quality Inspection', d.quality_inspection)
frappe.throw(_("Quality Inspection: {0} is not submitted for the item: {1} in row {2}").format(link, d.item_code, d.idx), QualityInspectionNotSubmittedError)
- qa_failed = any([r.status=="Rejected" for r in qa_doc.readings])
- if qa_failed:
+ if qa_doc.status != 'Accepted':
frappe.throw(_("Row {0}: Quality Inspection rejected for item {1}")
.format(d.idx, d.item_code), QualityInspectionRejectedError)
elif qa_required :
diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
index a7dfc9ee28..56b046a92e 100644
--- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
@@ -27,10 +27,11 @@ class TestQualityInspection(unittest.TestCase):
dn.reload()
self.assertRaises(QualityInspectionRejectedError, dn.submit)
- frappe.db.set_value("Quality Inspection Reading", {"parent": qa.name}, "status", "Accepted")
+ frappe.db.set_value("Quality Inspection", qa.name, "status", "Accepted")
dn.reload()
dn.submit()
+ qa.reload()
qa.cancel()
dn.reload()
dn.cancel()
From ad0b8fdd1e63c01c0819e129940fae5b83924560 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Mon, 17 May 2021 10:49:21 +0530
Subject: [PATCH 133/149] chore: Added change log for v13.3.0
---
erpnext/change_log/v13/v13_3_0.md | 73 +++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
create mode 100644 erpnext/change_log/v13/v13_3_0.md
diff --git a/erpnext/change_log/v13/v13_3_0.md b/erpnext/change_log/v13/v13_3_0.md
new file mode 100644
index 0000000000..016dbb01f4
--- /dev/null
+++ b/erpnext/change_log/v13/v13_3_0.md
@@ -0,0 +1,73 @@
+# Version 13.3.0 Release Notes
+
+### Features & Enhancements
+
+- Purchase receipt creation from purchase invoice ([#25126](https://github.com/frappe/erpnext/pull/25126))
+- New Document Transaction Deletion ([#25354](https://github.com/frappe/erpnext/pull/25354))
+- Employee Referral ([#24997](https://github.com/frappe/erpnext/pull/24997))
+- Add Create Expense Claim button in Delivery Trip ([#25526](https://github.com/frappe/erpnext/pull/25526))
+- Reduced rate of asset depreciation as per IT Act ([#25648](https://github.com/frappe/erpnext/pull/25648))
+- Improve DATEV export ([#25238](https://github.com/frappe/erpnext/pull/25238))
+- Add pick batch button ([#25413](https://github.com/frappe/erpnext/pull/25413))
+- Enable custom field search on POS ([#25421](https://github.com/frappe/erpnext/pull/25421))
+- New check field in subscriptions for (not) submitting invoices ([#25394](https://github.com/frappe/erpnext/pull/25394))
+- Show POS reserved stock in stock projected qty report ([#25593](https://github.com/frappe/erpnext/pull/25593))
+- e-way bill validity field ([#25555](https://github.com/frappe/erpnext/pull/25555))
+- Significant reduction in time taken to save sales documents ([#25475](https://github.com/frappe/erpnext/pull/25475))
+
+### Fixes
+
+- Bank statement import via google sheet ([#25677](https://github.com/frappe/erpnext/pull/25677))
+- Invoices not getting fetched during payment reconciliation ([#25598](https://github.com/frappe/erpnext/pull/25598))
+- Error on applying TDS without party ([#25632](https://github.com/frappe/erpnext/pull/25632))
+- Allow to cancel loan with cancelled repayment entry ([#25507](https://github.com/frappe/erpnext/pull/25507))
+- Can't open general ledger from consolidated financial report ([#25542](https://github.com/frappe/erpnext/pull/25542))
+- Add 'Partially Received' to Status drop-down list in Material Request ([#24857](https://github.com/frappe/erpnext/pull/24857))
+- Updated item filters for material request ([#25531](https://github.com/frappe/erpnext/pull/25531))
+- Added validation in stock entry to check duplicate serial nos ([#25611](https://github.com/frappe/erpnext/pull/25611))
+- Update shopify api version ([#25600](https://github.com/frappe/erpnext/pull/25600))
+- Dialog variable assignment after definition in POS ([#25680](https://github.com/frappe/erpnext/pull/25680))
+- Added tax_types list ([#25587](https://github.com/frappe/erpnext/pull/25587))
+- Include search fields in Project Link field query ([#25505](https://github.com/frappe/erpnext/pull/25505))
+- Item stock levels displaying inconsistently ([#25506](https://github.com/frappe/erpnext/pull/25506))
+- Change today to now to get data for reposting ([#25703](https://github.com/frappe/erpnext/pull/25703))
+- Parameter for get_filtered_list_for_consolidated_report in consolidated balance sheet ([#25700](https://github.com/frappe/erpnext/pull/25700))
+- Minor fixes in loan ([#25546](https://github.com/frappe/erpnext/pull/25546))
+- Fieldname when updating docfield property ([#25516](https://github.com/frappe/erpnext/pull/25516))
+- Use get_serial_nos for splitting ([#25590](https://github.com/frappe/erpnext/pull/25590))
+- Show item's full name on hover over item in POS ([#25554](https://github.com/frappe/erpnext/pull/25554))
+- Stock ledger entry created against draft stock entry ([#25540](https://github.com/frappe/erpnext/pull/25540))
+- Incorrect expense account set in pos invoice ([#25543](https://github.com/frappe/erpnext/pull/25543))
+- Stock balance and batch-wise balance history report showing different closing stock ([#25575](https://github.com/frappe/erpnext/pull/25575))
+- Make strings translatable ([#25521](https://github.com/frappe/erpnext/pull/25521))
+- Serial no changed after saving stock reconciliation ([#25541](https://github.com/frappe/erpnext/pull/25541))
+- Ignore fraction difference while making round off gl entry ([#25438](https://github.com/frappe/erpnext/pull/25438))
+- Sync shopify customer addresses ([#25481](https://github.com/frappe/erpnext/pull/25481))
+- Total stock summary report not working ([#25551](https://github.com/frappe/erpnext/pull/25551))
+- Rename field has not updated value of deposit and withdrawal fields ([#25545](https://github.com/frappe/erpnext/pull/25545))
+- Unexpected keyword argument 'merge_logs' ([#25489](https://github.com/frappe/erpnext/pull/25489))
+- Validation message of quality inspection in purchase receipt ([#25667](https://github.com/frappe/erpnext/pull/25667))
+- Added is_stock_item filter ([#25530](https://github.com/frappe/erpnext/pull/25530))
+- Fetch total stock at company in PO ([#25532](https://github.com/frappe/erpnext/pull/25532))
+- Updated filters for process statement of accounts ([#25384](https://github.com/frappe/erpnext/pull/25384))
+- Incorrect expense account set in pos invoice ([#25571](https://github.com/frappe/erpnext/pull/25571))
+- Client script breaking while settings tax labels ([#25653](https://github.com/frappe/erpnext/pull/25653))
+- Empty payment term column in accounts receivable report ([#25556](https://github.com/frappe/erpnext/pull/25556))
+- Designation insufficient permission on lead doctype. ([#25331](https://github.com/frappe/erpnext/pull/25331))
+- Force https for shopify webhook registration ([#25630](https://github.com/frappe/erpnext/pull/25630))
+- Patch regional fields for old companies ([#25673](https://github.com/frappe/erpnext/pull/25673))
+- Woocommerce order sync issue ([#25692](https://github.com/frappe/erpnext/pull/25692))
+- Allow to receive same serial numbers multiple times ([#25471](https://github.com/frappe/erpnext/pull/25471))
+- Update Allocated amount after Paid Amount is changed in PE ([#25515](https://github.com/frappe/erpnext/pull/25515))
+- Updating Standard Notification's channel field ([#25564](https://github.com/frappe/erpnext/pull/25564))
+- Report summary showing inflated values when values are accumulated in Group Company ([#25577](https://github.com/frappe/erpnext/pull/25577))
+- UI fixes related to overflowing payment section ([#25652](https://github.com/frappe/erpnext/pull/25652))
+- List invoices in Payment Reconciliation Payment ([#25524](https://github.com/frappe/erpnext/pull/25524))
+- Ageing errors in PSOA ([#25490](https://github.com/frappe/erpnext/pull/25490))
+- Prevent spurious defaults for items when making prec from dnote ([#25559](https://github.com/frappe/erpnext/pull/25559))
+- Stock reconciliation getting time out error during submission ([#25557](https://github.com/frappe/erpnext/pull/25557))
+- Timesheet filter date exclusive issue ([#25626](https://github.com/frappe/erpnext/pull/25626))
+- Update cost center in the item table fetched from POS Profile ([#25609](https://github.com/frappe/erpnext/pull/25609))
+- Updated modified time in purchase invoice to pull new fields ([#25678](https://github.com/frappe/erpnext/pull/25678))
+- Stock and Accounts Settings form refactor ([#25534](https://github.com/frappe/erpnext/pull/25534))
+- Payment amount showing in foreign currency ([#25292](https://github.com/frappe/erpnext/pull/25292))
\ No newline at end of file
From 2f403f1bcd42e9a8991c604f3a05e94d13dc3b52 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Mon, 17 May 2021 10:50:26 +0530
Subject: [PATCH 134/149] fix: renamed change log
---
erpnext/change_log/v13/v13.0.2.md | 7 -------
1 file changed, 7 deletions(-)
delete mode 100644 erpnext/change_log/v13/v13.0.2.md
diff --git a/erpnext/change_log/v13/v13.0.2.md b/erpnext/change_log/v13/v13.0.2.md
deleted file mode 100644
index 2bfbdfcc5d..0000000000
--- a/erpnext/change_log/v13/v13.0.2.md
+++ /dev/null
@@ -1,7 +0,0 @@
-## Version 13.0.2 Release Notes
-
-### Fixes
-- fix: frappe.whitelist for doc methods ([#25231](https://github.com/frappe/erpnext/pull/25231))
-- fix: incorrect incoming rate for the sales return ([#25306](https://github.com/frappe/erpnext/pull/25306))
-- fix(e-invoicing): validations & tax calculation fixes ([#25314](https://github.com/frappe/erpnext/pull/25314))
-- fix: update scheduler check time ([#25295](https://github.com/frappe/erpnext/pull/25295))
\ No newline at end of file
From 9ec0f118005732d41e84ad7e7844c72d0a01db9c Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Mon, 17 May 2021 10:50:42 +0530
Subject: [PATCH 135/149] fix: renamed change log
---
erpnext/change_log/v13/v13_0_2.md | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 erpnext/change_log/v13/v13_0_2.md
diff --git a/erpnext/change_log/v13/v13_0_2.md b/erpnext/change_log/v13/v13_0_2.md
new file mode 100644
index 0000000000..2bfbdfcc5d
--- /dev/null
+++ b/erpnext/change_log/v13/v13_0_2.md
@@ -0,0 +1,7 @@
+## Version 13.0.2 Release Notes
+
+### Fixes
+- fix: frappe.whitelist for doc methods ([#25231](https://github.com/frappe/erpnext/pull/25231))
+- fix: incorrect incoming rate for the sales return ([#25306](https://github.com/frappe/erpnext/pull/25306))
+- fix(e-invoicing): validations & tax calculation fixes ([#25314](https://github.com/frappe/erpnext/pull/25314))
+- fix: update scheduler check time ([#25295](https://github.com/frappe/erpnext/pull/25295))
\ No newline at end of file
From bc92ecb10f36724a967e4bdc17b09fa119f81ec8 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Mon, 17 May 2021 11:56:29 +0550
Subject: [PATCH 136/149] bumped to version 13.3.0
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 6775398532..ad971e2976 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
-__version__ = '13.2.1'
+__version__ = '13.3.0'
def get_default_company(user=None):
'''Get default company for user'''
From 0517abad43592417daade7aa36b4eb40364d7c29 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Sun, 16 May 2021 16:48:44 +0530
Subject: [PATCH 137/149] fix: run scheduler for reposting if there is no
scheduler is running for the reposting
---
.../repost_item_valuation/repost_item_valuation.py | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index 63c71891e4..63e96466d0 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -4,8 +4,9 @@
from __future__ import unicode_literals
import frappe, erpnext
+from rq.timeouts import JobTimeoutException
from frappe.model.document import Document
-from frappe.utils import cint, get_link_to_form, add_to_date, now, today
+from frappe.utils import cint, get_link_to_form, add_to_date, now, today, time_diff_in_hours
from erpnext.stock.stock_ledger import repost_future_sle
from erpnext.accounts.utils import update_gl_entries_after, check_if_stock_and_account_balance_synced
from frappe.utils.user import get_users_with_role
@@ -57,7 +58,8 @@ def repost(doc):
repost_gl_entries(doc)
doc.set_status('Completed')
- except Exception:
+
+ except (Exception, JobTimeoutException):
frappe.db.rollback()
traceback = frappe.get_traceback()
frappe.log_error(traceback)
@@ -113,6 +115,12 @@ def notify_error_to_stock_managers(doc, traceback):
frappe.sendmail(recipients=recipients, subject=subject, message=message)
def repost_entries():
+ job_log = frappe.get_all('Scheduled Job Log', fields = ['status', 'creation'],
+ filters = {'scheduled_job_type': 'repost_item_valuation.repost_entries'}, order_by='creation desc', limit=1)
+
+ if job_log and job_log[0]['status'] == 'Start' and time_diff_in_hours(now(), job_log[0]['creation']) < 2:
+ return
+
riv_entries = get_repost_item_valuation_entries()
for row in riv_entries:
From 9d6f343111234a533f04a20da0da0ab86d9066ff Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 18 May 2021 15:44:52 +0530
Subject: [PATCH 138/149] chore(deps): bump ini from 1.3.5 to 1.3.7 (#25733)
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
yarn.lock | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index 635bb066ec..242695c4b8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1540,16 +1540,11 @@ inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-ini@1.3.7:
+ini@1.3.7, ini@~1.3.0:
version "1.3.7"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84"
integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==
-ini@~1.3.0:
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
- integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
-
is-callable@^1.1.5:
version "1.2.3"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e"
From 0fb6f9306f6cb3f6022dca0c2a0f945160a508a1 Mon Sep 17 00:00:00 2001
From: anushka19 <37659765+anushka19@users.noreply.github.com>
Date: Tue, 18 May 2021 17:00:33 +0530
Subject: [PATCH 139/149] fix: Accumulated depreciation (#25740)
* fix: Accumulated depreciation
* fix: Sider issues
---
erpnext/assets/doctype/asset_category/asset_category.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/assets/doctype/asset_category/asset_category.js b/erpnext/assets/doctype/asset_category/asset_category.js
index 74963c2aa9..51ce157a81 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.js
+++ b/erpnext/assets/doctype/asset_category/asset_category.js
@@ -4,7 +4,7 @@
frappe.ui.form.on('Asset Category', {
onload: function(frm) {
frm.add_fetch('company_name', 'accumulated_depreciation_account', 'accumulated_depreciation_account');
- frm.add_fetch('company_name', 'depreciation_expense_account', 'accumulated_depreciation_account');
+ frm.add_fetch('company_name', 'depreciation_expense_account', 'depreciation_expense_account');
frm.set_query('fixed_asset_account', 'accounts', function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
From 1483a60b90e9286875d803a3182996217ced57ed Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Wed, 19 May 2021 12:30:11 +0530
Subject: [PATCH 140/149] fix: super call syntax error
---
erpnext/selling/doctype/quotation/quotation.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js
index 10606bf81e..7fecd4bc34 100644
--- a/erpnext/selling/doctype/quotation/quotation.js
+++ b/erpnext/selling/doctype/quotation/quotation.js
@@ -39,8 +39,7 @@ frappe.ui.form.on('Quotation', {
erpnext.selling.QuotationController = class QuotationController extends erpnext.selling.SellingController {
onload(doc, dt, dn) {
var me = this;
- super.(doc, dt, dn);
-
+ super.onload(doc, dt, dn);
}
party_name() {
var me = this;
From 6a1e31c63334b7356647d24da84435b25da50bbe Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Thu, 20 May 2021 23:16:22 +0530
Subject: [PATCH 141/149] fix: Check if user can rread before querying Support
Settings
---
erpnext/support/doctype/issue/issue.js | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/erpnext/support/doctype/issue/issue.js b/erpnext/support/doctype/issue/issue.js
index ecc9fcfe82..99a4e04b7d 100644
--- a/erpnext/support/doctype/issue/issue.js
+++ b/erpnext/support/doctype/issue/issue.js
@@ -9,15 +9,17 @@ frappe.ui.form.on("Issue", {
};
});
- frappe.db.get_value("Support Settings", {name: "Support Settings"},
- ["allow_resetting_service_level_agreement", "track_service_level_agreement"], (r) => {
- if (r && r.track_service_level_agreement == "0") {
- frm.set_df_property("service_level_section", "hidden", 1);
- }
- if (r && r.allow_resetting_service_level_agreement == "0") {
- frm.set_df_property("reset_service_level_agreement", "hidden", 1);
- }
- });
+ if (frappe.model.can_read("Support Settings")) {
+ frappe.db.get_value("Support Settings", {name: "Support Settings"},
+ ["allow_resetting_service_level_agreement", "track_service_level_agreement"], (r) => {
+ if (r && r.track_service_level_agreement == "0") {
+ frm.set_df_property("service_level_section", "hidden", 1);
+ }
+ if (r && r.allow_resetting_service_level_agreement == "0") {
+ frm.set_df_property("reset_service_level_agreement", "hidden", 1);
+ }
+ });
+ }
if (frm.doc.service_level_agreement) {
frappe.call({
From 81d49e9c71fceba8cd2e9369a0f712c0f9c41ccc Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 21 May 2021 17:03:09 +0530
Subject: [PATCH 142/149] fix: Use extend_cscript function to properly extend
class methods to cscript
---
.eslintrc | 3 ++-
.../payment_reconciliation.js | 2 +-
.../accounts/doctype/pos_invoice/pos_invoice.js | 4 ++--
.../doctype/sales_invoice/sales_invoice.js | 5 ++++-
.../doctype/purchase_order/purchase_order.js | 2 +-
.../request_for_quotation/request_for_quotation.js | 2 +-
.../supplier_quotation/supplier_quotation.js | 2 +-
erpnext/crm/doctype/lead/lead.js | 2 +-
erpnext/crm/doctype/opportunity/opportunity.js | 4 ++--
.../maintenance_schedule/maintenance_schedule.js | 2 +-
.../doctype/maintenance_visit/maintenance_visit.js | 2 +-
erpnext/manufacturing/doctype/bom/bom.js | 4 ++--
erpnext/public/js/controllers/taxes_and_totals.js | 4 +++-
erpnext/public/js/controllers/transaction.js | 2 +-
.../doctype/installation_note/installation_note.js | 2 +-
erpnext/selling/doctype/sales_order/sales_order.js | 5 +++--
erpnext/selling/doctype/sms_center/sms_center.js | 2 +-
.../doctype/currency_exchange/currency_exchange.js | 14 +++++++-------
.../stock/doctype/delivery_note/delivery_note.js | 2 +-
.../doctype/material_request/material_request.js | 4 ++--
.../doctype/purchase_receipt/purchase_receipt.js | 2 +-
erpnext/stock/doctype/stock_entry/stock_entry.js | 2 +-
.../doctype/warranty_claim/warranty_claim.js | 4 ++--
23 files changed, 42 insertions(+), 35 deletions(-)
diff --git a/.eslintrc b/.eslintrc
index 3b6ab7498d..e40502acd6 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -151,6 +151,7 @@
"context": true,
"before": true,
"beforeEach": true,
- "onScan": true
+ "onScan": true,
+ "extend_cscript": true
}
}
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
index 8dcd1aa8e7..c71a62dfb3 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
@@ -262,4 +262,4 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
};
-$.extend(cur_frm.cscript, new erpnext.accounts.PaymentReconciliationController({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.accounts.PaymentReconciliationController({frm: cur_frm}));
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
index 72d587afb5..181e9f8ec0 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
@@ -135,7 +135,7 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
}
}
-$.extend(cur_frm.cscript, new erpnext.selling.POSInvoiceController({ frm: cur_frm }))
+extend_cscript(cur_frm.cscript, new erpnext.selling.POSInvoiceController({ frm: cur_frm }))
frappe.ui.form.on('POS Invoice', {
redeem_loyalty_points: function(frm) {
@@ -235,4 +235,4 @@ frappe.ui.form.on('POS Invoice', {
});
});
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index b48db246ac..ea7432caa2 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -450,8 +450,11 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
}
};
+console.log('innn')
// for backward compatibility: combine new and previous states
-$.extend(cur_frm.cscript, new erpnext.accounts.SalesInvoiceController({frm: cur_frm}));
+let controller_instance = new erpnext.accounts.SalesInvoiceController({frm: cur_frm})
+extend_cscript(cur_frm.cscript, controller_instance);
+extend_cscript(cur_frm.cscript.__proto_, controller_instance.__proto__);
cur_frm.cscript['Make Delivery Note'] = function() {
frappe.model.open_mapped_doc({
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index c0e19e9c3d..384bbc5385 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -547,7 +547,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
};
// for backward compatibility: combine new and previous states
-$.extend(cur_frm.cscript, new erpnext.buying.PurchaseOrderController({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.buying.PurchaseOrderController({frm: cur_frm}));
cur_frm.cscript.update_status= function(label, status){
frappe.call({
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
index ee0e1ef576..bde00cbd94 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
@@ -414,4 +414,4 @@ erpnext.buying.RequestforQuotationController = class RequestforQuotationControll
};
// for backward compatibility: combine new and previous states
-$.extend(cur_frm.cscript, new erpnext.buying.RequestforQuotationController({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.buying.RequestforQuotationController({frm: cur_frm}));
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
index a3ba52e67b..dc9c590dc5 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
@@ -95,7 +95,7 @@ erpnext.buying.SupplierQuotationController = class SupplierQuotationController e
};
// for backward compatibility: combine new and previous states
-$.extend(cur_frm.cscript, new erpnext.buying.SupplierQuotationController({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.buying.SupplierQuotationController({frm: cur_frm}));
cur_frm.fields_dict['items'].grid.get_field('project').get_query =
function(doc, cdt, cdn) {
diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js
index 8dfee1d6c7..ebe85241d2 100644
--- a/erpnext/crm/doctype/lead/lead.js
+++ b/erpnext/crm/doctype/lead/lead.js
@@ -88,4 +88,4 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller
}
};
-$.extend(cur_frm.cscript, new erpnext.LeadController({ frm: cur_frm }));
+extend_cscript(cur_frm.cscript, new erpnext.LeadController({ frm: cur_frm }));
diff --git a/erpnext/crm/doctype/opportunity/opportunity.js b/erpnext/crm/doctype/opportunity/opportunity.js
index 925c30b451..43e1b99f3a 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.js
+++ b/erpnext/crm/doctype/opportunity/opportunity.js
@@ -195,7 +195,7 @@ erpnext.crm.Opportunity = class Opportunity extends frappe.ui.form.Controller {
}
};
-$.extend(cur_frm.cscript, new erpnext.crm.Opportunity({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.crm.Opportunity({frm: cur_frm}));
cur_frm.cscript.item_code = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
@@ -213,4 +213,4 @@ cur_frm.cscript.item_code = function(doc, cdt, cdn) {
}
})
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
index 2adfaf45ef..2371d9652c 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
@@ -115,5 +115,5 @@ erpnext.maintenance.MaintenanceSchedule = class MaintenanceSchedule extends frap
}
};
-$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceSchedule({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.maintenance.MaintenanceSchedule({frm: cur_frm}));
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
index 12dc59ccfc..503253040b 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
@@ -99,4 +99,4 @@ erpnext.maintenance.MaintenanceVisit = class MaintenanceVisit extends frappe.ui.
}
};
-$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({frm: cur_frm}));
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index b32b96af13..44f841f13b 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -405,7 +405,7 @@ erpnext.bom.BomController = class BomController extends erpnext.TransactionContr
}
};
-$.extend(cur_frm.cscript, new erpnext.bom.BomController({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.bom.BomController({frm: cur_frm}));
cur_frm.cscript.hour_rate = function(doc) {
erpnext.bom.calculate_op_cost(doc);
@@ -662,4 +662,4 @@ frappe.ui.form.on("BOM", "with_operations", function(frm) {
frm.set_value("operations", []);
}
toggle_operations(frm);
-});
\ No newline at end of file
+});
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 31410da6bf..32439b6819 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -166,7 +166,9 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
"account_list": frappe.flags.round_off_applicable_accounts
},
callback(r) {
- frappe.flags.round_off_applicable_accounts.push(...r.message);
+ if (r.message) {
+ frappe.flags.round_off_applicable_accounts.push(...r.message);
+ }
}
});
}
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index b5337464ae..0ffda07cde 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -5,7 +5,7 @@ frappe.provide('erpnext.accounts.dimensions');
erpnext.TransactionController = class TransactionController extends erpnext.taxes_and_totals {
setup() {
- this._super();
+ super.setup();
frappe.flags.hide_serial_batch_dialog = true;
frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
diff --git a/erpnext/selling/doctype/installation_note/installation_note.js b/erpnext/selling/doctype/installation_note/installation_note.js
index ffa185baf6..27a3b35ccf 100644
--- a/erpnext/selling/doctype/installation_note/installation_note.js
+++ b/erpnext/selling/doctype/installation_note/installation_note.js
@@ -57,4 +57,4 @@ erpnext.selling.InstallationNote = class InstallationNote extends frappe.ui.form
}
};
-$.extend(cur_frm.cscript, new erpnext.selling.InstallationNote({frm: cur_frm}));
\ No newline at end of file
+extend_cscript(cur_frm.cscript, new erpnext.selling.InstallationNote({frm: cur_frm}));
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index d5ceca8ec8..b42c615312 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -104,7 +104,7 @@ frappe.ui.form.on("Sales Order Item", {
erpnext.selling.SalesOrderController = class SalesOrderController extends erpnext.selling.SellingController {
onload(doc, dt, dn) {
- super.onload();
+ super.onload(doc, dt, dn);
}
refresh(doc, dt, dn) {
@@ -744,4 +744,5 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex
});
}
};
-$.extend(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm}));
+
+extend_cscript(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm}));
diff --git a/erpnext/selling/doctype/sms_center/sms_center.js b/erpnext/selling/doctype/sms_center/sms_center.js
index dda28031df..974cfc7918 100644
--- a/erpnext/selling/doctype/sms_center/sms_center.js
+++ b/erpnext/selling/doctype/sms_center/sms_center.js
@@ -1,7 +1,7 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-$.extend(cur_frm.cscript, {
+extend_cscript(cur_frm.cscript, {
message: function () {
var total_characters = this.frm.doc.message.length;
var total_msg = 1;
diff --git a/erpnext/setup/doctype/currency_exchange/currency_exchange.js b/erpnext/setup/doctype/currency_exchange/currency_exchange.js
index a8ea55ca0c..85036a163e 100644
--- a/erpnext/setup/doctype/currency_exchange/currency_exchange.js
+++ b/erpnext/setup/doctype/currency_exchange/currency_exchange.js
@@ -1,30 +1,30 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-$.extend(cur_frm.cscript, {
+extend_cscript(cur_frm.cscript, {
onload: function() {
if(cur_frm.doc.__islocal) {
cur_frm.set_value("to_currency", frappe.defaults.get_global_default("currency"));
}
},
-
+
refresh: function() {
cur_frm.cscript.set_exchange_rate_label();
},
-
+
from_currency: function() {
cur_frm.cscript.set_exchange_rate_label();
},
-
+
to_currency: function() {
cur_frm.cscript.set_exchange_rate_label();
},
-
+
set_exchange_rate_label: function() {
if(cur_frm.doc.from_currency && cur_frm.doc.to_currency) {
var default_label = __(frappe.meta.docfield_map[cur_frm.doctype]["exchange_rate"].label);
- cur_frm.fields_dict.exchange_rate.set_label(default_label +
+ cur_frm.fields_dict.exchange_rate.set_label(default_label +
repl(" (1 %(from_currency)s = [?] %(to_currency)s)", cur_frm.doc));
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index b736015808..c3803f19a1 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -305,7 +305,7 @@ erpnext.stock.DeliveryNoteController = class DeliveryNoteController extends erpn
}
};
-$.extend(cur_frm.cscript, new erpnext.stock.DeliveryNoteController({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.stock.DeliveryNoteController({frm: cur_frm}));
frappe.ui.form.on('Delivery Note', {
setup: function(frm) {
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index f516e061c0..6585e1c78c 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -433,7 +433,7 @@ erpnext.buying.MaterialRequestController = class MaterialRequestController exten
if (doc.material_request_type == "Customer Provided") {
return{
query: "erpnext.controllers.queries.item_query",
- filters:{
+ filters:{
'customer': me.frm.doc.customer,
'is_stock_item':1
}
@@ -472,7 +472,7 @@ erpnext.buying.MaterialRequestController = class MaterialRequestController exten
};
// for backward compatibility: combine new and previous states
-$.extend(cur_frm.cscript, new erpnext.buying.MaterialRequestController({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.buying.MaterialRequestController({frm: cur_frm}));
function set_schedule_date(frm) {
if(frm.doc.schedule_date){
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index 688ae1d410..0182ed55a1 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -251,7 +251,7 @@ erpnext.stock.PurchaseReceiptController = class PurchaseReceiptController extend
};
// for backward compatibility: combine new and previous states
-$.extend(cur_frm.cscript, new erpnext.stock.PurchaseReceiptController({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.stock.PurchaseReceiptController({frm: cur_frm}));
cur_frm.cscript.update_status = function(status) {
frappe.ui.form.is_saving = true;
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 6afcd1f43e..700093fae3 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -1064,4 +1064,4 @@ erpnext.stock.select_batch_and_serial_no = (frm, item) => {
}
-$.extend(cur_frm.cscript, new erpnext.stock.StockEntry({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.stock.StockEntry({frm: cur_frm}));
diff --git a/erpnext/support/doctype/warranty_claim/warranty_claim.js b/erpnext/support/doctype/warranty_claim/warranty_claim.js
index c9aa41fdae..358768eb46 100644
--- a/erpnext/support/doctype/warranty_claim/warranty_claim.js
+++ b/erpnext/support/doctype/warranty_claim/warranty_claim.js
@@ -55,7 +55,7 @@ erpnext.support.WarrantyClaim = class WarrantyClaim extends frappe.ui.form.Contr
}
};
-$.extend(cur_frm.cscript, new erpnext.support.WarrantyClaim({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.support.WarrantyClaim({frm: cur_frm}));
cur_frm.fields_dict['serial_no'].get_query = function(doc, cdt, cdn) {
var cond = [];
@@ -93,4 +93,4 @@ cur_frm.fields_dict['item_code'].get_query = function(doc, cdt, cdn) {
]
}
}
-};
\ No newline at end of file
+};
From 3e6cc5037bb2b9084dab8d6e89d70532c8323bc8 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 21 May 2021 17:37:19 +0530
Subject: [PATCH 143/149] fix: Remove unnecessary code
---
erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index ea7432caa2..e464a783ad 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -450,11 +450,8 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
}
};
-console.log('innn')
// for backward compatibility: combine new and previous states
-let controller_instance = new erpnext.accounts.SalesInvoiceController({frm: cur_frm})
-extend_cscript(cur_frm.cscript, controller_instance);
-extend_cscript(cur_frm.cscript.__proto_, controller_instance.__proto__);
+extend_cscript(cur_frm.cscript, new erpnext.accounts.SalesInvoiceController({frm: cur_frm}));
cur_frm.cscript['Make Delivery Note'] = function() {
frappe.model.open_mapped_doc({
From 59961f70ee7185b346d72e0173db1030281bfc32 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 20 May 2021 23:43:19 +0530
Subject: [PATCH 144/149] refactor: timesheet
---
.../doctype/sales_invoice/sales_invoice.js | 90 +-
.../doctype/sales_invoice/sales_invoice.json | 10 +-
.../doctype/sales_invoice/sales_invoice.py | 24 +-
.../sales_invoice_timesheet.json | 234 +---
erpnext/patches.txt | 1 +
.../patches/v13_0/update_timesheet_changes.py | 25 +
.../v7_0/convert_timelog_to_timesheet.py | 2 +-
.../doctype/activity_type/activity_type.js | 4 +
.../doctype/timesheet/test_timesheet.py | 14 +-
.../projects/doctype/timesheet/timesheet.js | 169 ++-
.../projects/doctype/timesheet/timesheet.json | 58 +-
.../projects/doctype/timesheet/timesheet.py | 78 +-
.../timesheet_detail/timesheet_detail.json | 1192 ++++-------------
erpnext/projects/report/billing_summary.py | 4 +-
...ee_hours_utilization_based_on_timesheet.py | 6 +-
.../test_employee_util.py | 4 +-
.../test_project_profitability.py | 2 +-
erpnext/public/js/utils.js | 12 +
18 files changed, 697 insertions(+), 1232 deletions(-)
create mode 100644 erpnext/patches/v13_0/update_timesheet_changes.py
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index b48db246ac..9e1dbf4333 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -17,7 +17,7 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
var me = this;
super.onload();
- this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice'];
+ this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice', 'Timesheet'];
if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) {
// show debit_to in print format
this.frm.set_df_property("debit_to", "print_hide", 0);
@@ -685,14 +685,16 @@ frappe.ui.form.on('Sales Invoice', {
},
project: function(frm){
- frm.call({
- method: "add_timesheet_data",
- doc: frm.doc,
- callback: function(r, rt) {
- refresh_field(['timesheets'])
- }
- })
- frm.refresh();
+ if (!frm.doc.is_return) {
+ frm.call({
+ method: "add_timesheet_data",
+ doc: frm.doc,
+ callback: function(r, rt) {
+ refresh_field(['timesheets'])
+ }
+ })
+ frm.refresh();
+ }
},
onload: function(frm) {
@@ -807,14 +809,27 @@ frappe.ui.form.on('Sales Invoice', {
}
},
+ add_timesheet_row: function(frm, row, exchange_rate) {
+ frm.add_child('timesheets', {
+ 'activity_type': row.activity_type,
+ 'description': row.description,
+ 'time_sheet': row.parent,
+ 'billing_hours': row.billing_hours,
+ 'billing_amount': flt(row.billing_amount) * flt(exchange_rate),
+ 'timesheet_detail': row.name
+ });
+ frm.refresh_field('timesheets');
+ calculate_total_billing_amount(frm);
+ },
+
refresh: function(frm) {
- if (frm.doc.project) {
+ if (frm.doc.docstatus===0 && !frm.doc.is_return) {
frm.add_custom_button(__('Fetch Timesheet'), function() {
let d = new frappe.ui.Dialog({
title: __('Fetch Timesheet'),
fields: [
{
- "label" : "From",
+ "label" : __("From"),
"fieldname": "from_time",
"fieldtype": "Date",
"reqd": 1,
@@ -824,11 +839,18 @@ frappe.ui.form.on('Sales Invoice', {
fieldname: 'col_break_1',
},
{
- "label" : "To",
+ "label" : __("To"),
"fieldname": "to_time",
"fieldtype": "Date",
"reqd": 1,
- }
+ },
+ {
+ "label" : __("Project"),
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "options": "Project",
+ "default": frm.doc.project
+ },
],
primary_action: function() {
let data = d.get_values();
@@ -837,27 +859,35 @@ frappe.ui.form.on('Sales Invoice', {
args: {
from_time: data.from_time,
to_time: data.to_time,
- project: frm.doc.project
+ project: data.project
},
callback: function(r) {
- if(!r.exc) {
- if(r.message.length > 0) {
- frm.clear_table('timesheets')
- r.message.forEach((d) => {
- frm.add_child('timesheets',{
- 'time_sheet': d.parent,
- 'billing_hours': d.billing_hours,
- 'billing_amount': d.billing_amt,
- 'timesheet_detail': d.name
+ if (!r.exc && r.message.length > 0) {
+ frm.clear_table('timesheets')
+ r.message.forEach((d) => {
+ let exchange_rate = 1.0;
+ if (frm.doc.currency != d.currency) {
+ frappe.call({
+ method: 'erpnext.setup.utils.get_exchange_rate',
+ args: {
+ from_currency: d.currency,
+ to_currency: frm.doc.currency
+ },
+ callback: function(r) {
+ if (r.message) {
+ exchange_rate = r.message;
+ frm.events.add_timesheet_row(frm, d, exchange_rate);
+ }
+ }
});
- });
- frm.refresh_field('timesheets')
- }
- else {
- frappe.msgprint(__('No Timesheet Found.'))
- }
- d.hide();
+ } else {
+ frm.events.add_timesheet_row(frm, d, exchange_rate);
+ }
+ });
+ } else {
+ frappe.msgprint(__('No Timesheets found with the selected filters.'))
}
+ d.hide();
}
});
},
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index c6c67b4ddc..52bc409b6e 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -748,6 +748,7 @@
{
"collapsible": 1,
"collapsible_depends_on": "eval:doc.total_billing_amount > 0",
+ "depends_on": "eval: !doc.is_return",
"fieldname": "time_sheet_list",
"fieldtype": "Section Break",
"hide_days": 1,
@@ -770,6 +771,7 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Total Billing Amount",
+ "options": "currency",
"print_hide": 1,
"read_only": 1
},
@@ -1951,6 +1953,12 @@
"label": "Set Target Warehouse",
"options": "Warehouse"
},
+ {
+ "default": "0",
+ "fieldname": "is_debit_note",
+ "fieldtype": "Check",
+ "label": "Is Debit Note"
+ },
{
"default": "0",
"depends_on": "grand_total",
@@ -1969,7 +1977,7 @@
"link_fieldname": "consolidated_invoice"
}
],
- "modified": "2021-04-15 23:57:58.766651",
+ "modified": "2021-05-20 22:48:33.988881",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index bb74a02606..a008742390 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -125,6 +125,8 @@ class SalesInvoice(SellingController):
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount", "items")
if not self.is_return:
self.validate_serial_numbers()
+ else:
+ self.timesheets = []
self.update_packing_list()
self.set_billing_hours_and_amount()
self.update_timesheet_billing_for_project()
@@ -337,7 +339,7 @@ class SalesInvoice(SellingController):
if "Healthcare" in active_domains:
manage_invoice_submit_cancel(self, "on_cancel")
-
+ self.unlink_sales_invoice_from_timesheets()
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry', 'Repost Item Valuation')
def update_status_updater_args(self):
@@ -393,6 +395,18 @@ class SalesInvoice(SellingController):
if validate_against_credit_limit:
check_credit_limit(self.customer, self.company, bypass_credit_limit_check_at_sales_order)
+ def unlink_sales_invoice_from_timesheets(self):
+ for row in self.timesheets:
+ timesheet = frappe.get_doc('Timesheet', row.time_sheet)
+ for time_log in timesheet.time_logs:
+ if time_log.sales_invoice == self.name:
+ time_log.sales_invoice = None
+ timesheet.calculate_total_amounts()
+ timesheet.calculate_percentage_billed()
+ timesheet.flags.ignore_validate_update_after_submit = True
+ timesheet.set_status()
+ timesheet.db_update_all()
+
@frappe.whitelist()
def set_missing_values(self, for_validate=False):
pos = self.set_pos_fields(for_validate)
@@ -427,7 +441,7 @@ class SalesInvoice(SellingController):
timesheet.calculate_percentage_billed()
timesheet.flags.ignore_validate_update_after_submit = True
timesheet.set_status()
- timesheet.save()
+ timesheet.db_update_all()
def update_time_sheet_detail(self, timesheet, args, sales_invoice):
for data in timesheet.time_logs:
@@ -741,8 +755,10 @@ class SalesInvoice(SellingController):
self.append('timesheets', {
'time_sheet': data.parent,
'billing_hours': data.billing_hours,
- 'billing_amount': data.billing_amt,
- 'timesheet_detail': data.name
+ 'billing_amount': data.billing_amount,
+ 'timesheet_detail': data.name,
+ 'activity_type': data.activity_type,
+ 'description': data.description
})
self.calculate_billing_amount_for_timesheet()
diff --git a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json
index f7b9aef96c..f069e8dd0b 100644
--- a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json
+++ b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json
@@ -1,172 +1,78 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2016-06-14 19:21:34.321662",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2016-06-14 19:21:34.321662",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "activity_type",
+ "description",
+ "billing_hours",
+ "billing_amount",
+ "time_sheet",
+ "timesheet_detail"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "time_sheet",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Time Sheet",
- "length": 0,
- "no_copy": 0,
- "options": "Timesheet",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "time_sheet",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "label": "Time Sheet",
+ "options": "Timesheet",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "billing_hours",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Billing Hours",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "billing_hours",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Billing Hours",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "billing_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Billing Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "billing_amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Billing Amount",
+ "options": "currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "timesheet_detail",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Timesheet Detail",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "allow_on_submit": 1,
+ "fieldname": "timesheet_detail",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Timesheet Detail",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "activity_type",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Activity Type",
+ "options": "Activity Type",
+ "read_only": 1
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "in_list_view": 1,
+ "label": "Description",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2019-02-18 18:50:44.770361",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Sales Invoice Timesheet",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-20 22:33:57.234846",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Sales Invoice Timesheet",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 82d223cada..f94644ddff 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -778,3 +778,4 @@ erpnext.patches.v12_0.add_ewaybill_validity_field
erpnext.patches.v13_0.germany_make_custom_fields
erpnext.patches.v13_0.germany_fill_debtor_creditor_number
erpnext.patches.v13_0.set_pos_closing_as_failed
+erpnext.patches.v13_0.update_timesheet_changes
diff --git a/erpnext/patches/v13_0/update_timesheet_changes.py b/erpnext/patches/v13_0/update_timesheet_changes.py
new file mode 100644
index 0000000000..93b7f8e59a
--- /dev/null
+++ b/erpnext/patches/v13_0/update_timesheet_changes.py
@@ -0,0 +1,25 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.model.utils.rename_field import rename_field
+
+def execute():
+ frappe.reload_doc("projects", "doctype", "timesheet")
+ frappe.reload_doc("projects", "doctype", "timesheet_detail")
+
+ if frappe.db.has_column("Timesheet Detail", "billable"):
+ rename_field("Timesheet Detail", "billable", "is_billable")
+
+ base_currency = frappe.defaults.get_global_default('currency')
+
+ frappe.db.sql("""UPDATE `tabTimesheet Detail`
+ SET base_billing_rate = billing_rate,
+ base_billing_amount = billing_amount,
+ base_costing_rate = costing_rate,
+ base_costing_amount = costing_amount""")
+
+ frappe.db.sql("""UPDATE `tabTimesheet`
+ SET currency = '{0}',
+ exchange_rate = 1.0,
+ base_total_billable_amount = total_billable_amount,
+ base_total_billed_amount = total_billed_amount,
+ base_total_costing_amount = total_costing_amount""".format(base_currency))
\ No newline at end of file
diff --git a/erpnext/patches/v7_0/convert_timelog_to_timesheet.py b/erpnext/patches/v7_0/convert_timelog_to_timesheet.py
index 3af6622d96..8c60b5b71e 100644
--- a/erpnext/patches/v7_0/convert_timelog_to_timesheet.py
+++ b/erpnext/patches/v7_0/convert_timelog_to_timesheet.py
@@ -51,7 +51,7 @@ def execute():
def get_timelog_data(data):
return {
- 'billable': data.billable,
+ 'is_billable': data.billable,
'from_time': data.from_time,
'hours': data.hours,
'to_time': data.to_time,
diff --git a/erpnext/projects/doctype/activity_type/activity_type.js b/erpnext/projects/doctype/activity_type/activity_type.js
index 7eb3571af1..f1ba882812 100644
--- a/erpnext/projects/doctype/activity_type/activity_type.js
+++ b/erpnext/projects/doctype/activity_type/activity_type.js
@@ -1,4 +1,8 @@
frappe.ui.form.on("Activity Type", {
+ onload: function(frm) {
+ frm.set_currency_labels(["billing_rate", "costing_rate"], frappe.defaults.get_global_default('currency'));
+ },
+
refresh: function(frm) {
frm.add_custom_button(__("Activity Cost per Employee"), function() {
frappe.route_options = {"activity_type": frm.doc.name};
diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py
index d21ac0f2f0..2b0c3abdd7 100644
--- a/erpnext/projects/doctype/timesheet/test_timesheet.py
+++ b/erpnext/projects/doctype/timesheet/test_timesheet.py
@@ -37,7 +37,7 @@ class TestTimesheet(unittest.TestCase):
emp = make_employee("test_employee_6@salary.com")
make_salary_structure_for_timesheet(emp)
- timesheet = make_timesheet(emp, simulate=True, billable=1)
+ timesheet = make_timesheet(emp, simulate=True, is_billable=1)
self.assertEqual(timesheet.total_hours, 2)
self.assertEqual(timesheet.total_billable_hours, 2)
@@ -49,7 +49,7 @@ class TestTimesheet(unittest.TestCase):
emp = make_employee("test_employee_6@salary.com")
make_salary_structure_for_timesheet(emp)
- timesheet = make_timesheet(emp, simulate=True, billable=0)
+ timesheet = make_timesheet(emp, simulate=True, is_billable=0)
self.assertEqual(timesheet.total_hours, 2)
self.assertEqual(timesheet.total_billable_hours, 0)
@@ -61,7 +61,7 @@ class TestTimesheet(unittest.TestCase):
emp = make_employee("test_employee_6@salary.com", company="_Test Company")
salary_structure = make_salary_structure_for_timesheet(emp)
- timesheet = make_timesheet(emp, simulate = True, billable=1)
+ timesheet = make_timesheet(emp, simulate = True, is_billable=1)
salary_slip = make_salary_slip(timesheet.name)
salary_slip.submit()
@@ -82,7 +82,7 @@ class TestTimesheet(unittest.TestCase):
def test_sales_invoice_from_timesheet(self):
emp = make_employee("test_employee_6@salary.com")
- timesheet = make_timesheet(emp, simulate=True, billable=1)
+ timesheet = make_timesheet(emp, simulate=True, is_billable=1)
sales_invoice = make_sales_invoice(timesheet.name, '_Test Item', '_Test Customer')
sales_invoice.due_date = nowdate()
sales_invoice.submit()
@@ -100,7 +100,7 @@ class TestTimesheet(unittest.TestCase):
emp = make_employee("test_employee_6@salary.com")
project = frappe.get_value("Project", {"project_name": "_Test Project"})
- timesheet = make_timesheet(emp, simulate=True, billable=1, project=project, company='_Test Company')
+ timesheet = make_timesheet(emp, simulate=True, is_billable=1, project=project, company='_Test Company')
sales_invoice = create_sales_invoice(do_not_save=True)
sales_invoice.project = project
sales_invoice.submit()
@@ -171,13 +171,13 @@ def make_salary_structure_for_timesheet(employee, company=None):
return salary_structure
-def make_timesheet(employee, simulate=False, billable = 0, activity_type="_Test Activity Type", project=None, task=None, company=None):
+def make_timesheet(employee, simulate=False, is_billable = 0, activity_type="_Test Activity Type", project=None, task=None, company=None):
update_activity_type(activity_type)
timesheet = frappe.new_doc("Timesheet")
timesheet.employee = employee
timesheet.company = company or '_Test Company'
timesheet_detail = timesheet.append('time_logs', {})
- timesheet_detail.billable = billable
+ timesheet_detail.is_billable = is_billable
timesheet_detail.activity_type = activity_type
timesheet_detail.from_time = now_datetime()
timesheet_detail.hours = 2
diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js
index 43a57e5d4a..84c7b8118b 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.js
+++ b/erpnext/projects/doctype/timesheet/timesheet.js
@@ -90,17 +90,99 @@ frappe.ui.form.on("Timesheet", {
}
if(frm.doc.per_billed > 0) {
frm.fields_dict["time_logs"].grid.toggle_enable("billing_hours", false);
- frm.fields_dict["time_logs"].grid.toggle_enable("billable", false);
+ frm.fields_dict["time_logs"].grid.toggle_enable("is_billable", false);
}
+ frm.trigger('setup_filters');
+ frm.trigger('set_dynamic_field_label');
+ },
+
+ customer: function(frm) {
+ frm.set_query('parent_project', function(doc) {
+ return {
+ filters: {
+ "customer": doc.customer
+ }
+ };
+ });
+ frm.set_query('project', 'time_logs', function(doc) {
+ return {
+ filters: {
+ "customer": doc.customer
+ }
+ };
+ });
+ frm.refresh();
+ },
+
+ currency: function(frm) {
+ let base_currency = frappe.defaults.get_global_default('currency');
+ if (base_currency != frm.doc.currency) {
+ frappe.call({
+ method: "erpnext.setup.utils.get_exchange_rate",
+ args: {
+ from_currency: frm.doc.currency,
+ to_currency: base_currency
+ },
+ callback: function(r) {
+ if (r.message) {
+ frm.set_value('exchange_rate', flt(r.message));
+ frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency + " = [?] " + base_currency);
+ }
+ }
+ });
+ }
+ frm.trigger('set_dynamic_field_label');
+ },
+
+ exchange_rate: function(frm) {
+ $.each(frm.doc.time_logs, function(i, d) {
+ calculate_billing_costing_amount(frm, d.doctype, d.name);
+ });
+ calculate_time_and_amount(frm);
+ },
+
+ set_dynamic_field_label: function(frm) {
+ let base_currency = frappe.defaults.get_global_default('currency');
+ frm.set_currency_labels(["base_total_costing_amount", "base_total_billable_amount", "base_total_billed_amount"], base_currency);
+ frm.set_currency_labels(["total_costing_amount", "total_billable_amount", "total_billed_amount"], frm.doc.currency);
+
+ frm.toggle_display(["base_total_costing_amount", "base_total_billable_amount", "base_total_billed_amount"],
+ frm.doc.currency != base_currency);
+
+ if (frm.doc.time_logs.length > 0) {
+ frm.set_currency_labels(["base_billing_rate", "base_billing_amount", "base_costing_rate", "base_costing_amount"], base_currency, "time_logs");
+ frm.set_currency_labels(["billing_rate", "billing_amount", "costing_rate", "costing_amount"], frm.doc.currency, "time_logs");
+
+ let time_logs_grid = frm.fields_dict.time_logs.grid;
+ $.each(["base_billing_rate", "base_billing_amount", "base_costing_rate", "base_costing_amount"], function(i, d) {
+ if (frappe.meta.get_docfield(time_logs_grid.doctype, d))
+ time_logs_grid.set_column_disp(d, frm.doc.currency != base_currency);
+ });
+ }
+ frm.refresh_fields();
},
make_invoice: function(frm) {
+ let fields = [{
+ "fieldtype": "Link",
+ "label": __("Item Code"),
+ "fieldname": "item_code",
+ "options": "Item"
+ }];
+
+ if (!frm.doc.customer) {
+ fields.push({
+ "fieldtype": "Link",
+ "label": __("Customer"),
+ "fieldname": "customer",
+ "options": "Customer",
+ "default": frm.doc.customer
+ });
+ }
+
let dialog = new frappe.ui.Dialog({
- title: __("Select Item (optional)"),
- fields: [
- {"fieldtype": "Link", "label": __("Item Code"), "fieldname": "item_code", "options":"Item"},
- {"fieldtype": "Link", "label": __("Customer"), "fieldname": "customer", "options":"Customer"}
- ]
+ title: __("Create Sales Invoice"),
+ fields: fields
});
dialog.set_primary_action(__('Create Sales Invoice'), () => {
@@ -113,7 +195,8 @@ frappe.ui.form.on("Timesheet", {
args: {
"source_name": frm.doc.name,
"item_code": args.item_code,
- "customer": args.customer
+ "customer": frm.doc.customer || args.customer,
+ "currency": frm.doc.currency
},
freeze: true,
callback: function(r) {
@@ -136,8 +219,7 @@ frappe.ui.form.on("Timesheet", {
parent_project: function(frm) {
set_project_in_timelog(frm);
- },
-
+ }
});
frappe.ui.form.on("Timesheet Detail", {
@@ -171,36 +253,34 @@ frappe.ui.form.on("Timesheet Detail", {
if(frm.doc.parent_project) {
frappe.model.set_value(cdt, cdn, 'project', frm.doc.parent_project);
}
-
- var $trigger_again = $('.form-grid').find('.grid-row').find('.btn-open-row');
- $trigger_again.on('click', () => {
- let $timer = $('.form-grid').find('[data-fieldname="timer"]');
- if ($timer.get(0)) {
- $timer.append(frappe.render_template("timesheet"));
- }
- frm.trigger("control_timer");
- });
},
+
hours: function(frm, cdt, cdn) {
calculate_end_time(frm, cdt, cdn);
+ calculate_billing_costing_amount(frm, cdt, cdn);
+ calculate_time_and_amount(frm);
},
billing_hours: function(frm, cdt, cdn) {
calculate_billing_costing_amount(frm, cdt, cdn);
+ calculate_time_and_amount(frm);
},
billing_rate: function(frm, cdt, cdn) {
calculate_billing_costing_amount(frm, cdt, cdn);
+ calculate_time_and_amount(frm);
},
costing_rate: function(frm, cdt, cdn) {
calculate_billing_costing_amount(frm, cdt, cdn);
+ calculate_time_and_amount(frm);
},
- billable: function(frm, cdt, cdn) {
+ is_billable: function(frm, cdt, cdn) {
update_billing_hours(frm, cdt, cdn);
update_time_rates(frm, cdt, cdn);
calculate_billing_costing_amount(frm, cdt, cdn);
+ calculate_time_and_amount(frm);
},
activity_type: function(frm, cdt, cdn) {
@@ -208,7 +288,8 @@ frappe.ui.form.on("Timesheet Detail", {
method: "erpnext.projects.doctype.timesheet.timesheet.get_activity_cost",
args: {
employee: frm.doc.employee,
- activity_type: frm.selected_doc.activity_type
+ activity_type: frm.selected_doc.activity_type,
+ currency: frm.doc.currency
},
callback: function(r){
if(r.message){
@@ -240,9 +321,9 @@ var calculate_end_time = function(frm, cdt, cdn) {
}
};
-var update_billing_hours = function(frm, cdt, cdn){
- var child = locals[cdt][cdn];
- if(!child.billable) {
+var update_billing_hours = function(frm, cdt, cdn) {
+ let child = frappe.get_doc(cdt, cdn);
+ if (!child.is_billable) {
frappe.model.set_value(cdt, cdn, 'billing_hours', 0.0);
} else {
// bill all hours by default
@@ -250,40 +331,44 @@ var update_billing_hours = function(frm, cdt, cdn){
}
};
-var update_time_rates = function(frm, cdt, cdn){
- var child = locals[cdt][cdn];
- if(!child.billable){
+var update_time_rates = function(frm, cdt, cdn) {
+ let child = frappe.get_doc(cdt, cdn);
+ if (!child.is_billable) {
frappe.model.set_value(cdt, cdn, 'billing_rate', 0.0);
}
};
-var calculate_billing_costing_amount = function(frm, cdt, cdn){
- var child = locals[cdt][cdn];
- var billing_amount = 0.0;
- var costing_amount = 0.0;
-
- if(child.billing_hours && child.billable){
- billing_amount = (child.billing_hours * child.billing_rate);
+var calculate_billing_costing_amount = function(frm, cdt, cdn) {
+ let row = frappe.get_doc(cdt, cdn);
+ let billing_amount = 0.0;
+ let base_billing_amount = 0.0;
+ let exchange_rate = flt(frm.doc.exchange_rate);
+ frappe.model.set_value(cdt, cdn, 'base_billing_rate', flt(row.billing_rate) * exchange_rate);
+ frappe.model.set_value(cdt, cdn, 'base_costing_rate', flt(row.costing_rate) * exchange_rate);
+ if (row.billing_hours && row.is_billable) {
+ base_billing_amount = flt(row.billing_hours) * flt(row.base_billing_rate);
+ billing_amount = flt(row.billing_hours) * flt(row.billing_rate);
}
- costing_amount = flt(child.costing_rate * child.hours);
+
+ frappe.model.set_value(cdt, cdn, 'base_billing_amount', base_billing_amount);
+ frappe.model.set_value(cdt, cdn, 'base_costing_amount', flt(row.base_costing_rate) * flt(row.hours));
frappe.model.set_value(cdt, cdn, 'billing_amount', billing_amount);
- frappe.model.set_value(cdt, cdn, 'costing_amount', costing_amount);
- calculate_time_and_amount(frm);
+ frappe.model.set_value(cdt, cdn, 'costing_amount', flt(row.costing_rate) * flt(row.hours));
};
var calculate_time_and_amount = function(frm) {
- var tl = frm.doc.time_logs || [];
- var total_working_hr = 0;
- var total_billing_hr = 0;
- var total_billable_amount = 0;
- var total_costing_amount = 0;
+ let tl = frm.doc.time_logs || [];
+ let total_working_hr = 0;
+ let total_billing_hr = 0;
+ let total_billable_amount = 0;
+ let total_costing_amount = 0;
for(var i=0; i
Date: Sun, 23 May 2021 13:31:54 +0530
Subject: [PATCH 145/149] fix: Rename email.bundle to erpnext_email.bundle
to avoid override of frappe email styles
---
erpnext/hooks.py | 2 +-
.../scss/{email.bundle.scss => erpnext_email.bundle.scss} | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename erpnext/public/scss/{email.bundle.scss => erpnext_email.bundle.scss} (100%)
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 3024819d76..a1d37e2812 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -19,7 +19,7 @@ app_include_js = "erpnext.bundle.js"
app_include_css = "erpnext.bundle.css"
web_include_js = "erpnext-web.bundle.js"
web_include_css = "erpnext-web.bundle.css"
-email_css = "email.bundle.css"
+email_css = "email_erpnext.bundle.css"
doctype_js = {
"Address": "public/js/address.js",
diff --git a/erpnext/public/scss/email.bundle.scss b/erpnext/public/scss/erpnext_email.bundle.scss
similarity index 100%
rename from erpnext/public/scss/email.bundle.scss
rename to erpnext/public/scss/erpnext_email.bundle.scss
From 6368c976c7f1825fb2a11b098b0d4fbc6b6a276e Mon Sep 17 00:00:00 2001
From: Saqib
Date: Tue, 18 May 2021 18:39:35 +0530
Subject: [PATCH 146/149] fix: expected amount in pos closing payments table
(#25737)
---
.../pos_closing_entry/pos_closing_entry.js | 39 ++++++++++++-------
1 file changed, 24 insertions(+), 15 deletions(-)
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
index aa0c53e228..8c5a34a0d8 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
@@ -101,15 +101,24 @@ frappe.ui.form.on('POS Closing Entry', {
},
before_save: function(frm) {
+ frm.set_value("grand_total", 0);
+ frm.set_value("net_total", 0);
+ frm.set_value("total_quantity", 0);
+ frm.set_value("taxes", []);
+
+ for (let row of frm.doc.payment_reconciliation) {
+ row.expected_amount = 0;
+ }
+
for (let row of frm.doc.pos_transactions) {
frappe.db.get_doc("POS Invoice", row.pos_invoice).then(doc => {
- cur_frm.doc.grand_total -= flt(doc.grand_total);
- cur_frm.doc.net_total -= flt(doc.net_total);
- cur_frm.doc.total_quantity -= flt(doc.total_qty);
- refresh_payments(doc, cur_frm, 1);
- refresh_taxes(doc, cur_frm, 1);
- refresh_fields(cur_frm);
- set_html_data(cur_frm);
+ frm.doc.grand_total += flt(doc.grand_total);
+ frm.doc.net_total += flt(doc.net_total);
+ frm.doc.total_quantity += flt(doc.total_qty);
+ refresh_payments(doc, frm);
+ refresh_taxes(doc, frm);
+ refresh_fields(frm);
+ set_html_data(frm);
});
}
}
@@ -118,7 +127,7 @@ frappe.ui.form.on('POS Closing Entry', {
frappe.ui.form.on('POS Closing Entry Detail', {
closing_amount: (frm, cdt, cdn) => {
const row = locals[cdt][cdn];
- frappe.model.set_value(cdt, cdn, "difference", flt(row.expected_amount - row.closing_amount))
+ frappe.model.set_value(cdt, cdn, "difference", flt(row.expected_amount - row.closing_amount));
}
})
@@ -142,28 +151,28 @@ function add_to_pos_transaction(d, frm) {
})
}
-function refresh_payments(d, frm, remove) {
+function refresh_payments(d, frm) {
d.payments.forEach(p => {
const payment = frm.doc.payment_reconciliation.find(pay => pay.mode_of_payment === p.mode_of_payment);
if (payment) {
- if (!remove) payment.expected_amount += flt(p.amount);
- else payment.expected_amount -= flt(p.amount);
+ payment.expected_amount += flt(p.amount);
+ payment.difference = payment.closing_amount - payment.expected_amount;
} else {
frm.add_child("payment_reconciliation", {
mode_of_payment: p.mode_of_payment,
opening_amount: 0,
- expected_amount: p.amount
+ expected_amount: p.amount,
+ closing_amount: 0
})
}
})
}
-function refresh_taxes(d, frm, remove) {
+function refresh_taxes(d, frm) {
d.taxes.forEach(t => {
const tax = frm.doc.taxes.find(tx => tx.account_head === t.account_head && tx.rate === t.rate);
if (tax) {
- if (!remove) tax.amount += flt(t.tax_amount);
- else tax.amount -= flt(t.tax_amount);
+ tax.amount += flt(t.tax_amount);
} else {
frm.add_child("taxes", {
account_head: t.account_head,
From 10085580c86f9fcfb4cc96e5265665b422baa987 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Mon, 24 May 2021 17:05:27 +0550
Subject: [PATCH 147/149] bumped to version 13.3.1
---
erpnext/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index ad971e2976..8d1767497f 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
-__version__ = '13.3.0'
+__version__ = '13.3.1'
def get_default_company(user=None):
'''Get default company for user'''
From 45bc14408e5313a339130181f00d55c414b59de4 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 25 May 2021 15:57:33 +0530
Subject: [PATCH 148/149] refactor: Remove redundant variables.scss import
---
erpnext/public/scss/erpnext.scss | 46 +++++++++----------
erpnext/public/scss/erpnext_email.bundle.scss | 14 +++---
2 files changed, 28 insertions(+), 32 deletions(-)
diff --git a/erpnext/public/scss/erpnext.scss b/erpnext/public/scss/erpnext.scss
index 0e6186138f..8ab5973deb 100644
--- a/erpnext/public/scss/erpnext.scss
+++ b/erpnext/public/scss/erpnext.scss
@@ -1,5 +1,3 @@
-@import "frappe/public/scss/desk/variables";
-
.erpnext-footer {
margin: 11px auto;
text-align: center;
@@ -141,7 +139,7 @@ body[data-route="pos"] {
}
.pos-payment-row {
- border-bottom:1px solid $border-color;
+ border-bottom:1px solid var(--border-color);
margin: 2px 0px 5px 0px;
height: 60px;
margin-top: 0px;
@@ -154,7 +152,7 @@ body[data-route="pos"] {
}
.pos-keyboard-key, .delete-btn {
- border: 1px solid $border-color;
+ border: 1px solid var(--border-color);
height:85px;
width:85px;
margin:10px 10px;
@@ -165,7 +163,7 @@ body[data-route="pos"] {
}
.numeric-keypad {
- border: 1px solid $border-color;
+ border: 1px solid var(--border-color);
height:69px;
width:69px;
font-size:20px;
@@ -192,13 +190,13 @@ body[data-route="pos"] {
background-color: #fff;
margin-left:-4px;
- @media (max-width: map-get($grid-breakpoints, "xl")) {
+ @media (max-width: var(--xl-width)) {
height: 45px;
width: 45px;
font-size: 14px;
}
- @media (max-width: map-get($grid-breakpoints, "lg")) {
+ @media (max-width: var(--lg-width)) {
height: 40px;
width: 40px;
}
@@ -209,16 +207,16 @@ body[data-route="pos"] {
& > .row > button {
border: none;
- border-right: 1px solid $border-color;
- border-bottom: 1px solid $border-color;
+ border-right: 1px solid var(--border-color);
+ border-bottom: 1px solid var(--border-color);
&:first-child {
- border-left: 1px solid $border-color;
+ border-left: 1px solid var(--border-color);
}
}
& > .row:first-child > button {
- border-top: 1px solid $border-color;
+ border-top: 1px solid var(--border-color);
}
}
@@ -236,13 +234,13 @@ body[data-route="pos"] {
}
.list-row-head.pos-invoice-list {
- border-top: 1px solid $border-color;
+ border-top: 1px solid var(--border-color);
}
.modal-dialog {
width: 750px;
- @media (max-width: map-get($grid-breakpoints, 'md')) {
+ @media (max-width: var(--md-width)) {
width: auto;
.modal-content {
@@ -251,7 +249,7 @@ body[data-route="pos"] {
}
}
- @media (max-width: map-get($grid-breakpoints, 'md')) {
+ @media (max-width: var(--md-width)) {
.amount-row h3 {
font-size: 15px;
}
@@ -291,7 +289,7 @@ body[data-route="pos"] {
padding: 9px 15px;
font-size: 12px;
margin: 0px;
- border-bottom: 1px solid $border-color;
+ border-bottom: 1px solid var(--border-color);
.cell {
display: table-cell;
@@ -313,7 +311,7 @@ body[data-route="pos"] {
.pos-bill-header {
background-color: #f5f7fa;
- border: 1px solid $border-color;
+ border: 1px solid var(--border-color);
padding: 13px 15px;
}
@@ -322,8 +320,8 @@ body[data-route="pos"] {
}
.totals-area {
- border-right: 1px solid $border-color;
- border-left: 1px solid $border-color;
+ border-right: 1px solid var(--border-color);
+ border-left: 1px solid var(--border-color);
margin-bottom: 15px;
}
@@ -334,10 +332,10 @@ body[data-route="pos"] {
.item-cart-items {
height: calc(100vh - 526px);
overflow: auto;
- border: 1px solid $border-color;
+ border: 1px solid var(--border-color);
border-top: none;
- @media (max-width: map-get($grid-breakpoints, 'md')) {
+ @media (max-width: var(--md-width)) {
height: 30vh;
}
}
@@ -359,12 +357,12 @@ body[data-route="pos"] {
}
.item-list {
- border: 1px solid $border-color;
+ border: 1px solid var(--border-color);
border-top: none;
max-height: calc(100vh - 190px);
overflow: auto;
- @media (max-width: map-get($grid-breakpoints, 'md')) {
+ @media (max-width: var(--md-width)) {
max-height: initial;
}
@@ -402,7 +400,7 @@ body[data-route="pos"] {
&> .pos-list-row {
border: none;
- @media (max-width: map-get($grid-breakpoints, 'xl')) {
+ @media (max-width: var(--xl-width)) {
padding: 5px 15px;
}
}
@@ -428,7 +426,7 @@ body[data-route="pos"] {
cursor: pointer;
}
- @media (max-width: map-get($grid-breakpoints, 'md')) {
+ @media (max-width: var(--md-width)) {
.page-actions {
max-width: 110px;
}
diff --git a/erpnext/public/scss/erpnext_email.bundle.scss b/erpnext/public/scss/erpnext_email.bundle.scss
index 3c0b918dae..d94e74a3ae 100644
--- a/erpnext/public/scss/erpnext_email.bundle.scss
+++ b/erpnext/public/scss/erpnext_email.bundle.scss
@@ -1,14 +1,12 @@
-@import "frappe/public/scss/desk/variables";
-
.panel-header {
background-color: var(--bg-color);
- border: 1px solid $border-color;
+ border: 1px solid var(--border-color);
border-radius: 3px 3px 0 0;
}
.panel-body {
- background-color: #fff;
- border: 1px solid $border-color;
+ background-color: white;
+ border: 1px solid var(--border-color);
border-top: none;
border-radius: 0 0 3px 3px;
overflow-wrap: break-word;
@@ -26,7 +24,7 @@
line-height: 24px;
text-align: center;
- color: $border-color;
- border: 1px solid $border-color;
- background-color: #fff;
+ color: var(--border-color);
+ border: 1px solid var(--border-color);
+ background-color: white;
}
From 59769c7a8685fb22ba18cccd9283e2e912784b59 Mon Sep 17 00:00:00 2001
From: Anupam Kumar
Date: Wed, 26 May 2021 12:16:04 +0530
Subject: [PATCH 149/149] fix: student invalid password reset link (#25825)
---
erpnext/education/doctype/student/student.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/erpnext/education/doctype/student/student.py b/erpnext/education/doctype/student/student.py
index 2dc0f634f0..6be9e7104b 100644
--- a/erpnext/education/doctype/student/student.py
+++ b/erpnext/education/doctype/student/student.py
@@ -74,7 +74,6 @@ class Student(Document):
student_user.flags.ignore_permissions = True
student_user.add_roles("Student")
student_user.save()
- update_password_link = student_user.reset_password()
def update_applicant_status(self):
"""Updates Student Applicant status to Admitted"""