mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-20 13:39:18 +00:00
Merge branch 'develop' of https://github.com/frappe/erpnext into develop
This commit is contained in:
@@ -5,7 +5,7 @@ import frappe
|
|||||||
from erpnext.hooks import regional_overrides
|
from erpnext.hooks import regional_overrides
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate
|
||||||
|
|
||||||
__version__ = '13.7.0'
|
__version__ = '13.7.1'
|
||||||
|
|
||||||
def get_default_company(user=None):
|
def get_default_company(user=None):
|
||||||
'''Get default company for user'''
|
'''Get default company for user'''
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ frappe.ui.form.on("BOM", {
|
|||||||
|
|
||||||
if (!frm.doc.__islocal && frm.doc.docstatus<2) {
|
if (!frm.doc.__islocal && frm.doc.docstatus<2) {
|
||||||
frm.add_custom_button(__("Update Cost"), function() {
|
frm.add_custom_button(__("Update Cost"), function() {
|
||||||
frm.events.update_cost(frm);
|
frm.events.update_cost(frm, true);
|
||||||
});
|
});
|
||||||
frm.add_custom_button(__("Browse BOM"), function() {
|
frm.add_custom_button(__("Browse BOM"), function() {
|
||||||
frappe.route_options = {
|
frappe.route_options = {
|
||||||
@@ -318,14 +318,15 @@ frappe.ui.form.on("BOM", {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
update_cost: function(frm) {
|
update_cost: function(frm, save_doc=false) {
|
||||||
return frappe.call({
|
return frappe.call({
|
||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
method: "update_cost",
|
method: "update_cost",
|
||||||
freeze: true,
|
freeze: true,
|
||||||
args: {
|
args: {
|
||||||
update_parent: true,
|
update_parent: true,
|
||||||
from_child_bom:false
|
save: save_doc,
|
||||||
|
from_child_bom: false
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
refresh_field("items");
|
refresh_field("items");
|
||||||
|
|||||||
@@ -330,7 +330,7 @@ class BOM(WebsiteGenerator):
|
|||||||
frappe.get_doc("BOM", bom).update_cost(from_child_bom=True)
|
frappe.get_doc("BOM", bom).update_cost(from_child_bom=True)
|
||||||
|
|
||||||
if not from_child_bom:
|
if not from_child_bom:
|
||||||
frappe.msgprint(_("Cost Updated"))
|
frappe.msgprint(_("Cost Updated"), alert=True)
|
||||||
|
|
||||||
def update_parent_cost(self):
|
def update_parent_cost(self):
|
||||||
if self.total_cost:
|
if self.total_cost:
|
||||||
|
|||||||
@@ -747,9 +747,8 @@ def get_bin_details(row, company, for_warehouse=None, all_warehouse=False):
|
|||||||
group by item_code, warehouse
|
group by item_code, warehouse
|
||||||
""".format(conditions=conditions), { "item_code": row['item_code'] }, as_dict=1)
|
""".format(conditions=conditions), { "item_code": row['item_code'] }, as_dict=1)
|
||||||
|
|
||||||
def get_warehouse_list(warehouses, warehouse_list=None):
|
def get_warehouse_list(warehouses):
|
||||||
if not warehouse_list:
|
warehouse_list = []
|
||||||
warehouse_list = []
|
|
||||||
|
|
||||||
if isinstance(warehouses, str):
|
if isinstance(warehouses, str):
|
||||||
warehouses = json.loads(warehouses)
|
warehouses = json.loads(warehouses)
|
||||||
@@ -761,23 +760,19 @@ def get_warehouse_list(warehouses, warehouse_list=None):
|
|||||||
else:
|
else:
|
||||||
warehouse_list.append(row.get("warehouse"))
|
warehouse_list.append(row.get("warehouse"))
|
||||||
|
|
||||||
|
return warehouse_list
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_items_for_material_requests(doc, warehouses=None, get_parent_warehouse_data=None):
|
def get_items_for_material_requests(doc, warehouses=None, get_parent_warehouse_data=None):
|
||||||
if isinstance(doc, str):
|
if isinstance(doc, str):
|
||||||
doc = frappe._dict(json.loads(doc))
|
doc = frappe._dict(json.loads(doc))
|
||||||
|
|
||||||
warehouse_list = []
|
|
||||||
if warehouses:
|
if warehouses:
|
||||||
get_warehouse_list(warehouses, warehouse_list)
|
warehouses = list(set(get_warehouse_list(warehouses)))
|
||||||
|
|
||||||
if warehouse_list:
|
|
||||||
warehouses = list(set(warehouse_list))
|
|
||||||
|
|
||||||
if doc.get("for_warehouse") and not get_parent_warehouse_data and doc.get("for_warehouse") in warehouses:
|
if doc.get("for_warehouse") and not get_parent_warehouse_data and doc.get("for_warehouse") in warehouses:
|
||||||
warehouses.remove(doc.get("for_warehouse"))
|
warehouses.remove(doc.get("for_warehouse"))
|
||||||
|
|
||||||
warehouse_list = None
|
|
||||||
|
|
||||||
doc['mr_items'] = []
|
doc['mr_items'] = []
|
||||||
|
|
||||||
po_items = doc.get('po_items') if doc.get('po_items') else doc.get('items')
|
po_items = doc.get('po_items') if doc.get('po_items') else doc.get('items')
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from erpnext.stock.doctype.item.test_item import create_item
|
|||||||
from erpnext.manufacturing.doctype.production_plan.production_plan import get_sales_orders
|
from erpnext.manufacturing.doctype.production_plan.production_plan import get_sales_orders
|
||||||
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
|
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
|
||||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||||
from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests
|
from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests, get_warehouse_list
|
||||||
|
|
||||||
class TestProductionPlan(unittest.TestCase):
|
class TestProductionPlan(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -251,6 +251,27 @@ class TestProductionPlan(unittest.TestCase):
|
|||||||
pln.cancel()
|
pln.cancel()
|
||||||
frappe.delete_doc("Production Plan", pln.name)
|
frappe.delete_doc("Production Plan", pln.name)
|
||||||
|
|
||||||
|
def test_get_warehouse_list_group(self):
|
||||||
|
"""Check if required warehouses are returned"""
|
||||||
|
warehouse_json = '[{\"warehouse\":\"_Test Warehouse Group - _TC\"}]'
|
||||||
|
|
||||||
|
warehouses = set(get_warehouse_list(warehouse_json))
|
||||||
|
expected_warehouses = {"_Test Warehouse Group-C1 - _TC", "_Test Warehouse Group-C2 - _TC"}
|
||||||
|
|
||||||
|
missing_warehouse = expected_warehouses - warehouses
|
||||||
|
|
||||||
|
self.assertTrue(len(missing_warehouse) == 0,
|
||||||
|
msg=f"Following warehouses were expected {', '.join(missing_warehouse)}")
|
||||||
|
|
||||||
|
def test_get_warehouse_list_single(self):
|
||||||
|
warehouse_json = '[{\"warehouse\":\"_Test Scrap Warehouse - _TC\"}]'
|
||||||
|
|
||||||
|
warehouses = set(get_warehouse_list(warehouse_json))
|
||||||
|
expected_warehouses = {"_Test Scrap Warehouse - _TC", }
|
||||||
|
|
||||||
|
self.assertEqual(warehouses, expected_warehouses)
|
||||||
|
|
||||||
|
|
||||||
def create_production_plan(**args):
|
def create_production_plan(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
this.frm.refresh_fields();
|
this.frm.refresh_fields();
|
||||||
}
|
}
|
||||||
|
|
||||||
calculate_discount_amount(){
|
calculate_discount_amount() {
|
||||||
if (frappe.meta.get_docfield(this.frm.doc.doctype, "discount_amount")) {
|
if (frappe.meta.get_docfield(this.frm.doc.doctype, "discount_amount")) {
|
||||||
this.calculate_item_values();
|
this.calculate_item_values();
|
||||||
this.calculate_net_total();
|
this.calculate_net_total();
|
||||||
@@ -75,18 +75,15 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_calculate_taxes_and_totals() {
|
_calculate_taxes_and_totals() {
|
||||||
frappe.run_serially([
|
this.validate_conversion_rate();
|
||||||
() => this.validate_conversion_rate(),
|
this.calculate_item_values();
|
||||||
() => this.calculate_item_values(),
|
this.initialize_taxes();
|
||||||
() => this.update_item_tax_map(),
|
this.determine_exclusive_rate();
|
||||||
() => this.initialize_taxes(),
|
this.calculate_net_total();
|
||||||
() => this.determine_exclusive_rate(),
|
this.calculate_taxes();
|
||||||
() => this.calculate_net_total(),
|
this.manipulate_grand_total_for_inclusive_tax();
|
||||||
() => this.calculate_taxes(),
|
this.calculate_totals();
|
||||||
() => this.manipulate_grand_total_for_inclusive_tax(),
|
this._cleanup();
|
||||||
() => this.calculate_totals(),
|
|
||||||
() => this._cleanup()
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
validate_conversion_rate() {
|
validate_conversion_rate() {
|
||||||
@@ -270,46 +267,6 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
frappe.model.round_floats_in(this.frm.doc, ["total", "base_total", "net_total", "base_net_total"]);
|
frappe.model.round_floats_in(this.frm.doc, ["total", "base_total", "net_total", "base_net_total"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
update_item_tax_map() {
|
|
||||||
let me = this;
|
|
||||||
let item_codes = [];
|
|
||||||
let item_rates = {};
|
|
||||||
let item_tax_templates = {};
|
|
||||||
|
|
||||||
$.each(this.frm.doc.items || [], function(i, item) {
|
|
||||||
if (item.item_code) {
|
|
||||||
// Use combination of name and item code in case same item is added multiple times
|
|
||||||
item_codes.push([item.item_code, item.name]);
|
|
||||||
item_rates[item.name] = item.net_rate;
|
|
||||||
item_tax_templates[item.name] = item.item_tax_template;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (item_codes.length) {
|
|
||||||
return this.frm.call({
|
|
||||||
method: "erpnext.stock.get_item_details.get_item_tax_info",
|
|
||||||
args: {
|
|
||||||
company: me.frm.doc.company,
|
|
||||||
tax_category: cstr(me.frm.doc.tax_category),
|
|
||||||
item_codes: item_codes,
|
|
||||||
item_rates: item_rates,
|
|
||||||
item_tax_templates: item_tax_templates
|
|
||||||
},
|
|
||||||
callback: function(r) {
|
|
||||||
if (!r.exc) {
|
|
||||||
$.each(me.frm.doc.items || [], function(i, item) {
|
|
||||||
if (item.name && r.message.hasOwnProperty(item.name) && r.message[item.name].item_tax_template) {
|
|
||||||
item.item_tax_template = r.message[item.name].item_tax_template;
|
|
||||||
item.item_tax_rate = r.message[item.name].item_tax_rate;
|
|
||||||
me.add_taxes_from_item_tax_template(item.item_tax_rate);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add_taxes_from_item_tax_template(item_tax_map) {
|
add_taxes_from_item_tax_template(item_tax_map) {
|
||||||
let me = this;
|
let me = this;
|
||||||
|
|
||||||
@@ -634,8 +591,6 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail);
|
tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.frm.refresh_fields();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set_discount_amount() {
|
set_discount_amount() {
|
||||||
|
|||||||
@@ -846,9 +846,9 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
|
|
||||||
frappe.run_serially([
|
frappe.run_serially([
|
||||||
() => me.frm.script_manager.trigger("currency"),
|
() => me.frm.script_manager.trigger("currency"),
|
||||||
|
() => me.update_item_tax_map(),
|
||||||
() => me.apply_default_taxes(),
|
() => me.apply_default_taxes(),
|
||||||
() => me.apply_pricing_rule(),
|
() => me.apply_pricing_rule()
|
||||||
() => me.calculate_taxes_and_totals()
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1807,6 +1807,46 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_item_tax_map() {
|
||||||
|
let me = this;
|
||||||
|
let item_codes = [];
|
||||||
|
let item_rates = {};
|
||||||
|
let item_tax_templates = {};
|
||||||
|
|
||||||
|
$.each(this.frm.doc.items || [], function(i, item) {
|
||||||
|
if (item.item_code) {
|
||||||
|
// Use combination of name and item code in case same item is added multiple times
|
||||||
|
item_codes.push([item.item_code, item.name]);
|
||||||
|
item_rates[item.name] = item.net_rate;
|
||||||
|
item_tax_templates[item.name] = item.item_tax_template;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (item_codes.length) {
|
||||||
|
return this.frm.call({
|
||||||
|
method: "erpnext.stock.get_item_details.get_item_tax_info",
|
||||||
|
args: {
|
||||||
|
company: me.frm.doc.company,
|
||||||
|
tax_category: cstr(me.frm.doc.tax_category),
|
||||||
|
item_codes: item_codes,
|
||||||
|
item_rates: item_rates,
|
||||||
|
item_tax_templates: item_tax_templates
|
||||||
|
},
|
||||||
|
callback: function(r) {
|
||||||
|
if (!r.exc) {
|
||||||
|
$.each(me.frm.doc.items || [], function(i, item) {
|
||||||
|
if (item.name && r.message.hasOwnProperty(item.name) && r.message[item.name].item_tax_template) {
|
||||||
|
item.item_tax_template = r.message[item.name].item_tax_template;
|
||||||
|
item.item_tax_rate = r.message[item.name].item_tax_rate;
|
||||||
|
me.add_taxes_from_item_tax_template(item.item_tax_rate);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
item_tax_template(doc, cdt, cdn) {
|
item_tax_template(doc, cdt, cdn) {
|
||||||
var me = this;
|
var me = this;
|
||||||
if(me.frm.updating_party_details) return;
|
if(me.frm.updating_party_details) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user