Date: Fri, 23 Apr 2021 08:04:00 +0530
Subject: [PATCH 013/115] 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 37b03f3f0e0..2f8d3e31d95 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 6b07197ec10..dd91fec3c17 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 493bd448024..72d587afb5f 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 06aa20bfc5a..b31cdce0b2f 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 b361c0c3457..8e8f85a3e48 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 dd0f0658485..c0e19e9c3d0 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 b76c3784a47..ee0e1ef576c 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 a0187b0a824..a3ba52e67b2 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 0c88d2826f7..8dfee1d6c72 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 ac374a95f4e..925c30b4516 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 b59d8488285..68e7780039b 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 b49b00e219b..06146047eb3 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 c21d4b893cc..5639cc9ea46 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 3205a92b1b6..ab965d54e3b 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 29aa85484a8..bbafc820764 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 ddbcdfde57e..2adfaf45ef1 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 4cbb02a5b3f..12dc59ccfce 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 fbfd801a114..2b329448fba 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 757f33eecce..413a5ee9719 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 67b12fbca4f..8ceae836207 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 87b21b78de8..d346357a8f8 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 3a3ee3858bf..448bb653642 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 1c0abdffcfc..a4c165e9ee7 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 0d656bc1fb6..7df976c1be7 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 140c9dc90b6..c74b45e6db6 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 832fd3eccf6..752fafdb971 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 9548d6c5f36..1c3e3147976 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 ebe6cd98f81..efb8dd9d5ca 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 27ef107acef..7e0198d33b3 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 d04c488a59d..9fc264086a3 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 d49a8138fb5..d44c7083563 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 7fd0877d11a..ffa185baf6d 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 5a0d9c90655..10606bf81e1 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 e3b41e66fbc..d5ceca8ec83 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 04285735abd..eb02867720c 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 95cb92b1b36..30e0b762bd5 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 334bdeac9d3..63ea198c599 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 1abbc35334f..433f78adc96 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 527b0d3ea93..86936b4db37 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 57cc3504a90..f87b273d64c 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 64dcbed1d85..16e74636cee 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 ac4ed5e75d9..3badc7ee60c 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 79f46758d12..c9aa41fdaef 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 b56c416dbde..37beb5a584b 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/115] 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 1a215031c1a..a5ca7eee5d4 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/115] 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 5ad2d852326..9139d84facc 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 1396f19d3f6..e4cdcb41163 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/115] 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 ed523939232..59c253c425b 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/115] 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 e4cdcb41163..2029b0708a6 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/115] 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 3fc1df76bc3..98d08c0a185 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/115] 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 98d08c0a185..3832415db62 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/115] 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 444b40ed798..db605f7285a 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 384f4b5b7e6d23436046d0f84888c5687cdca7f7 Mon Sep 17 00:00:00 2001
From: Saqib
Date: Tue, 4 May 2021 12:33:49 +0530
Subject: [PATCH 022/115] 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 09479221fbb..1363b53746a 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 0c4a4224407..094f5db89b9 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/115] 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 087c12ed2df..01927c2d10f 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 6dfede45906..bbd73e91129 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/115] 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 709fe577477..9384ae5542f 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 18ad15ed160ce209cea7b6da7cc6fc07fb3ee152 Mon Sep 17 00:00:00 2001
From: Asharam Seervi
Date: Tue, 4 May 2021 19:28:07 +0530
Subject: [PATCH 025/115] 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 4c3888be4aa..bab6b90d1aa 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 026/115] 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 f91b432a394..d218a5ee5f0 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 027/115] 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 b686dc026c6..3f2d3390c05 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 028/115] 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 d218a5ee5f0..10c802c6f07 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 029/115] 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 4461f29fe37..4de877353aa 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 030/115] 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 10c802c6f07..0af8da77a0c 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 031/115] 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 cf6ec18f3b8..6635128f9ef 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 032/115] 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 16eea24f847..f9b2c1d7876 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 c02dd2e518d..5ecc9f81405 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 00000000000..e69de29bb2d
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 00000000000..616312e3118
--- /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 00000000000..e20e74c78b7
--- /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 00000000000..c3339fd341e
--- /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 bbfcb7ad7d1..9729987d2d3 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 d502f763197b9d3891c4c2e498c132a87d35ee19 Mon Sep 17 00:00:00 2001
From: Saqib
Date: Thu, 6 May 2021 16:10:55 +0530
Subject: [PATCH 033/115] 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 23f9fd8ecbe..7faaf261587 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 00000000000..87d98f1a563
--- /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 699441be7e6..b4e7a8889ef 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 9ded8dab5bc..b12e152b14e 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 034/115] 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 49ca9423e8d..51d86ff0bf8 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 035/115] 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 9ea616f8e77..aa0c53e228b 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 a9b91e02a9d..4d6e4a2ba07 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 1065168a50c..82528728ddc 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 20fd610899e..cffeb4d5351 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 4d5472df4b4..bc7874305c0 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 5276da97200..4bb6138e5d7 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 7faaf261587..82d223cada0 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 00000000000..1c576db1c7e
--- /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 695becdd0569aac2bb57e0c87b9d4234b3ca9647 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Thu, 6 May 2021 18:03:32 +0530
Subject: [PATCH 036/115] 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 48cfa51041d..2f76bc7d56a 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 134eaa5786745fc9930a795b74f0461e353363ac Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Thu, 6 May 2021 19:13:54 +0530
Subject: [PATCH 037/115] 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 06068238213..1be2fbf5c81 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 0e3b24cda3d..927adc7086c 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 5593466fc2b..4d3388090dc 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 a85d3e70f34..658380ea429 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 2cef5092767..539a360269f 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 5efa41db1f7..459b7eacb43 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 d2978838763..b219e7ecce0 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 76a84508291..e5872171815 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 373b0a58c98..c1f9433b411 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 5053c6a5124..5c725d332de 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 e74d837ef5c..f63d2695aa3 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 3b9608b8056..2dd7c6f35b8 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 038/115] 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 fbfd801a114..a09a5e34300 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 979f7ca3128..d1f63854c71 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 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 039/115] 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 4de877353aa..bb74a02606f 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 040/115] 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 3832415db62..d1dcdc21c87 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 041/115] 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 f0a05ed192f..5d5b2e19ce3 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 cbdf90681d3..7634fd0caf4 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 f9f0bb3cecc..16efb6caee1 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 042/115] 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 06331d7ff78..a6471eb53cd 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 043/115] 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 1729abce9ef..287b8a7484f 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 cf0946beaba..3577457c980 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 094f5db89b9..7793af737f9 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 14efa1f8fc7..d20ddbde5c6 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 fe261b30b45..5d04824b571 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 044/115] 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 bd7a1265170..4c7faf4f65b 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 2cc064f34a5..92b68a98a90 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 50db0338c4a..37381fa9428 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 045/115] 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 e1276e7da3d..781f94e203a 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 f18eabc84bb..cf5d98d0923 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 046/115] 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 bc1ac5ea069..b31724fa487 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 3cdfcb212f5..2570df70261 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 047/115] 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 8d7b238c17f..4e2d9e61704 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 048/115] 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 1e6a3d1b3be..473db565fa5 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 52f7fe238e8..cfbd7fd0c8b 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 babc6dc9602..cb109f8050d 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 1183e41d041..808d2791709 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 049/115] 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 00000000000..636ef18a518
--- /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 00000000000..7db69679236
--- /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 00000000000..519cfcac72b
--- /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 00000000000..2d329e26aa0
--- /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 00000000000..fbc4bbbbb36
--- /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 050/115] 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 8cf1a31ad6d..00000000000
--- 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 6e4efcb6685..00000000000
--- 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 979a8bd712b..00000000000
--- 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 6fb7db0e64a..00000000000
--- 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 29deada8a41..00000000000
--- 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 b081ed4414b..00000000000
--- 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 5e744ceac5b..00000000000
--- 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 ac878de105b..00000000000
--- 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 4077c4940d1..3c0b918dae9 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 00000000000..6ef1892a3df
--- /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 00000000000..d3313c7cee2
--- /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 4076ebec1fd..0e6186138fc 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 051/115] 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 10f660a140b..f2c3dea1160 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 ad4ff9ee60a..2b6aeee1bc6 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 4b3597afd73..3f145dc958c 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 8dab2d62510..9c67c1cf9f0 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 e3405e0ce89..6db4150be94 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 2079cf88dd9..2aa42e66f8e 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 bddffd465e6..f00dd3e7912 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 b610e7dd587..c0ffdc9d519 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 135982d7090..17f6880293c 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 ea343713a13..c64c6343cca 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 052/115] fix: gitignore dist directory
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 652fbdc3176..63c51c49765 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 053/115] 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 00000000000..c820d233a5e
--- /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 054/115] 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 c74b45e6db6..dfe2c88ea82 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 055/115] 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 ed02f79c2dd..8d99b48b595 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 056/115] 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 7634fd0caf4..381c5e5dec4 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 362f6cf88ee..3840e781b4c 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 057/115] 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 cb18309e3c9..c5ce514cdd2 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 b4a547b21ba..4167ca70df2 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 1c23e2a0ec2..5fdde07faa4 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 ef9aad562df..ffe8be1162f 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 a0d76031fc4..40a8f85d8d6 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 42f4472f29e..aaa98f2f1f4 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 29487962f69..d370fbcda70 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 fb72073a07f..03e96a4b3be 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 79ab8a4d7f2..c9f0029ed80 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 2bb8a53c454..5f2dc480a1b 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 7fb159d6b50..d079bedb420 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 03a1be8a4e7..21f63699753 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 74ce30108fd..3b99c57051a 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 3f22ca21412..578eccf787d 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 690a692ddca..b3e1dc8d87b 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 0b71036c860..6e7ae87d08c 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 b54c9712c89..a4a96b813ee 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 aafc9642d46..e0ffa5dd41a 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 fae6f860b6d..fa4707ce2b4 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 a8753877a6a..da56710c679 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 85e008ac293..eb626f3eee0 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 7108338dab4..e1cca9e3ef4 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 ac9a409bcbe..80d1cdfc8f2 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 6b1fafe5f4c..cb1ee92196f 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 c6a534dac34..bbe9bf5228d 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 bf5c4025a0b..b717491a821 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 058/115] 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 8a42d9e13c1..7c73ad6c90e 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 19c90730908..472746ab84c 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 334bdeac9d3..7875b9cd87f 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 ef7d54ac968..772c8df96e1 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 aa9e1720913527aef4193a053606d5cf38a4f1cf Mon Sep 17 00:00:00 2001
From: Ganga Manoj
Date: Sat, 8 May 2021 17:15:33 +0530
Subject: [PATCH 059/115] 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 e3e6e80616a..a268c15c70b 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 a6fbb66aa2b..68cba2993c6 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 879901f6a8d..11b71c20761 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 de85bc3922c..81e730126ec 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 eeea6da7a42..1e716031751 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 9226cd3932e3a087c7e474c43b7b8d0535221c3c Mon Sep 17 00:00:00 2001
From: Saqib
Date: Mon, 10 May 2021 12:36:56 +0530
Subject: [PATCH 060/115] 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 9aff1440d6a..8799275fc4e 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 40a8f85d8d6..30a270c2043 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 bb6cd8bdc2b..9d1ce9bbbfb 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 6338056698f..052d7bdedf8 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 061/115] 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 7866fdea31a..2af57f4c891 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 062/115] 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 4bb6138e5d7..ed3aee5c1a1 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 c2b5e4f9a90..9957aad019f 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 64e027dd28b..077538d479c 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 8367a257ea4..00000000000
--- 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 29f6c3731d7..e1c803a038b 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 00000000000..e69de29bb2d
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 00000000000..bbe68369ffd
--- /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 00000000000..20caa15ee41
--- /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 00000000000..9313f955167
--- /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 00000000000..38f8de7a660
--- /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 00000000000..d7175ddac43
--- /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 00000000000..e69de29bb2d
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 00000000000..be0be945c4e
--- /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 00000000000..2176cb10deb
--- /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 063/115] 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 f91b432a394..43eea1357a5 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 064/115] 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 43eea1357a5..a3f4de48b87 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 065/115] 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 0bb8e68b698..9bdaa8d1eeb 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 8adf5bf7473..8e0a1e1c185 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 9384ae5542f..b8a82a9edab 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 066/115] 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 a3f4de48b87..7cfd939e956 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 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 067/115] 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 09db7fee2b1..5c1cbaa4aaa 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 dd1822ef58dc24f32d5bf62d634c886a50d7a386 Mon Sep 17 00:00:00 2001
From: Mohammad Hasnain Mohsin Rajan
Date: Wed, 12 May 2021 13:01:53 +0530
Subject: [PATCH 068/115] 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 9ffa481c1cb..df68318052f 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 069/115] 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 24e67febca5..d3d3ffa17fa 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 070/115] 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 8e0a1e1c185..4f4f1b2240b 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 fe68a0ff80c8d807a5886d46f2d51ad33e6949f1 Mon Sep 17 00:00:00 2001
From: Rohit Waghchaure
Date: Wed, 12 May 2021 19:42:04 +0530
Subject: [PATCH 071/115] 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 6dedaa8c530..a505ee09d28 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 ab1ae418ccac57709c6feb4b0f53375eba271997 Mon Sep 17 00:00:00 2001
From: Anuja P
Date: Thu, 13 May 2021 14:26:27 +0530
Subject: [PATCH 072/115] 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 b6238988295..b3aca531398 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 4be0e2ec068..922f6367df4 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 b6149e89f5f..c388669592d 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 073/115] 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 f44d5953326..db1fea192ee 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 01157d6eafc..cf79c03935d 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 074/115] 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 287b8a7484f..26bb44f4f7b 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 075/115] 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 3dbd6053441..016f29a7b51 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 5e913cc2aac..7ffff02850c 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 9f41b13f4b6..5f110e2727c 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 076/115] 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 df68318052f..27c55cc176e 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 077/115] 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 3f837805695..63c71891e44 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 078/115] 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 00000000000..e69de29bb2d
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 00000000000..1ac11409e3c
--- /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 00000000000..d52ffd05ac0
--- /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 00000000000..46e7ae08e92
--- /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 079/115] 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 1ac11409e3c..0b0026028fc 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 080/115] 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 0b0026028fc..894db9e55c9 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 46e7ae08e92..2ea782eb7af 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 081/115] 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 894db9e55c9..8cdce548525 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 2ea782eb7af..6bed89841c4 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 00000000000..dfd8d9e121d
--- /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 082/115] 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 8cdce548525..60490004043 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 083/115] 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 60490004043..5da63dec57a 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 6bed89841c4..db1bf5b6781 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 084/115] 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 5da63dec57a..391aacf391e 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 085/115] 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 db1bf5b6781..b08e796807f 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 086/115] 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 391aacf391e..56694fbec2c 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 b08e796807f..c4ec1374ce2 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 087/115] 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 c4ec1374ce2..1f4d1ba8a07 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 088/115] 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 56694fbec2c..0c0397ab046 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 1f4d1ba8a07..426e8d4aec2 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 089/115] 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 426e8d4aec2..fb7791f7e13 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 00000000000..17248d03203
--- /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 dfd8d9e121d..c9b8e209e4a 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 090/115] 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 0c0397ab046..098096ce0bf 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 df68318052f..cbfba7e31c4 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 091/115] 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 fb7791f7e13..aafcf1297e3 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 c9b8e209e4a..614ef8d2346 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 092/115] 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 17248d03203..977920a2315 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 614ef8d2346..21732b9dfd4 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 093/115] 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 aafcf1297e3..fdecd269eb7 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 094/115] 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 977920a2315..3a4b1754554 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 21732b9dfd4..dcf0e790641 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 095/115] 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 dcf0e790641..772b9a468ae 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 096/115] 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 772b9a468ae..78b15b11c53 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 097/115] 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 78b15b11c53..d3b8de5d191 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 098/115] 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 098096ce0bf..ed6fac4e605 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 fdecd269eb7..18436de3d8a 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 099/115] 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 cbfba7e31c4..148436edaab 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 100/115] 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 b14c2745159..41ca404d9b8 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 a7dfc9ee288..56b046a92e1 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 101/115] 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 00000000000..016dbb01f4d
--- /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 102/115] 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 2bfbdfcc5db..00000000000
--- 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 103/115] 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 00000000000..2bfbdfcc5db
--- /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 104/115] 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 6775398532b..ad971e2976c 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 105/115] 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 63c71891e44..63e96466d06 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 106/115] 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 635bb066ec3..242695c4b85 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 107/115] 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 74963c2aa96..51ce157a81c 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 108/115] 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 10606bf81e1..7fecd4bc347 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 109/115] 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 ecc9fcfe829..99a4e04b7d0 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 110/115] 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 3b6ab7498d9..e40502acd6c 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 8dcd1aa8e7f..c71a62dfb3c 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 72d587afb5f..181e9f8ec09 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 b48db246ac6..ea7432caa21 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 c0e19e9c3d0..384bbc53857 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 ee0e1ef576c..bde00cbd94e 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 a3ba52e67b2..dc9c590dc5e 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 8dfee1d6c72..ebe85241d28 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 925c30b4516..43e1b99f3ad 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 2adfaf45ef1..2371d9652cc 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 12dc59ccfce..503253040b2 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 b32b96af13b..44f841f13b4 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 31410da6bfc..32439b68197 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 b5337464ae1..0ffda07cde8 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 ffa185baf6d..27a3b35ccfb 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 d5ceca8ec83..b42c6153129 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 dda28031df5..974cfc79181 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 a8ea55ca0cb..85036a163e6 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 b736015808f..c3803f19a10 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 f516e061c00..6585e1c78cf 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 688ae1d4108..0182ed55a18 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 6afcd1f43eb..700093fae39 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 c9aa41fdaef..358768eb46c 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 111/115] 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 ea7432caa21..e464a783ad7 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 112/115] 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 b48db246ac6..9e1dbf4333c 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 c6c67b4ddc1..52bc409b6e5 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 bb74a02606f..a0087423906 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 f7b9aef96cc..f069e8dd0b8 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 82d223cada0..f94644ddff1 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 00000000000..93b7f8e59a4
--- /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 3af6622d96e..8c60b5b71ec 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 7eb3571af10..f1ba882812e 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 d21ac0f2f02..2b0c3abdd77 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 43a57e5d4a4..84c7b8118b8 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 113/115] 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 3024819d764..a1d37e2812d 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 114/115] 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 aa0c53e228b..8c5a34a0d8e 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 115/115] 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 ad971e2976c..8d1767497f4 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'''