Rate with margin in customer and company currency (#11437)
* field for company margin
* added base_rate_with_margin
* calculate company margin
* test for item price
* test for delivery note
* test for sales order
* test for quotation
* test for sales invoice
diff --git a/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_margin.js b/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_margin.js
new file mode 100644
index 0000000..60652c8
--- /dev/null
+++ b/erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_margin.js
@@ -0,0 +1,36 @@
+QUnit.module('Accounts');
+
+QUnit.test("test sales invoice with margin", function(assert) {
+ assert.expect(3);
+ let done = assert.async();
+ frappe.run_serially([
+ () => {
+ return frappe.tests.make('Sales Invoice', [
+ {customer: 'Test Customer 1'},
+ {selling_price_list: 'Test-Selling-USD'},
+ {currency: 'USD'},
+ {items: [
+ [
+ {'item_code': 'Test Product 3'},
+ {'delivery_date': frappe.datetime.add_days(frappe.defaults.get_default("year_end_date"), 1)},
+ {'qty': 1},
+ {'margin_type': 'Percentage'},
+ {'margin_rate_or_amount': 20}
+ ]
+ ]}
+ ]);
+ },
+ () => cur_frm.save(),
+ () => {
+ assert.ok(cur_frm.doc.items[0].rate_with_margin == 240, "Margin rate correct");
+ assert.ok(cur_frm.doc.items[0].base_rate_with_margin == cur_frm.doc.conversion_rate * 240, "Base margin rate correct");
+ assert.ok(cur_frm.doc.total == 240, "Amount correct");
+
+ },
+ () => frappe.tests.click_button('Submit'),
+ () => frappe.tests.click_button('Yes'),
+ () => frappe.timeout(0.3),
+ () => done()
+ ]);
+});
+
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
index 613f384..becb902 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
@@ -729,6 +729,7 @@
"label": "Rate With Margin",
"length": 0,
"no_copy": 0,
+ "options": "currency",
"permlevel": 0,
"precision": "2",
"print_hide": 1,
@@ -809,6 +810,38 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount",
+ "fieldname": "base_rate_with_margin",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Rate With Margin (Company Currency)",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company:company:default_currency",
+ "permlevel": 0,
+ "precision": "2",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "section_break1",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2166,7 +2199,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-09-27 08:31:37.827893",
+ "modified": "2017-11-03 11:33:36.004844",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index e85e56b..e9672df 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -62,7 +62,7 @@
(1.0 - (item.discount_percentage / 100.0)), item.precision("rate"))
if item.doctype in ['Quotation Item', 'Sales Order Item', 'Delivery Note Item', 'Sales Invoice Item']:
- item.rate_with_margin = self.calculate_margin(item)
+ item.rate_with_margin, item.base_rate_with_margin = self.calculate_margin(item)
item.rate = flt(item.rate_with_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate"))\
if item.rate_with_margin > 0 else item.rate
@@ -503,6 +503,7 @@
def calculate_margin(self, item):
rate_with_margin = 0.0
+ base_rate_with_margin = 0.0
if item.price_list_rate:
if item.pricing_rule and not self.doc.ignore_pricing_rule:
pricing_rule = frappe.get_doc('Pricing Rule', item.pricing_rule)
@@ -512,8 +513,9 @@
if item.margin_type and item.margin_rate_or_amount:
margin_value = item.margin_rate_or_amount if item.margin_type == 'Amount' else flt(item.price_list_rate) * flt(item.margin_rate_or_amount) / 100
rate_with_margin = flt(item.price_list_rate) + flt(margin_value)
+ base_rate_with_margin = flt(rate_with_margin) * flt(self.doc.conversion_rate)
- return rate_with_margin
+ return rate_with_margin, base_rate_with_margin
def set_item_wise_tax_breakup(self):
self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 84624b8..05c323b 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -4,11 +4,13 @@
erpnext.taxes_and_totals = erpnext.payments.extend({
setup: function() {},
apply_pricing_rule_on_item: function(item){
+
if(item.margin_type == "Percentage"){
item.rate_with_margin = flt(item.price_list_rate)
+ flt(item.price_list_rate) * ( flt(item.margin_rate_or_amount) / 100);
} else {
item.rate_with_margin = flt(item.price_list_rate) + flt(item.margin_rate_or_amount);
+ item.base_rate_with_margin = flt(item.rate_with_margin) * flt(cur_frm.doc.conversion_rate);
}
item.rate = flt(item.rate_with_margin , precision("rate", item));
diff --git a/erpnext/selling/doctype/quotation/tests/test_quotation_with_margin.js b/erpnext/selling/doctype/quotation/tests/test_quotation_with_margin.js
new file mode 100644
index 0000000..590a828
--- /dev/null
+++ b/erpnext/selling/doctype/quotation/tests/test_quotation_with_margin.js
@@ -0,0 +1,36 @@
+QUnit.module('Selling');
+
+QUnit.test("test quotation with margin", function(assert) {
+ assert.expect(3);
+ let done = assert.async();
+ frappe.run_serially([
+ () => {
+ return frappe.tests.make('Quotation', [
+ {customer: 'Test Customer 1'},
+ {selling_price_list: 'Test-Selling-USD'},
+ {currency: 'USD'},
+ {items: [
+ [
+ {'item_code': 'Test Product 3'},
+ {'delivery_date': frappe.datetime.add_days(frappe.defaults.get_default("year_end_date"), 1)},
+ {'qty': 1},
+ {'margin_type': 'Percentage'},
+ {'margin_rate_or_amount': 20}
+ ]
+ ]}
+ ]);
+ },
+ () => cur_frm.save(),
+ () => {
+ assert.ok(cur_frm.doc.items[0].rate_with_margin == 240, "Margin rate correct");
+ assert.ok(cur_frm.doc.items[0].base_rate_with_margin == cur_frm.doc.conversion_rate * 240, "Base margin rate correct");
+ assert.ok(cur_frm.doc.total == 240, "Amount correct");
+
+ },
+ () => frappe.tests.click_button('Submit'),
+ () => frappe.tests.click_button('Yes'),
+ () => frappe.timeout(0.3),
+ () => done()
+ ]);
+});
+
diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json
index 3fc56fa..f2e89ca 100644
--- a/erpnext/selling/doctype/quotation_item/quotation_item.json
+++ b/erpnext/selling/doctype/quotation_item/quotation_item.json
@@ -714,6 +714,7 @@
"label": "Rate With Margin",
"length": 0,
"no_copy": 0,
+ "options": "currency",
"permlevel": 0,
"precision": "2",
"print_hide": 1,
@@ -795,6 +796,38 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount",
+ "fieldname": "base_rate_with_margin",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Rate With Margin (Company Currency)",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company:company:default_currency",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "section_break1",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1583,7 +1616,7 @@
"istable": 1,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2017-09-27 08:31:37.485134",
+ "modified": "2017-11-03 11:29:59.995384",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation Item",
diff --git a/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_margin.js b/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_margin.js
new file mode 100644
index 0000000..8575b78
--- /dev/null
+++ b/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_margin.js
@@ -0,0 +1,38 @@
+QUnit.module('Selling');
+
+QUnit.test("test sales order with margin", function(assert) {
+ assert.expect(3);
+ let done = assert.async();
+ frappe.run_serially([
+ () => {
+ return frappe.tests.make('Sales Order', [
+ {customer:'Test Customer 1'},
+ {selling_price_list: 'Test-Selling-USD'},
+ {currency: 'USD'},
+ {items: [
+ [
+ {'item_code': 'Test Product 3'},
+ {'delivery_date': frappe.datetime.add_days(frappe.defaults.get_default("year_end_date"), 1)},
+ {'qty': 1},
+ {'margin_type': 'Amount'},
+ {'margin_rate_or_amount': 20}
+ ]
+ ]},
+ ]);
+ },
+
+ () => cur_frm.save(),
+ () => {
+ // get_rate_details
+ assert.ok(cur_frm.doc.items[0].rate_with_margin == 220, "Margin rate correct");
+ assert.ok(cur_frm.doc.items[0].base_rate_with_margin == cur_frm.doc.conversion_rate * 220, "Base margin rate correct");
+ assert.ok(cur_frm.doc.total == 220, "Amount correct");
+ },
+
+ () => frappe.tests.click_button('Submit'),
+ () => frappe.tests.click_button('Yes'),
+ () => frappe.timeout(0.3),
+ () => done()
+ ]);
+});
+
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
index fd7b0f2..b772f51 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
@@ -744,6 +744,7 @@
"label": "Rate With Margin",
"length": 0,
"no_copy": 0,
+ "options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
@@ -825,6 +826,38 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount",
+ "fieldname": "base_rate_with_margin",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Rate With Margin (Company Currency)",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company:company:default_currency",
+ "permlevel": 0,
+ "precision": "2",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "section_break_simple1",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1963,7 +1996,7 @@
"istable": 1,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2017-09-27 08:31:37.129537",
+ "modified": "2017-11-03 11:33:48.453373",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order Item",
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note_with_margin.js b/erpnext/stock/doctype/delivery_note/test_delivery_note_with_margin.js
new file mode 100644
index 0000000..67c9f38
--- /dev/null
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note_with_margin.js
@@ -0,0 +1,37 @@
+QUnit.module('Stock');
+
+QUnit.test("test delivery note with margin", function(assert) {
+ assert.expect(3);
+ let done = assert.async();
+ frappe.run_serially([
+ () => {
+ return frappe.tests.make('Delivery Note', [
+ {customer:'Test Customer 1'},
+ {selling_price_list: 'Test-Selling-USD'},
+ {currency: 'USD'},
+ {items: [
+ [
+ {'item_code': 'Test Product 3'},
+ {'qty': 1},
+ {'margin_type': 'Amount'},
+ {'margin_rate_or_amount': 10}
+ ]
+ ]},
+ ]);
+ },
+
+ () => cur_frm.save(),
+ () => {
+ // get_rate_details
+ assert.ok(cur_frm.doc.items[0].rate_with_margin == 210, "Margin rate correct");
+ assert.ok(cur_frm.doc.items[0].base_rate_with_margin == cur_frm.doc.conversion_rate * 210, "Base margin rate correct");
+ assert.ok(cur_frm.doc.total == 210, "Amount correct");
+ },
+
+ () => frappe.tests.click_button('Submit'),
+ () => frappe.tests.click_button('Yes'),
+ () => frappe.timeout(0.3),
+ () => done()
+ ]);
+});
+
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
index 4e1ea40..72f1dfd 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
@@ -743,6 +743,7 @@
"label": "Rate With Margin",
"length": 0,
"no_copy": 0,
+ "options": "currency",
"permlevel": 0,
"precision": "2",
"print_hide": 1,
@@ -824,6 +825,38 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount",
+ "fieldname": "base_rate_with_margin",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Rate With Margin (Company Currency)",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company:company:default_currency",
+ "permlevel": 0,
+ "precision": "2",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "section_break_1",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1956,7 +1989,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-09-27 08:31:38.768846",
+ "modified": "2017-11-03 11:32:04.837794",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note Item",
diff --git a/erpnext/stock/doctype/item_price/test_item_price.js b/erpnext/stock/doctype/item_price/test_item_price.js
new file mode 100644
index 0000000..6383fb0
--- /dev/null
+++ b/erpnext/stock/doctype/item_price/test_item_price.js
@@ -0,0 +1,22 @@
+QUnit.module('Stock');
+
+QUnit.test("test item price", function(assert) {
+ assert.expect(2);
+ let done = assert.async();
+ frappe.run_serially([
+ () => {
+ return frappe.tests.make('Item Price', [
+ {price_list:'Test-Selling-USD'},
+ {item_code: 'Test Product 3'},
+ {price_list_rate: 200}
+ ]);
+ },
+ () => cur_frm.save(),
+ () => {
+ assert.ok(cur_frm.doc.item_name == 'Test Product 3', "Item name correct");
+ assert.ok(cur_frm.doc.price_list_rate == 200, "Price list rate correct");
+ },
+ () => frappe.timeout(0.3),
+ () => done()
+ ]);
+});
\ No newline at end of file
diff --git a/erpnext/tests/ui/tests.txt b/erpnext/tests/ui/tests.txt
index cbaaf10..3e40485 100644
--- a/erpnext/tests/ui/tests.txt
+++ b/erpnext/tests/ui/tests.txt
@@ -134,3 +134,8 @@
erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.js
erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js
erpnext/projects/doctype/task/tests/test_task_tree.js
+erpnext/stock/doctype/item_price/test_item_price.js
+erpnext/stock/doctype/delivery_note/test_delivery_note_with_margin.js
+erpnext/selling/doctype/sales_order/tests/test_sales_order_with_margin.js
+erpnext/selling/doctype/quotation/tests/test_quotation_with_margin.js
+erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_margin.js