Merge pull request #5518 from saurabh6790/warehouse_tree
Warehouse tree
This commit is contained in:
commit
7b6cdf4a63
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
cur_frm.list_route = "Accounts Browser/Account";
|
cur_frm.list_route = "Tree/Account";
|
||||||
|
|
||||||
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
||||||
if(doc.__islocal) {
|
if(doc.__islocal) {
|
||||||
@ -48,7 +48,7 @@ cur_frm.cscript.account_type = function(doc, cdt, cdn) {
|
|||||||
|
|
||||||
cur_frm.cscript.add_toolbar_buttons = function(doc) {
|
cur_frm.cscript.add_toolbar_buttons = function(doc) {
|
||||||
cur_frm.add_custom_button(__('Chart of Accounts'),
|
cur_frm.add_custom_button(__('Chart of Accounts'),
|
||||||
function() { frappe.set_route("Accounts Browser", "Account"); }, __("View"))
|
function() { frappe.set_route("Tree", "Account"); }, __("View"))
|
||||||
|
|
||||||
if (doc.is_group == 1) {
|
if (doc.is_group == 1) {
|
||||||
cur_frm.add_custom_button(__('Group to Non-Group'),
|
cur_frm.add_custom_button(__('Group to Non-Group'),
|
||||||
|
@ -179,9 +179,12 @@ class Account(Document):
|
|||||||
self.warehouse = None
|
self.warehouse = None
|
||||||
|
|
||||||
def validate_warehouse(self, warehouse):
|
def validate_warehouse(self, warehouse):
|
||||||
if frappe.db.get_value("Stock Ledger Entry", {"warehouse": warehouse}):
|
lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"])
|
||||||
|
|
||||||
|
if frappe.db.sql_list("""select sle.name from `tabStock Ledger Entry` sle where exists (select wh.name from
|
||||||
|
tabWarehouse wh where lft >= %s and rgt <= %s and sle.warehouse = wh.name)""", (lft, rgt)):
|
||||||
throw(_("Stock entries exist against warehouse {0}, hence you cannot re-assign or modify Warehouse").format(warehouse))
|
throw(_("Stock entries exist against warehouse {0}, hence you cannot re-assign or modify Warehouse").format(warehouse))
|
||||||
|
|
||||||
def update_nsm_model(self):
|
def update_nsm_model(self):
|
||||||
"""update lft, rgt indices for nested set model"""
|
"""update lft, rgt indices for nested set model"""
|
||||||
import frappe
|
import frappe
|
||||||
|
52
erpnext/accounts/doctype/account/account_tree.js
Normal file
52
erpnext/accounts/doctype/account/account_tree.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
frappe.treeview_settings["Account"] = {
|
||||||
|
breadcrumbs: "Accounts",
|
||||||
|
title: __("Chart Of Accounts"),
|
||||||
|
get_tree_root: false,
|
||||||
|
filters: [{
|
||||||
|
fieldname: "company",
|
||||||
|
fieldtype:"Select",
|
||||||
|
options: $.map(locals[':Company'], function(c) { return c.name; }).sort(),
|
||||||
|
label: __("Company"),
|
||||||
|
default: frappe.defaults.get_default('company') ? frappe.defaults.get_default('company'): ""
|
||||||
|
}],
|
||||||
|
root_label: "Accounts",
|
||||||
|
get_tree_nodes: 'erpnext.accounts.utils.get_children',
|
||||||
|
add_tree_node: 'erpnext.accounts.utils.add_ac',
|
||||||
|
menu_items:[
|
||||||
|
{
|
||||||
|
label: __('New Company'),
|
||||||
|
action: function() { newdoc('Company'); },
|
||||||
|
condition: 'frappe.boot.user.can_create.indexOf("Company") === -1'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
fields: [
|
||||||
|
{fieldtype:'Data', fieldname:'account_name', label:__('New Account Name'), reqd:true,
|
||||||
|
description: __("Name of new Account. Note: Please don't create accounts for Customers and Suppliers")},
|
||||||
|
{fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
|
||||||
|
description: __('Further accounts can be made under Groups, but entries can be made against non-Groups')},
|
||||||
|
{fieldtype:'Select', fieldname:'root_type', label:__('Root Type'),
|
||||||
|
options: ['Asset', 'Liability', 'Equity', 'Income', 'Expense'].join('\n')},
|
||||||
|
{fieldtype:'Select', fieldname:'account_type', label:__('Account Type'),
|
||||||
|
options: ['', 'Bank', 'Cash', 'Warehouse', 'Tax', 'Chargeable'].join('\n'),
|
||||||
|
description: __("Optional. This setting will be used to filter in various transactions."),
|
||||||
|
depends_on: 'eval:doc.is_group==1'},
|
||||||
|
{fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate'),
|
||||||
|
depends_on: 'eval:doc.is_group==1&&doc.account_type=="Tax"'},
|
||||||
|
{fieldtype:'Link', fieldname:'warehouse', label:__('Warehouse'), options:"Warehouse",
|
||||||
|
depends_on: 'eval:(doc.is_group==1&&doc.account_type=="Warehouse")'},
|
||||||
|
{fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency",
|
||||||
|
description: __("Optional. Sets company's default currency, if not specified.")}
|
||||||
|
],
|
||||||
|
onrender: function(node) {
|
||||||
|
var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr";
|
||||||
|
if (node.data && node.data.balance!==undefined) {
|
||||||
|
$('<span class="balance-area pull-right text-muted small">'
|
||||||
|
+ (node.data.balance_in_account_currency ?
|
||||||
|
(format_currency(Math.abs(node.data.balance_in_account_currency),
|
||||||
|
node.data.account_currency) + " / ") : "")
|
||||||
|
+ format_currency(Math.abs(node.data.balance), node.data.company_currency)
|
||||||
|
+ " " + dr_or_cr
|
||||||
|
+ '</span>').insertBefore(node.$ul);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
frappe.provide("erpnext.accounts");
|
frappe.provide("erpnext.accounts");
|
||||||
|
|
||||||
cur_frm.list_route = "Accounts Browser/Cost Center";
|
cur_frm.list_route = "Tree/Cost Center";
|
||||||
|
|
||||||
|
|
||||||
frappe.ui.form.on('Cost Center', {
|
frappe.ui.form.on('Cost Center', {
|
||||||
@ -34,7 +34,7 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
|||||||
cur_frm.set_intro(intro_txt);
|
cur_frm.set_intro(intro_txt);
|
||||||
|
|
||||||
cur_frm.add_custom_button(__('Chart of Cost Centers'),
|
cur_frm.add_custom_button(__('Chart of Cost Centers'),
|
||||||
function() { frappe.set_route("Accounts Browser", "Cost Center"); }, __("View"))
|
function() { frappe.set_route("Tree", "Cost Center"); }, __("View"))
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript.parent_cost_center = function(doc, cdt, cdn) {
|
cur_frm.cscript.parent_cost_center = function(doc, cdt, cdn) {
|
||||||
|
26
erpnext/accounts/doctype/cost_center/cost_center_tree.js
Normal file
26
erpnext/accounts/doctype/cost_center/cost_center_tree.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
frappe.treeview_settings["Cost Center"] = {
|
||||||
|
breadcrumbs: "Accounts",
|
||||||
|
get_tree_root: false,
|
||||||
|
filters: [{
|
||||||
|
fieldname: "company",
|
||||||
|
fieldtype:"Select",
|
||||||
|
options: $.map(locals[':Company'], function(c) { return c.name; }).sort(),
|
||||||
|
label: __("Company"),
|
||||||
|
default: frappe.defaults.get_default('company') ? frappe.defaults.get_default('company'): ""
|
||||||
|
}],
|
||||||
|
root_label: "Cost Centers",
|
||||||
|
get_tree_nodes: 'erpnext.accounts.utils.get_children',
|
||||||
|
add_tree_node: 'erpnext.accounts.utils.add_cc',
|
||||||
|
menu_items:[
|
||||||
|
{
|
||||||
|
label: __('New Company'),
|
||||||
|
action: function() { newdoc('Company'); },
|
||||||
|
condition: 'frappe.boot.user.can_create.indexOf("Company") === -1'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
fields:[
|
||||||
|
{fieldtype:'Data', fieldname:'cost_center_name', label:__('New Cost Center Name'), reqd:true},
|
||||||
|
{fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
|
||||||
|
description:__('Further cost centers can be made under Groups but entries can be made against non-Groups')}
|
||||||
|
]
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
Tree view browser for Chart of Accounts and Chart of Cost Centers
|
|
@ -1 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
@ -1,334 +0,0 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
|
||||||
// License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
// tree of chart of accounts / cost centers
|
|
||||||
// multiple companies
|
|
||||||
// add node
|
|
||||||
// edit node
|
|
||||||
// see ledger
|
|
||||||
|
|
||||||
frappe.pages["Accounts Browser"].on_page_load = function(wrapper){
|
|
||||||
frappe.ui.make_app_page({
|
|
||||||
parent: wrapper,
|
|
||||||
single_column: true
|
|
||||||
})
|
|
||||||
|
|
||||||
frappe.breadcrumbs.add("Accounts");
|
|
||||||
|
|
||||||
var main = wrapper.page.main,
|
|
||||||
chart_area = $("<div>")
|
|
||||||
.css({"margin-bottom": "15px", "min-height": "200px"})
|
|
||||||
.appendTo(main),
|
|
||||||
help_area = $('<hr><div style="padding: 0px 15px;">'+
|
|
||||||
'<h4>'+__('Quick Help')+'</h4>'+
|
|
||||||
'<ol>'+
|
|
||||||
'<li>'+__('To add child nodes, explore tree and click on the node under which you want to add more nodes.')+'</li>'+
|
|
||||||
'<li>'+
|
|
||||||
__('Accounting Entries can be made against leaf nodes. Entries against Groups are not allowed.')+
|
|
||||||
'</li>'+
|
|
||||||
'<li>'+__('Please do NOT create Accounts for Customers and Suppliers. They are created directly from the Customer / Supplier masters.')+'</li>'+
|
|
||||||
'<li>'+
|
|
||||||
'<b>'+__('To create a Bank Account')+'</b>: '+
|
|
||||||
__('Go to the appropriate group (usually Application of Funds > Current Assets > Bank Accounts and create a new Account (by clicking on Add Child) of type "Bank"')+
|
|
||||||
'</li>'+
|
|
||||||
'<li>'+
|
|
||||||
'<b>'+__('To create a Tax Account') +'</b>: '+
|
|
||||||
__('Go to the appropriate group (usually Source of Funds > Current Liabilities > Taxes and Duties and create a new Account (by clicking on Add Child) of type "Tax" and do mention the Tax rate.')+
|
|
||||||
'</li>'+
|
|
||||||
'</ol>'+
|
|
||||||
'<p>'+__('Please setup your chart of accounts before you start Accounting Entries')+'</p></div>').appendTo(main);
|
|
||||||
|
|
||||||
if (frappe.boot.user.can_create.indexOf("Company") !== -1) {
|
|
||||||
wrapper.page.add_menu_item(__('New Company'), function() { newdoc('Company'); }, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
wrapper.page.add_menu_item(__('Refresh'), function() {
|
|
||||||
wrapper.$company_select.change();
|
|
||||||
});
|
|
||||||
|
|
||||||
wrapper.page.set_primary_action(__('New'), function() {
|
|
||||||
erpnext.account_chart && erpnext.account_chart.make_new();
|
|
||||||
}, "octicon octicon-plus");
|
|
||||||
|
|
||||||
var company_list = $.map(locals[':Company'], function(c) { return c.name; }).sort();
|
|
||||||
|
|
||||||
// company-select
|
|
||||||
wrapper.$company_select = wrapper.page.add_select("Company", company_list)
|
|
||||||
.change(function() {
|
|
||||||
var ctype = frappe.get_route()[1] || 'Account';
|
|
||||||
erpnext.account_chart = new erpnext.AccountsChart(ctype, $(this).val(),
|
|
||||||
chart_area.get(0), wrapper.page);
|
|
||||||
})
|
|
||||||
|
|
||||||
if(frappe.defaults.get_default('company')) {
|
|
||||||
wrapper.$company_select.val(frappe.defaults.get_default('company'));
|
|
||||||
}
|
|
||||||
wrapper.$company_select.change();
|
|
||||||
}
|
|
||||||
|
|
||||||
frappe.pages["Accounts Browser"].on_page_show = function(wrapper){
|
|
||||||
// set route
|
|
||||||
var ctype = frappe.get_route()[1] || 'Account';
|
|
||||||
|
|
||||||
if(frappe.route_options) {
|
|
||||||
if(frappe.route_options.company) {
|
|
||||||
wrapper.$company_select.val(frappe.route_options.company).change();
|
|
||||||
}
|
|
||||||
frappe.route_options = null;
|
|
||||||
} else if(erpnext.account_chart && erpnext.account_chart.ctype != ctype) {
|
|
||||||
wrapper.$company_select.change();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
erpnext.AccountsChart = Class.extend({
|
|
||||||
init: function(ctype, company, wrapper, page) {
|
|
||||||
$(wrapper).empty();
|
|
||||||
var me = this;
|
|
||||||
me.ctype = ctype;
|
|
||||||
me.can_create = frappe.model.can_create(this.ctype);
|
|
||||||
me.can_delete = frappe.model.can_delete(this.ctype);
|
|
||||||
me.can_write = frappe.model.can_write(this.ctype);
|
|
||||||
me.page = page;
|
|
||||||
me.set_title();
|
|
||||||
|
|
||||||
// __("Accounts"), __("Cost Centers")
|
|
||||||
|
|
||||||
me.company = company;
|
|
||||||
this.tree = new frappe.ui.Tree({
|
|
||||||
parent: $(wrapper),
|
|
||||||
label: ctype==="Account" ? "Accounts" : "Cost Centers",
|
|
||||||
args: {ctype: ctype, comp: company},
|
|
||||||
method: 'erpnext.accounts.page.accounts_browser.accounts_browser.get_children',
|
|
||||||
click: function(link) {
|
|
||||||
// bold
|
|
||||||
$('.bold').removeClass('bold'); // deselect
|
|
||||||
$(link).parent().find('.balance-area:first').addClass('bold'); // select
|
|
||||||
|
|
||||||
},
|
|
||||||
toolbar: [
|
|
||||||
{ toggle_btn: true },
|
|
||||||
{
|
|
||||||
label: __("Open"),
|
|
||||||
condition: function(node) { return !node.root },
|
|
||||||
click: function(node, btn) {
|
|
||||||
frappe.set_route("Form", me.ctype, node.label);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
condition: function(node) { return node.expandable; },
|
|
||||||
label: __("Add Child"),
|
|
||||||
click: function() {
|
|
||||||
me.make_new()
|
|
||||||
},
|
|
||||||
btnClass: "hidden-xs"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
condition: function(node) {
|
|
||||||
return !node.root && me.ctype === 'Account'
|
|
||||||
&& frappe.boot.user.can_read.indexOf("GL Entry") !== -1
|
|
||||||
},
|
|
||||||
label: __("View Ledger"),
|
|
||||||
click: function(node, btn) {
|
|
||||||
frappe.route_options = {
|
|
||||||
"account": node.label,
|
|
||||||
"from_date": sys_defaults.year_start_date,
|
|
||||||
"to_date": sys_defaults.year_end_date,
|
|
||||||
"company": me.company
|
|
||||||
};
|
|
||||||
frappe.set_route("query-report", "General Ledger");
|
|
||||||
},
|
|
||||||
btnClass: "hidden-xs"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
condition: function(node) { return !node.root && me.can_write },
|
|
||||||
label: __("Rename"),
|
|
||||||
click: function(node) {
|
|
||||||
frappe.model.rename_doc(me.ctype, node.label, function(new_name) {
|
|
||||||
node.reload_parent();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
btnClass: "hidden-xs"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
condition: function(node) { return !node.root && me.can_delete },
|
|
||||||
label: __("Delete"),
|
|
||||||
click: function(node) {
|
|
||||||
frappe.model.delete_doc(me.ctype, node.label, function() {
|
|
||||||
node.parent.remove();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
btnClass: "hidden-xs"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
onrender: function(node) {
|
|
||||||
var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr";
|
|
||||||
if (me.ctype == 'Account' && node.data && node.data.balance!==undefined) {
|
|
||||||
$('<span class="balance-area pull-right text-muted small">'
|
|
||||||
+ (node.data.balance_in_account_currency ?
|
|
||||||
(format_currency(Math.abs(node.data.balance_in_account_currency),
|
|
||||||
node.data.account_currency) + " / ") : "")
|
|
||||||
+ format_currency(Math.abs(node.data.balance), node.data.company_currency)
|
|
||||||
+ " " + dr_or_cr
|
|
||||||
+ '</span>').insertBefore(node.$ul);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
set_title: function(val) {
|
|
||||||
var chart_str = this.ctype=="Account" ? __("Chart of Accounts") : __("Chart of Cost Centers");
|
|
||||||
if(val) {
|
|
||||||
this.page.set_title(chart_str + " - " + cstr(val));
|
|
||||||
} else {
|
|
||||||
this.page.set_title(chart_str);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
make_new: function() {
|
|
||||||
if(this.ctype=='Account') {
|
|
||||||
this.new_account();
|
|
||||||
} else {
|
|
||||||
this.new_cost_center();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
new_account: function() {
|
|
||||||
var me = this;
|
|
||||||
|
|
||||||
var node = me.tree.get_selected_node();
|
|
||||||
|
|
||||||
if(!(node && node.expandable)) {
|
|
||||||
frappe.msgprint(__("Select a group node first."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the dialog
|
|
||||||
var d = new frappe.ui.Dialog({
|
|
||||||
title:__('New Account'),
|
|
||||||
fields: [
|
|
||||||
{fieldtype:'Data', fieldname:'account_name', label:__('New Account Name'), reqd:true,
|
|
||||||
description: __("Name of new Account. Note: Please don't create accounts for Customers and Suppliers")},
|
|
||||||
{fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
|
|
||||||
description: __('Further accounts can be made under Groups, but entries can be made against non-Groups')},
|
|
||||||
{fieldtype:'Select', fieldname:'root_type', label:__('Root Type'),
|
|
||||||
options: ['Asset', 'Liability', 'Equity', 'Income', 'Expense'].join('\n'),
|
|
||||||
},
|
|
||||||
{fieldtype:'Select', fieldname:'account_type', label:__('Account Type'),
|
|
||||||
options: ['', 'Bank', 'Cash', 'Warehouse', 'Tax', 'Chargeable'].join('\n'),
|
|
||||||
description: __("Optional. This setting will be used to filter in various transactions.") },
|
|
||||||
{fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate')},
|
|
||||||
{fieldtype:'Link', fieldname:'warehouse', label:__('Warehouse'), options:"Warehouse"},
|
|
||||||
{fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency",
|
|
||||||
description: __("Optional. Sets company's default currency, if not specified.")}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
var fd = d.fields_dict;
|
|
||||||
|
|
||||||
// account type if ledger
|
|
||||||
$(fd.is_group.input).change(function() {
|
|
||||||
if($(this).prop("checked")) {
|
|
||||||
$(fd.account_type.wrapper).toggle(false);
|
|
||||||
$(fd.tax_rate.wrapper).toggle(false);
|
|
||||||
$(fd.warehouse.wrapper).toggle(false);
|
|
||||||
} else {
|
|
||||||
$(fd.account_type.wrapper).toggle(node.root ? false : true);
|
|
||||||
fd.account_type.$input.trigger("change");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// tax rate if tax
|
|
||||||
$(fd.account_type.input).change(function() {
|
|
||||||
$(fd.tax_rate.wrapper).toggle(fd.account_type.get_value()==='Tax');
|
|
||||||
$(fd.warehouse.wrapper).toggle(fd.account_type.get_value()==='Warehouse');
|
|
||||||
})
|
|
||||||
|
|
||||||
// create
|
|
||||||
d.set_primary_action(__("Create New"), function() {
|
|
||||||
var btn = this;
|
|
||||||
var v = d.get_values();
|
|
||||||
if(!v) return;
|
|
||||||
|
|
||||||
if(v.account_type==="Warehouse" && !v.warehouse) {
|
|
||||||
msgprint(__("Warehouse is required"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var node = me.tree.get_selected_node();
|
|
||||||
v.parent_account = node.label;
|
|
||||||
v.company = me.company;
|
|
||||||
|
|
||||||
if(node.root) {
|
|
||||||
v.is_root = 1;
|
|
||||||
v.parent_account = null;
|
|
||||||
} else {
|
|
||||||
v.is_root = 0;
|
|
||||||
v.root_type = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return frappe.call({
|
|
||||||
args: v,
|
|
||||||
method: 'erpnext.accounts.utils.add_ac',
|
|
||||||
callback: function(r) {
|
|
||||||
d.hide();
|
|
||||||
if(node.expanded) {
|
|
||||||
node.toggle_node();
|
|
||||||
}
|
|
||||||
node.load();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// show
|
|
||||||
d.on_page_show = function() {
|
|
||||||
$(fd.is_group.input).change();
|
|
||||||
$(fd.account_type.input).change();
|
|
||||||
}
|
|
||||||
|
|
||||||
$(fd.is_group.input).prop("checked", false).change();
|
|
||||||
|
|
||||||
// In case of root, show root type and hide account_type, is_group
|
|
||||||
$(fd.root_type.wrapper).toggle(node.root);
|
|
||||||
$(fd.is_group.wrapper).toggle(!node.root);
|
|
||||||
|
|
||||||
d.show();
|
|
||||||
},
|
|
||||||
|
|
||||||
new_cost_center: function(){
|
|
||||||
var me = this;
|
|
||||||
// the dialog
|
|
||||||
var d = new frappe.ui.Dialog({
|
|
||||||
title:__('New Cost Center'),
|
|
||||||
fields: [
|
|
||||||
{fieldtype:'Data', fieldname:'cost_center_name', label:__('New Cost Center Name'), reqd:true},
|
|
||||||
{fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
|
|
||||||
description:__('Further cost centers can be made under Groups but entries can be made against non-Groups')},
|
|
||||||
{fieldtype:'Button', fieldname:'create_new', label:__('Create New') }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
// create
|
|
||||||
$(d.fields_dict.create_new.input).click(function() {
|
|
||||||
var v = d.get_values();
|
|
||||||
if(!v) return;
|
|
||||||
|
|
||||||
var node = me.tree.get_selected_node();
|
|
||||||
|
|
||||||
v.parent_cost_center = node.label;
|
|
||||||
v.company = me.company;
|
|
||||||
|
|
||||||
return frappe.call({
|
|
||||||
args: v,
|
|
||||||
method: 'erpnext.accounts.utils.add_cc',
|
|
||||||
callback: function(r) {
|
|
||||||
d.hide();
|
|
||||||
if(node.expanded) {
|
|
||||||
node.toggle_node();
|
|
||||||
}
|
|
||||||
node.load();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
d.show();
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"creation": "2012-06-14 15:07:28.000000",
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "Page",
|
|
||||||
"icon": "icon-sitemap",
|
|
||||||
"idx": 1,
|
|
||||||
"modified": "2013-07-11 14:39:42.000000",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Accounts",
|
|
||||||
"name": "accounts-browser",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"page_name": "Accounts Browser",
|
|
||||||
"roles": [
|
|
||||||
{
|
|
||||||
"role": "Accounts User"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "Accounts Manager"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"standard": "Yes"
|
|
||||||
}
|
|
@ -1,57 +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
|
|
||||||
import frappe.defaults
|
|
||||||
from frappe.utils import flt
|
|
||||||
from erpnext.accounts.utils import get_balance_on
|
|
||||||
from erpnext.accounts.report.financial_statements import sort_root_accounts
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
|
||||||
def get_companies():
|
|
||||||
"""get a list of companies based on permission"""
|
|
||||||
return [d.name for d in frappe.get_list("Company", fields=["name"],
|
|
||||||
order_by="name")]
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
|
||||||
def get_children():
|
|
||||||
args = frappe.local.form_dict
|
|
||||||
ctype, company = args['ctype'], args['comp']
|
|
||||||
fieldname = frappe.db.escape(ctype.lower().replace(' ','_'))
|
|
||||||
doctype = frappe.db.escape(ctype)
|
|
||||||
|
|
||||||
# root
|
|
||||||
if args['parent'] in ("Accounts", "Cost Centers"):
|
|
||||||
fields = ", root_type, report_type, account_currency" if ctype=="Account" else ""
|
|
||||||
acc = frappe.db.sql(""" select
|
|
||||||
name as value, is_group as expandable {fields}
|
|
||||||
from `tab{doctype}`
|
|
||||||
where ifnull(`parent_{fieldname}`,'') = ''
|
|
||||||
and `company` = %s and docstatus<2
|
|
||||||
order by name""".format(fields=fields, fieldname = fieldname, doctype=doctype),
|
|
||||||
company, as_dict=1)
|
|
||||||
|
|
||||||
if args["parent"]=="Accounts":
|
|
||||||
sort_root_accounts(acc)
|
|
||||||
else:
|
|
||||||
# other
|
|
||||||
fields = ", account_currency" if ctype=="Account" else ""
|
|
||||||
acc = frappe.db.sql("""select
|
|
||||||
name as value, is_group as expandable, parent_{fieldname} as parent {fields}
|
|
||||||
from `tab{doctype}`
|
|
||||||
where ifnull(`parent_{fieldname}`,'') = %s
|
|
||||||
and docstatus<2
|
|
||||||
order by name""".format(fields=fields, fieldname=fieldname, doctype=doctype),
|
|
||||||
args['parent'], as_dict=1)
|
|
||||||
|
|
||||||
if ctype == 'Account':
|
|
||||||
company_currency = frappe.db.get_value("Company", company, "default_currency")
|
|
||||||
for each in acc:
|
|
||||||
each["company_currency"] = company_currency
|
|
||||||
each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False))
|
|
||||||
|
|
||||||
if each.account_currency != company_currency:
|
|
||||||
each["balance_in_account_currency"] = flt(get_balance_on(each.get("value")))
|
|
||||||
|
|
||||||
return acc
|
|
@ -10,6 +10,8 @@ from frappe.utils import formatdate
|
|||||||
|
|
||||||
# imported to enable erpnext.accounts.utils.get_account_currency
|
# imported to enable erpnext.accounts.utils.get_account_currency
|
||||||
from erpnext.accounts.doctype.account.account import get_account_currency
|
from erpnext.accounts.doctype.account.account import get_account_currency
|
||||||
|
import frappe.defaults
|
||||||
|
from erpnext.accounts.report.financial_statements import sort_root_accounts
|
||||||
|
|
||||||
class FiscalYearError(frappe.ValidationError): pass
|
class FiscalYearError(frappe.ValidationError): pass
|
||||||
|
|
||||||
@ -127,7 +129,7 @@ def add_ac(args=None):
|
|||||||
if not args:
|
if not args:
|
||||||
args = frappe.local.form_dict
|
args = frappe.local.form_dict
|
||||||
args.pop("cmd")
|
args.pop("cmd")
|
||||||
|
|
||||||
ac = frappe.new_doc("Account")
|
ac = frappe.new_doc("Account")
|
||||||
|
|
||||||
if args.get("ignore_permissions"):
|
if args.get("ignore_permissions"):
|
||||||
@ -135,6 +137,10 @@ def add_ac(args=None):
|
|||||||
args.pop("ignore_permissions")
|
args.pop("ignore_permissions")
|
||||||
|
|
||||||
ac.update(args)
|
ac.update(args)
|
||||||
|
|
||||||
|
if not ac.parent_account:
|
||||||
|
ac.parent_account = args.get("parent")
|
||||||
|
|
||||||
ac.old_parent = ""
|
ac.old_parent = ""
|
||||||
ac.freeze_account = "No"
|
ac.freeze_account = "No"
|
||||||
if cint(ac.get("is_root")):
|
if cint(ac.get("is_root")):
|
||||||
@ -153,6 +159,10 @@ def add_cc(args=None):
|
|||||||
|
|
||||||
cc = frappe.new_doc("Cost Center")
|
cc = frappe.new_doc("Cost Center")
|
||||||
cc.update(args)
|
cc.update(args)
|
||||||
|
|
||||||
|
if not cc.parent_cost_center:
|
||||||
|
cc.parent_cost_center = args.get("parent")
|
||||||
|
|
||||||
cc.old_parent = ""
|
cc.old_parent = ""
|
||||||
cc.insert()
|
cc.insert()
|
||||||
return cc.name
|
return cc.name
|
||||||
@ -428,3 +438,51 @@ def get_account_name(account_type=None, root_type=None, is_group=None, account_c
|
|||||||
"account_currency": account_currency or frappe.defaults.get_defaults().currency,
|
"account_currency": account_currency or frappe.defaults.get_defaults().currency,
|
||||||
"company": company or frappe.defaults.get_defaults().company
|
"company": company or frappe.defaults.get_defaults().company
|
||||||
}, "name")
|
}, "name")
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_companies():
|
||||||
|
"""get a list of companies based on permission"""
|
||||||
|
return [d.name for d in frappe.get_list("Company", fields=["name"],
|
||||||
|
order_by="name")]
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_children():
|
||||||
|
args = frappe.local.form_dict
|
||||||
|
doctype, company = args['doctype'], args['company']
|
||||||
|
fieldname = frappe.db.escape(doctype.lower().replace(' ','_'))
|
||||||
|
doctype = frappe.db.escape(doctype)
|
||||||
|
|
||||||
|
# root
|
||||||
|
if args['parent'] in ("Accounts", "Cost Centers"):
|
||||||
|
fields = ", root_type, report_type, account_currency" if doctype=="Account" else ""
|
||||||
|
acc = frappe.db.sql(""" select
|
||||||
|
name as value, is_group as expandable {fields}
|
||||||
|
from `tab{doctype}`
|
||||||
|
where ifnull(`parent_{fieldname}`,'') = ''
|
||||||
|
and `company` = %s and docstatus<2
|
||||||
|
order by name""".format(fields=fields, fieldname = fieldname, doctype=doctype),
|
||||||
|
company, as_dict=1)
|
||||||
|
|
||||||
|
if args["parent"]=="Accounts":
|
||||||
|
sort_root_accounts(acc)
|
||||||
|
else:
|
||||||
|
# other
|
||||||
|
fields = ", account_currency" if doctype=="Account" else ""
|
||||||
|
acc = frappe.db.sql("""select
|
||||||
|
name as value, is_group as expandable, parent_{fieldname} as parent {fields}
|
||||||
|
from `tab{doctype}`
|
||||||
|
where ifnull(`parent_{fieldname}`,'') = %s
|
||||||
|
and docstatus<2
|
||||||
|
order by name""".format(fields=fields, fieldname=fieldname, doctype=doctype),
|
||||||
|
args['parent'], as_dict=1)
|
||||||
|
|
||||||
|
if doctype == 'Account':
|
||||||
|
company_currency = frappe.db.get_value("Company", company, "default_currency")
|
||||||
|
for each in acc:
|
||||||
|
each["company_currency"] = company_currency
|
||||||
|
each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False))
|
||||||
|
|
||||||
|
if each.account_currency != company_currency:
|
||||||
|
each["balance_in_account_currency"] = flt(get_balance_on(each.get("value")))
|
||||||
|
|
||||||
|
return acc
|
||||||
|
@ -51,10 +51,10 @@ def get_data():
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "page",
|
"type": "page",
|
||||||
"name": "Accounts Browser",
|
"name": "Tree",
|
||||||
"icon": "icon-sitemap",
|
"icon": "icon-sitemap",
|
||||||
"label": _("Chart of Accounts"),
|
"label": _("Chart of Accounts"),
|
||||||
"route": "Accounts Browser/Account",
|
"route": "Tree/Account",
|
||||||
"description": _("Tree of financial accounts."),
|
"description": _("Tree of financial accounts."),
|
||||||
"doctype": "Account",
|
"doctype": "Account",
|
||||||
},
|
},
|
||||||
@ -193,10 +193,10 @@ def get_data():
|
|||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"type": "page",
|
"type": "page",
|
||||||
"name": "Accounts Browser",
|
"name": "Tree",
|
||||||
"icon": "icon-sitemap",
|
"icon": "icon-sitemap",
|
||||||
"label": _("Chart of Cost Centers"),
|
"label": _("Chart of Cost Centers"),
|
||||||
"route": "Accounts Browser/Cost Center",
|
"route": "Tree/Cost Center",
|
||||||
"description": _("Tree of financial Cost Centers."),
|
"description": _("Tree of financial Cost Centers."),
|
||||||
"doctype": "Cost Center",
|
"doctype": "Cost Center",
|
||||||
},
|
},
|
||||||
|
@ -97,10 +97,10 @@ def get_data():
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "page",
|
"type": "page",
|
||||||
"name": "Sales Browser",
|
"name": "Tree",
|
||||||
"icon": "icon-sitemap",
|
"icon": "icon-sitemap",
|
||||||
"label": _("Item Group"),
|
"label": _("Item Group"),
|
||||||
"link": "Sales Browser/Item Group",
|
"link": "Tree/Item Group",
|
||||||
"description": _("Tree of Item Groups."),
|
"description": _("Tree of Item Groups."),
|
||||||
"doctype": "Item Group",
|
"doctype": "Item Group",
|
||||||
},
|
},
|
||||||
|
@ -92,27 +92,27 @@ def get_data():
|
|||||||
{
|
{
|
||||||
"type": "page",
|
"type": "page",
|
||||||
"label": _("Customer Group"),
|
"label": _("Customer Group"),
|
||||||
"name": "Sales Browser",
|
"name": "Tree",
|
||||||
"icon": "icon-sitemap",
|
"icon": "icon-sitemap",
|
||||||
"link": "Sales Browser/Customer Group",
|
"link": "Tree/Customer Group",
|
||||||
"description": _("Manage Customer Group Tree."),
|
"description": _("Manage Customer Group Tree."),
|
||||||
"doctype": "Customer Group",
|
"doctype": "Customer Group",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "page",
|
"type": "page",
|
||||||
"label": _("Territory"),
|
"label": _("Territory"),
|
||||||
"name": "Sales Browser",
|
"name": "Tree",
|
||||||
"icon": "icon-sitemap",
|
"icon": "icon-sitemap",
|
||||||
"link": "Sales Browser/Territory",
|
"link": "Tree/Territory",
|
||||||
"description": _("Manage Territory Tree."),
|
"description": _("Manage Territory Tree."),
|
||||||
"doctype": "Territory",
|
"doctype": "Territory",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "page",
|
"type": "page",
|
||||||
"label": _("Sales Person"),
|
"label": _("Sales Person"),
|
||||||
"name": "Sales Browser",
|
"name": "Tree",
|
||||||
"icon": "icon-sitemap",
|
"icon": "icon-sitemap",
|
||||||
"link": "Sales Browser/Sales Person",
|
"link": "Tree/Sales Person",
|
||||||
"description": _("Manage Sales Person Tree."),
|
"description": _("Manage Sales Person Tree."),
|
||||||
"doctype": "Sales Person",
|
"doctype": "Sales Person",
|
||||||
},
|
},
|
||||||
|
@ -30,9 +30,9 @@ def get_data():
|
|||||||
{
|
{
|
||||||
"type": "page",
|
"type": "page",
|
||||||
"label": _("Customer Group"),
|
"label": _("Customer Group"),
|
||||||
"name": "Sales Browser",
|
"name": "Tree",
|
||||||
"icon": "icon-sitemap",
|
"icon": "icon-sitemap",
|
||||||
"link": "Sales Browser/Customer Group",
|
"link": "Tree/Customer Group",
|
||||||
"description": _("Manage Customer Group Tree."),
|
"description": _("Manage Customer Group Tree."),
|
||||||
"doctype": "Customer Group",
|
"doctype": "Customer Group",
|
||||||
},
|
},
|
||||||
@ -69,10 +69,10 @@ def get_data():
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "page",
|
"type": "page",
|
||||||
"name": "Sales Browser",
|
"name": "Tree",
|
||||||
"icon": "icon-sitemap",
|
"icon": "icon-sitemap",
|
||||||
"label": _("Item Group"),
|
"label": _("Item Group"),
|
||||||
"link": "Sales Browser/Item Group",
|
"link": "Tree/Item Group",
|
||||||
"description": _("Tree of Item Groups."),
|
"description": _("Tree of Item Groups."),
|
||||||
"doctype": "Item Group",
|
"doctype": "Item Group",
|
||||||
},
|
},
|
||||||
@ -101,9 +101,9 @@ def get_data():
|
|||||||
{
|
{
|
||||||
"type": "page",
|
"type": "page",
|
||||||
"label": _("Territory"),
|
"label": _("Territory"),
|
||||||
"name": "Sales Browser",
|
"name": "Tree",
|
||||||
"icon": "icon-sitemap",
|
"icon": "icon-sitemap",
|
||||||
"link": "Sales Browser/Territory",
|
"link": "Tree/Territory",
|
||||||
"description": _("Manage Territory Tree."),
|
"description": _("Manage Territory Tree."),
|
||||||
"doctype": "Territory",
|
"doctype": "Territory",
|
||||||
},
|
},
|
||||||
@ -115,9 +115,9 @@ def get_data():
|
|||||||
{
|
{
|
||||||
"type": "page",
|
"type": "page",
|
||||||
"label": _("Sales Person"),
|
"label": _("Sales Person"),
|
||||||
"name": "Sales Browser",
|
"name": "Tree",
|
||||||
"icon": "icon-sitemap",
|
"icon": "icon-sitemap",
|
||||||
"link": "Sales Browser/Sales Person",
|
"link": "Tree/Sales Person",
|
||||||
"description": _("Manage Sales Person Tree."),
|
"description": _("Manage Sales Person Tree."),
|
||||||
"doctype": "Sales Person",
|
"doctype": "Sales Person",
|
||||||
},
|
},
|
||||||
|
@ -78,10 +78,10 @@ def get_data():
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "page",
|
"type": "page",
|
||||||
"name": "Sales Browser",
|
"name": "Tree",
|
||||||
"icon": "icon-sitemap",
|
"icon": "icon-sitemap",
|
||||||
"label": _("Item Group"),
|
"label": _("Item Group"),
|
||||||
"link": "Sales Browser/Item Group",
|
"link": "Tree/Item Group",
|
||||||
"description": _("Tree of Item Groups."),
|
"description": _("Tree of Item Groups."),
|
||||||
"doctype": "Item Group",
|
"doctype": "Item Group",
|
||||||
},
|
},
|
||||||
|
@ -321,6 +321,7 @@ def get_warehouse_account():
|
|||||||
warehouse_account = frappe._dict()
|
warehouse_account = frappe._dict()
|
||||||
|
|
||||||
for d in frappe.db.sql("""select warehouse, name, account_currency from tabAccount
|
for d in frappe.db.sql("""select warehouse, name, account_currency from tabAccount
|
||||||
where account_type = 'Warehouse' and (warehouse is not null and warehouse != '')""", as_dict=1):
|
where account_type = 'Warehouse' and (warehouse is not null and warehouse != ''
|
||||||
|
and is_group != 1)""", as_dict=1):
|
||||||
warehouse_account.setdefault(d.warehouse, d)
|
warehouse_account.setdefault(d.warehouse, d)
|
||||||
return warehouse_account
|
return warehouse_account
|
||||||
|
@ -24,7 +24,7 @@ frappe.ui.form.on("BOM", {
|
|||||||
frm.events.update_cost(frm);
|
frm.events.update_cost(frm);
|
||||||
});
|
});
|
||||||
frm.add_custom_button(__("Browse BOM"), function() {
|
frm.add_custom_button(__("Browse BOM"), function() {
|
||||||
frappe.set_route("bom-browser", frm.doc.name);
|
frappe.set_route("Tree", "BOM");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,3 +438,14 @@ def validate_bom_no(item, bom_no):
|
|||||||
if item and not (bom.item.lower() == item.lower() or \
|
if item and not (bom.item.lower() == item.lower() or \
|
||||||
bom.item.lower() == cstr(frappe.db.get_value("Item", item, "variant_of")).lower()):
|
bom.item.lower() == cstr(frappe.db.get_value("Item", item, "variant_of")).lower()):
|
||||||
frappe.throw(_("BOM {0} does not belong to Item {1}").format(bom_no, item))
|
frappe.throw(_("BOM {0} does not belong to Item {1}").format(bom_no, item))
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_children(parent=None):
|
||||||
|
if parent:
|
||||||
|
return frappe.db.sql("""select item_code,
|
||||||
|
bom_no as value, qty,
|
||||||
|
if(ifnull(bom_no, "")!="", 1, 0) as expandable
|
||||||
|
from `tabBOM Item`
|
||||||
|
where parent=%s
|
||||||
|
order by idx
|
||||||
|
""", parent, as_dict=True)
|
35
erpnext/manufacturing/doctype/bom/bom_tree.js
Normal file
35
erpnext/manufacturing/doctype/bom/bom_tree.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
frappe.treeview_settings["BOM"] = {
|
||||||
|
get_tree_nodes: 'erpnext.manufacturing.doctype.bom.bom.get_children',
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
fieldname: "bom",
|
||||||
|
fieldtype:"Link",
|
||||||
|
options: "BOM",
|
||||||
|
label: __("BOM")
|
||||||
|
}
|
||||||
|
],
|
||||||
|
title: "BOM",
|
||||||
|
breadcrumb: "Manufacturing",
|
||||||
|
disable_add_node: true,
|
||||||
|
root_label: "bom", //fieldname from filters
|
||||||
|
get_label: function(node) {
|
||||||
|
if(node.data.qty) {
|
||||||
|
return node.data.qty + " x " + node.data.item_code;
|
||||||
|
} else {
|
||||||
|
return node.data.item_code || node.data.value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toolbar: [
|
||||||
|
{toggle_btn: true},
|
||||||
|
{
|
||||||
|
label:__("Edit"),
|
||||||
|
condition: function(node) {
|
||||||
|
return node.expandable;
|
||||||
|
},
|
||||||
|
click: function(node) {
|
||||||
|
|
||||||
|
frappe.set_route("Form", "BOM", node.data.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
@ -1,89 +0,0 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
|
||||||
// License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
frappe.pages['bom-browser'].on_page_load = function(wrapper) {
|
|
||||||
var page = frappe.ui.make_app_page({
|
|
||||||
parent: wrapper,
|
|
||||||
title: 'BOM Browser',
|
|
||||||
single_column: true
|
|
||||||
});
|
|
||||||
|
|
||||||
page.main.css({
|
|
||||||
"min-height": "300px",
|
|
||||||
"padding-bottom": "25px"
|
|
||||||
});
|
|
||||||
|
|
||||||
page.tree_area = $('<div class="padding"><p class="text-muted">'+
|
|
||||||
__("Select BOM to start")
|
|
||||||
+'</p></div>').appendTo(page.main);
|
|
||||||
|
|
||||||
frappe.breadcrumbs.add(frappe.breadcrumbs.last_module || "Manufacturing");
|
|
||||||
|
|
||||||
var make_tree = function() {
|
|
||||||
erpnext.bom_tree = new erpnext.BOMTree(page.$bom_select.val(), page, page.tree_area);
|
|
||||||
}
|
|
||||||
|
|
||||||
page.$bom_select = wrapper.page.add_field({fieldname: "bom",
|
|
||||||
fieldtype:"Link", options: "BOM", label: __("BOM")}).$input
|
|
||||||
.change(function() {
|
|
||||||
make_tree();
|
|
||||||
});
|
|
||||||
|
|
||||||
page.set_secondary_action(__('Refresh'), function() {
|
|
||||||
make_tree();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
frappe.pages['bom-browser'].on_page_show = function(wrapper){
|
|
||||||
// set from route
|
|
||||||
var bom = null;
|
|
||||||
if(frappe.get_route()[1]) {
|
|
||||||
var bom = frappe.get_route().splice(1).join("/");
|
|
||||||
}
|
|
||||||
if(frappe.route_options && frappe.route_options.bom) {
|
|
||||||
var bom = frappe.route_options.bom;
|
|
||||||
}
|
|
||||||
if(bom) {
|
|
||||||
wrapper.page.$bom_select.val(bom).trigger("change");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
erpnext.BOMTree = Class.extend({
|
|
||||||
init: function(root, page, parent) {
|
|
||||||
$(parent).empty();
|
|
||||||
var me = this;
|
|
||||||
me.page = page;
|
|
||||||
me.bom = page.$bom_select.val();
|
|
||||||
me.can_read = frappe.model.can_read("BOM");
|
|
||||||
me.can_create = frappe.boot.user.can_create.indexOf("BOM") !== -1 ||
|
|
||||||
frappe.boot.user.in_create.indexOf("BOM") !== -1;
|
|
||||||
me.can_write = frappe.model.can_write("BOM");
|
|
||||||
me.can_delete = frappe.model.can_delete("BOM");
|
|
||||||
this.tree = new frappe.ui.Tree({
|
|
||||||
parent: $(parent),
|
|
||||||
label: me.bom,
|
|
||||||
args: {parent: me.bom},
|
|
||||||
method: 'erpnext.manufacturing.page.bom_browser.bom_browser.get_children',
|
|
||||||
toolbar: [
|
|
||||||
{toggle_btn: true},
|
|
||||||
{
|
|
||||||
label:__("Edit"),
|
|
||||||
condition: function(node) {
|
|
||||||
return node.expandable;
|
|
||||||
},
|
|
||||||
click: function(node) {
|
|
||||||
frappe.set_route("Form", "BOM", node.data.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
get_label: function(node) {
|
|
||||||
if(node.data.qty) {
|
|
||||||
return node.data.qty + " x " + node.data.item_code;
|
|
||||||
} else {
|
|
||||||
return node.data.item_code || node.data.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"content": null,
|
|
||||||
"creation": "2015-05-25 02:57:33.472044",
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "Page",
|
|
||||||
"modified": "2015-05-25 02:57:33.472044",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Manufacturing",
|
|
||||||
"name": "bom-browser",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"page_name": "bom-browser",
|
|
||||||
"roles": [
|
|
||||||
{
|
|
||||||
"role": "Manufacturing User"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"script": null,
|
|
||||||
"standard": "Yes",
|
|
||||||
"style": null,
|
|
||||||
"title": "BOM Browser"
|
|
||||||
}
|
|
@ -1,15 +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
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
|
||||||
def get_children(parent):
|
|
||||||
return frappe.db.sql("""select item_code,
|
|
||||||
bom_no as value, qty,
|
|
||||||
if(ifnull(bom_no, "")!="", 1, 0) as expandable
|
|
||||||
from `tabBOM Item`
|
|
||||||
where parent=%s
|
|
||||||
order by idx
|
|
||||||
""", parent, as_dict=True)
|
|
@ -273,3 +273,4 @@ execute:frappe.rename_doc("DocType", "Payments", "Sales Invoice Payment", force=
|
|||||||
erpnext.patches.v7_0.update_mins_to_first_response
|
erpnext.patches.v7_0.update_mins_to_first_response
|
||||||
erpnext.patches.v6_20x.repost_valuation_rate_for_negative_inventory
|
erpnext.patches.v6_20x.repost_valuation_rate_for_negative_inventory
|
||||||
erpnext.patches.v7_0.re_route
|
erpnext.patches.v7_0.re_route
|
||||||
|
erpnext.patches.v7_0.create_warehouse_nestedset
|
||||||
|
48
erpnext/patches/v7_0/create_warehouse_nestedset.py
Normal file
48
erpnext/patches/v7_0/create_warehouse_nestedset.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import frappe
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doc("stock", "doctype", "warehouse")
|
||||||
|
|
||||||
|
for company in frappe.get_all("Company", fields=["name", "abbr"]):
|
||||||
|
if not frappe.db.get_value("Warehouse", "{0} - {1}".format(_("All Warehouses"), company.abbr)):
|
||||||
|
create_default_warehouse_group(company)
|
||||||
|
|
||||||
|
for warehouse in frappe.get_all("Warehouse", filters={"company": company.name}, fields=["name", "create_account_under",
|
||||||
|
"parent_warehouse", "is_group"]):
|
||||||
|
set_parent_to_warehouses(warehouse, company)
|
||||||
|
set_parent_to_warehouse_acounts(warehouse, company)
|
||||||
|
|
||||||
|
def set_parent_to_warehouses(warehouse, company):
|
||||||
|
warehouse = frappe.get_doc("Warehouse", warehouse.name)
|
||||||
|
warehouse.is_group = "Yes" if warehouse.is_group == "Yes" else "No"
|
||||||
|
|
||||||
|
if not warehouse.parent_warehouse and warehouse.name != "{0} - {1}".format(_("All Warehouses"), company.abbr):
|
||||||
|
warehouse.parent_warehouse = "{0} - {1}".format(_("All Warehouses"), company.abbr)
|
||||||
|
|
||||||
|
warehouse.save(ignore_permissions=True)
|
||||||
|
|
||||||
|
def set_parent_to_warehouse_acounts(warehouse, company):
|
||||||
|
account = frappe.db.get_value("Account", {"warehouse": warehouse.name})
|
||||||
|
stock_group = frappe.db.get_value("Account", {"account_type": "Stock",
|
||||||
|
"is_group": 1, "company": company.name})
|
||||||
|
|
||||||
|
if account and account != "{0} - {1}".format(_("All Warehouses"), company.abbr):
|
||||||
|
account = frappe.get_doc("Account", account)
|
||||||
|
|
||||||
|
if warehouse.create_account_under == stock_group or not warehouse.create_account_under:
|
||||||
|
if not warehouse.parent_warehouse:
|
||||||
|
account.parent_account = "{0} - {1}".format(_("All Warehouses"), company.abbr)
|
||||||
|
else:
|
||||||
|
account.parent_account = frappe.db.get_value("Account", warehouse.parent_warehouse)
|
||||||
|
|
||||||
|
account.save(ignore_permissions=True)
|
||||||
|
|
||||||
|
def create_default_warehouse_group(company):
|
||||||
|
frappe.get_doc({
|
||||||
|
"doctype": "Warehouse",
|
||||||
|
"warehouse_name": _("All Warehouses"),
|
||||||
|
"is_group": "Yes",
|
||||||
|
"company": company.name,
|
||||||
|
"parent_warehouse": ""
|
||||||
|
}).insert(ignore_permissions=True)
|
@ -20,12 +20,12 @@ $(document).bind('toolbar_setup', function() {
|
|||||||
|
|
||||||
// doctypes created via tree
|
// doctypes created via tree
|
||||||
$.extend(frappe.create_routes, {
|
$.extend(frappe.create_routes, {
|
||||||
"Customer Group": "Sales Browser/Customer Group",
|
"Customer Group": "Tree/Customer Group",
|
||||||
"Territory": "Sales Browser/Territory",
|
"Territory": "Tree/Territory",
|
||||||
"Item Group": "Sales Browser/Item Group",
|
"Item Group": "Tree/Item Group",
|
||||||
"Sales Person": "Sales Browser/Sales Person",
|
"Sales Person": "Tree/Sales Person",
|
||||||
"Account": "Accounts Browser/Account",
|
"Account": "Tree/Account",
|
||||||
"Cost Center": "Accounts Browser/Cost Center"
|
"Cost Center": "Tree/Cost Center"
|
||||||
});
|
});
|
||||||
|
|
||||||
// preferred modules for breadcrumbs
|
// preferred modules for breadcrumbs
|
||||||
|
@ -71,7 +71,11 @@ $.extend(erpnext.queries, {
|
|||||||
|
|
||||||
warehouse: function(doc) {
|
warehouse: function(doc) {
|
||||||
return {
|
return {
|
||||||
filters: [["Warehouse", "company", "in", ["", cstr(doc.company)]]]
|
filters: [
|
||||||
|
["Warehouse", "company", "in", ["", cstr(doc.company)]],
|
||||||
|
["Warehouse", "is_group", "=", "No"]
|
||||||
|
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Tree editor for Territory, Customer Group, Item Group, Sales Partner
|
|
@ -1 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
@ -1,166 +0,0 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
|
||||||
// License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
frappe.pages["Sales Browser"].on_page_load = function(wrapper){
|
|
||||||
var page = frappe.ui.make_app_page({
|
|
||||||
parent: wrapper,
|
|
||||||
single_column: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
wrapper.page.add_menu_item(__('Refresh'), function() {
|
|
||||||
wrapper.make_tree();
|
|
||||||
});
|
|
||||||
|
|
||||||
wrapper.make_tree = function() {
|
|
||||||
var ctype = frappe.get_route()[1] || 'Territory';
|
|
||||||
return frappe.call({
|
|
||||||
method: 'erpnext.selling.page.sales_browser.sales_browser.get_children',
|
|
||||||
args: {ctype: ctype},
|
|
||||||
callback: function(r) {
|
|
||||||
var root = r.message[0]["value"];
|
|
||||||
erpnext.sales_chart = new erpnext.SalesChart(ctype, root, page,
|
|
||||||
page.main.css({
|
|
||||||
"min-height": "300px",
|
|
||||||
"padding-bottom": "25px"
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
wrapper.make_tree();
|
|
||||||
}
|
|
||||||
|
|
||||||
frappe.pages['Sales Browser'].on_page_show = function(wrapper){
|
|
||||||
// set route
|
|
||||||
var ctype = frappe.get_route()[1] || 'Territory';
|
|
||||||
|
|
||||||
wrapper.page.set_title(__('{0} Tree',[__(ctype)]));
|
|
||||||
|
|
||||||
if(erpnext.sales_chart && erpnext.sales_chart.ctype != ctype) {
|
|
||||||
wrapper.make_tree();
|
|
||||||
}
|
|
||||||
|
|
||||||
frappe.breadcrumbs.add(frappe.breadcrumbs.last_module || "Selling");
|
|
||||||
};
|
|
||||||
|
|
||||||
erpnext.SalesChart = Class.extend({
|
|
||||||
init: function(ctype, root, page, parent) {
|
|
||||||
$(parent).empty();
|
|
||||||
var me = this;
|
|
||||||
me.ctype = ctype;
|
|
||||||
me.page = page;
|
|
||||||
me.can_read = frappe.model.can_read(this.ctype);
|
|
||||||
me.can_create = frappe.boot.user.can_create.indexOf(this.ctype) !== -1 ||
|
|
||||||
frappe.boot.user.in_create.indexOf(this.ctype) !== -1;
|
|
||||||
me.can_write = frappe.model.can_write(this.ctype);
|
|
||||||
me.can_delete = frappe.model.can_delete(this.ctype);
|
|
||||||
|
|
||||||
me.page.set_primary_action(__("New"), function() {
|
|
||||||
me.new_node();
|
|
||||||
}, "octicon octicon-plus");
|
|
||||||
|
|
||||||
this.tree = new frappe.ui.Tree({
|
|
||||||
parent: $(parent),
|
|
||||||
label: __(root),
|
|
||||||
args: {ctype: ctype},
|
|
||||||
method: 'erpnext.selling.page.sales_browser.sales_browser.get_children',
|
|
||||||
toolbar: [
|
|
||||||
{toggle_btn: true},
|
|
||||||
{
|
|
||||||
label:__("Edit"),
|
|
||||||
condition: function(node) {
|
|
||||||
return !node.root && me.can_read;
|
|
||||||
},
|
|
||||||
click: function(node) {
|
|
||||||
frappe.set_route("Form", me.ctype, node.label);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label:__("Add Child"),
|
|
||||||
condition: function(node) { return me.can_create && node.expandable; },
|
|
||||||
click: function(node) {
|
|
||||||
me.new_node();
|
|
||||||
},
|
|
||||||
btnClass: "hidden-xs"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label:__("Rename"),
|
|
||||||
condition: function(node) { return !node.root && me.can_write; },
|
|
||||||
click: function(node) {
|
|
||||||
frappe.model.rename_doc(me.ctype, node.label, function(new_name) {
|
|
||||||
node.$a.html(new_name);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
btnClass: "hidden-xs"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label:__("Delete"),
|
|
||||||
condition: function(node) { return !node.root && me.can_delete; },
|
|
||||||
click: function(node) {
|
|
||||||
frappe.model.delete_doc(me.ctype, node.label, function() {
|
|
||||||
node.parent.remove();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
btnClass: "hidden-xs"
|
|
||||||
}
|
|
||||||
|
|
||||||
]
|
|
||||||
});
|
|
||||||
},
|
|
||||||
new_node: function() {
|
|
||||||
var me = this;
|
|
||||||
var node = me.tree.get_selected_node();
|
|
||||||
|
|
||||||
if(!(node && node.expandable)) {
|
|
||||||
frappe.msgprint(__("Select a group node first."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fields = [
|
|
||||||
{fieldtype:'Data', fieldname: 'name_field',
|
|
||||||
label:__('New {0} Name',[__(me.ctype)]), reqd:true},
|
|
||||||
{fieldtype:'Select', fieldname:'is_group', label:__('Group Node'), options:'No\nYes',
|
|
||||||
description: __("Further nodes can be only created under 'Group' type nodes")}
|
|
||||||
]
|
|
||||||
|
|
||||||
if(me.ctype == "Sales Person") {
|
|
||||||
fields.splice(-1, 0, {fieldtype:'Link', fieldname:'employee', label:__('Employee'),
|
|
||||||
options:'Employee', description: __("Please enter Employee Id of this sales person")});
|
|
||||||
}
|
|
||||||
|
|
||||||
// the dialog
|
|
||||||
var d = new frappe.ui.Dialog({
|
|
||||||
title: __('New {0}',[__(me.ctype)]),
|
|
||||||
fields: fields
|
|
||||||
})
|
|
||||||
|
|
||||||
d.set_value("is_group", "No");
|
|
||||||
// create
|
|
||||||
d.set_primary_action(__("Create New"), function() {
|
|
||||||
var btn = this;
|
|
||||||
var v = d.get_values();
|
|
||||||
if(!v) return;
|
|
||||||
|
|
||||||
var node = me.tree.get_selected_node();
|
|
||||||
|
|
||||||
v.parent = node.label;
|
|
||||||
v.ctype = me.ctype;
|
|
||||||
|
|
||||||
return frappe.call({
|
|
||||||
method: 'erpnext.selling.page.sales_browser.sales_browser.add_node',
|
|
||||||
args: v,
|
|
||||||
callback: function(r) {
|
|
||||||
if(!r.exc) {
|
|
||||||
d.hide();
|
|
||||||
if(node.expanded) {
|
|
||||||
node.toggle_node();
|
|
||||||
}
|
|
||||||
node.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
d.show();
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"creation": "2012-06-14 15:07:26.000000",
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "Page",
|
|
||||||
"icon": "icon-sitemap",
|
|
||||||
"idx": 1,
|
|
||||||
"modified": "2013-07-11 14:43:56.000000",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Selling",
|
|
||||||
"name": "sales-browser",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"page_name": "Sales Browser",
|
|
||||||
"roles": [
|
|
||||||
{
|
|
||||||
"role": "Sales Master Manager"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "Material Master Manager"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "Accounts Manager"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "Sales Master Manager"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "Purchase Manager"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "Purchase Master Manager"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "Material Manager"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"standard": "Yes"
|
|
||||||
}
|
|
@ -1,37 +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
|
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
|
||||||
def get_children():
|
|
||||||
ctype = frappe.local.form_dict.get('ctype')
|
|
||||||
parent_field = 'parent_' + ctype.lower().replace(' ', '_')
|
|
||||||
parent = frappe.form_dict.get("parent") or ""
|
|
||||||
|
|
||||||
return frappe.db.sql("""select name as value,
|
|
||||||
if(is_group='Yes', 1, 0) as expandable
|
|
||||||
from `tab{ctype}`
|
|
||||||
where docstatus < 2
|
|
||||||
and ifnull(`{parent_field}`,'') = %s
|
|
||||||
order by name""".format(ctype=frappe.db.escape(ctype), parent_field=frappe.db.escape(parent_field)),
|
|
||||||
parent, as_dict=1)
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
|
||||||
def add_node():
|
|
||||||
ctype = frappe.form_dict.get('ctype')
|
|
||||||
parent_field = 'parent_' + ctype.lower().replace(' ', '_')
|
|
||||||
name_field = ctype.lower().replace(' ', '_') + '_name'
|
|
||||||
|
|
||||||
doc = frappe.new_doc(ctype)
|
|
||||||
doc.update({
|
|
||||||
name_field: frappe.form_dict['name_field'],
|
|
||||||
parent_field: frappe.form_dict['parent'],
|
|
||||||
"is_group": frappe.form_dict['is_group']
|
|
||||||
})
|
|
||||||
if ctype == "Sales Person":
|
|
||||||
doc.employee = frappe.form_dict.get('employee')
|
|
||||||
|
|
||||||
doc.save()
|
|
@ -18,11 +18,11 @@ frappe.ui.form.on("Company", {
|
|||||||
!frm.doc.__onload.transactions_exist));
|
!frm.doc.__onload.transactions_exist));
|
||||||
|
|
||||||
frm.add_custom_button(__('Cost Centers'), function() {
|
frm.add_custom_button(__('Cost Centers'), function() {
|
||||||
frappe.set_route('Accounts Browser', 'Cost Center', {'company': frm.doc.name})
|
frappe.set_route('Tree', 'Cost Center', {'company': frm.doc.name})
|
||||||
})
|
})
|
||||||
|
|
||||||
frm.add_custom_button(__('Chart of Accounts'), function() {
|
frm.add_custom_button(__('Chart of Accounts'), function() {
|
||||||
frappe.set_route('Accounts Browser', 'Account', {'company': frm.doc.name})
|
frappe.set_route('Tree', 'Account', {'company': frm.doc.name})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,15 +87,23 @@ class Company(Document):
|
|||||||
.format(self.country.lower()))(self)
|
.format(self.country.lower()))(self)
|
||||||
|
|
||||||
def create_default_warehouses(self):
|
def create_default_warehouses(self):
|
||||||
for whname in (_("Stores"), _("Work In Progress"), _("Finished Goods")):
|
for wh_detail in [
|
||||||
if not frappe.db.exists("Warehouse", whname + " - " + self.abbr):
|
{"warehouse_name": _("All Warehouses"), "is_group": "Yes"},
|
||||||
|
{"warehouse_name": _("Stores"), "is_group": "No"},
|
||||||
|
{"warehouse_name": _("Work In Progress"), "is_group": "No"},
|
||||||
|
{"warehouse_name": _("Finished Goods"), "is_group": "No"}]:
|
||||||
|
|
||||||
|
if not frappe.db.exists("Warehouse", "{0} - {1}".format(wh_detail["warehouse_name"], self.abbr)):
|
||||||
stock_group = frappe.db.get_value("Account", {"account_type": "Stock",
|
stock_group = frappe.db.get_value("Account", {"account_type": "Stock",
|
||||||
"is_group": 1, "company": self.name})
|
"is_group": 1, "company": self.name})
|
||||||
if stock_group:
|
if stock_group:
|
||||||
warehouse = frappe.get_doc({
|
warehouse = frappe.get_doc({
|
||||||
"doctype":"Warehouse",
|
"doctype":"Warehouse",
|
||||||
"warehouse_name": whname,
|
"warehouse_name": wh_detail["warehouse_name"],
|
||||||
|
"is_group": wh_detail["is_group"],
|
||||||
"company": self.name,
|
"company": self.name,
|
||||||
|
"parent_warehouse": "{0} - {1}".format(_("All Warehouses"), self.abbr) \
|
||||||
|
if wh_detail["is_group"] == "No" else "",
|
||||||
"create_account_under": stock_group
|
"create_account_under": stock_group
|
||||||
})
|
})
|
||||||
warehouse.flags.ignore_permissions = True
|
warehouse.flags.ignore_permissions = True
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
cur_frm.list_route = "Sales Browser/Customer Group";
|
cur_frm.list_route = "Tree/Customer Group";
|
||||||
|
|
||||||
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
||||||
cur_frm.cscript.set_root_readonly(doc);
|
cur_frm.cscript.set_root_readonly(doc);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
frappe.ui.form.on("Item Group", {
|
frappe.ui.form.on("Item Group", {
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
frm.list_route = "Sales Browser/Item Group";
|
frm.list_route = "Tree/Item Group";
|
||||||
|
|
||||||
//get query select item group
|
//get query select item group
|
||||||
frm.fields_dict['parent_item_group'].get_query = function(doc,cdt,cdn) {
|
frm.fields_dict['parent_item_group'].get_query = function(doc,cdt,cdn) {
|
||||||
@ -19,7 +19,7 @@ frappe.ui.form.on("Item Group", {
|
|||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
frm.trigger("set_root_readonly");
|
frm.trigger("set_root_readonly");
|
||||||
frm.add_custom_button(__("Item Group Tree"), function() {
|
frm.add_custom_button(__("Item Group Tree"), function() {
|
||||||
frappe.set_route("Sales Browser", "Item Group");
|
frappe.set_route("Tree", "Item Group");
|
||||||
}, "icon-sitemap");
|
}, "icon-sitemap");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
cur_frm.list_route = "Sales Browser/Sales Person";
|
cur_frm.list_route = "Tree/Sales Person";
|
||||||
|
|
||||||
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
||||||
cur_frm.cscript.set_root_readonly(doc);
|
cur_frm.cscript.set_root_readonly(doc);
|
||||||
|
11
erpnext/setup/doctype/sales_person/sales_person_tree.js
Normal file
11
erpnext/setup/doctype/sales_person/sales_person_tree.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
frappe.treeview_settings["Sales Person"] = {
|
||||||
|
fields: [
|
||||||
|
{fieldtype:'Data', fieldname: 'name_field',
|
||||||
|
label:__('New Sales Person Name'), reqd:true},
|
||||||
|
{fieldtype:'Link', fieldname:'employee',
|
||||||
|
label:__('Employee'), options:'Employee',
|
||||||
|
description: __("Please enter Employee Id of this sales person")},
|
||||||
|
{fieldtype:'Select', fieldname:'is_group', label:__('Group Node'), options:'No\nYes',
|
||||||
|
description: __("Further nodes can be only created under 'Group' type nodes")}
|
||||||
|
],
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
cur_frm.list_route = "Sales Browser/Territory";
|
cur_frm.list_route = "Tree/Territory";
|
||||||
|
|
||||||
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
||||||
cur_frm.cscript.set_root_readonly(doc);
|
cur_frm.cscript.set_root_readonly(doc);
|
||||||
|
@ -52,26 +52,26 @@ def update_page_info(bootinfo):
|
|||||||
bootinfo.page_info.update({
|
bootinfo.page_info.update({
|
||||||
"Chart of Accounts": {
|
"Chart of Accounts": {
|
||||||
"title": "Chart of Accounts",
|
"title": "Chart of Accounts",
|
||||||
"route": "Accounts Browser/Account"
|
"route": "Tree/Account"
|
||||||
},
|
},
|
||||||
"Chart of Cost Centers": {
|
"Chart of Cost Centers": {
|
||||||
"title": "Chart of Cost Centers",
|
"title": "Chart of Cost Centers",
|
||||||
"route": "Accounts Browser/Cost Center"
|
"route": "Tree/Cost Center"
|
||||||
},
|
},
|
||||||
"Item Group Tree": {
|
"Item Group Tree": {
|
||||||
"title": "Item Group Tree",
|
"title": "Item Group Tree",
|
||||||
"route": "Sales Browser/Item Group"
|
"route": "Tree/Item Group"
|
||||||
},
|
},
|
||||||
"Customer Group Tree": {
|
"Customer Group Tree": {
|
||||||
"title": "Customer Group Tree",
|
"title": "Customer Group Tree",
|
||||||
"route": "Sales Browser/Customer Group"
|
"route": "Tree/Customer Group"
|
||||||
},
|
},
|
||||||
"Territory Tree": {
|
"Territory Tree": {
|
||||||
"title": "Territory Tree",
|
"title": "Territory Tree",
|
||||||
"route": "Sales Browser/Territory"
|
"route": "Tree/Territory"
|
||||||
},
|
},
|
||||||
"Sales Person Tree": {
|
"Sales Person Tree": {
|
||||||
"title": "Sales Person Tree",
|
"title": "Sales Person Tree",
|
||||||
"route": "Sales Browser/Sales Person"
|
"route": "Tree/Sales Person"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
|
from frappe import _
|
||||||
from frappe.utils import flt, nowdate
|
from frappe.utils import flt, nowdate
|
||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
@ -15,13 +16,19 @@ class Bin(Document):
|
|||||||
self.validate_mandatory()
|
self.validate_mandatory()
|
||||||
|
|
||||||
self.projected_qty = flt(self.actual_qty) + flt(self.ordered_qty) + \
|
self.projected_qty = flt(self.actual_qty) + flt(self.ordered_qty) + \
|
||||||
flt(self.indented_qty) + flt(self.planned_qty) - flt(self.reserved_qty)
|
flt(self.indented_qty) + flt(self.planned_qty) - flt(self.reserved_qty)
|
||||||
|
|
||||||
|
self.block_transactions_against_group_warehouse()
|
||||||
|
|
||||||
def validate_mandatory(self):
|
def validate_mandatory(self):
|
||||||
qf = ['actual_qty', 'reserved_qty', 'ordered_qty', 'indented_qty']
|
qf = ['actual_qty', 'reserved_qty', 'ordered_qty', 'indented_qty']
|
||||||
for f in qf:
|
for f in qf:
|
||||||
if (not getattr(self, f, None)) or (not self.get(f)):
|
if (not getattr(self, f, None)) or (not self.get(f)):
|
||||||
self.set(f, 0.0)
|
self.set(f, 0.0)
|
||||||
|
|
||||||
|
def block_transactions_against_group_warehouse(self):
|
||||||
|
from erpnext.stock.utils import is_group_warehouse
|
||||||
|
is_group_warehouse(self.warehouse)
|
||||||
|
|
||||||
def update_stock(self, args, allow_negative_stock=False, via_landed_cost_voucher=False):
|
def update_stock(self, args, allow_negative_stock=False, via_landed_cost_voucher=False):
|
||||||
self.update_qty(args)
|
self.update_qty(args)
|
||||||
|
@ -160,6 +160,28 @@ $.extend(erpnext.item, {
|
|||||||
frm.fields_dict.supplier_items.grid.get_field("supplier").get_query = function(doc, cdt, cdn) {
|
frm.fields_dict.supplier_items.grid.get_field("supplier").get_query = function(doc, cdt, cdn) {
|
||||||
return { query: "erpnext.controllers.queries.supplier_query" }
|
return { query: "erpnext.controllers.queries.supplier_query" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frm.fields_dict['default_warehouse'].get_query = function(doc) {
|
||||||
|
return {
|
||||||
|
filters: { "is_group": "No" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frm.fields_dict.reorder_levels.grid.get_field("warehouse_group").get_query = function(doc, cdt, cdn) {
|
||||||
|
return {
|
||||||
|
filters: { "is_group": "Yes" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frm.fields_dict.reorder_levels.grid.get_field("warehouse").get_query = function(doc, cdt, cdn) {
|
||||||
|
var d = locals[cdt][cdn];
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
"is_group": "No",
|
||||||
|
"parent_warehouse": d.warehouse_group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -227,6 +227,35 @@
|
|||||||
"warehouse_reorder_qty": 20
|
"warehouse_reorder_qty": 20
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default_warehouse": "_Test Warehouse Group-C1 - _TC",
|
||||||
|
"description": "_Test Item 1",
|
||||||
|
"doctype": "Item",
|
||||||
|
"expense_account": "_Test Account Cost for Goods Sold - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"has_batch_no": 0,
|
||||||
|
"has_serial_no": 0,
|
||||||
|
"income_account": "Sales - _TC",
|
||||||
|
"inspection_required": 0,
|
||||||
|
"is_stock_item": 1,
|
||||||
|
"is_sub_contracted_item": 0,
|
||||||
|
"item_code": "_Test Item Warehouse Group Wise Reorder",
|
||||||
|
"item_group": "_Test Item Group",
|
||||||
|
"item_name": "_Test Item Warehouse Group Wise Reorder",
|
||||||
|
"apply_warehouse_wise_reorder_level": 1,
|
||||||
|
"reorder_levels": [
|
||||||
|
{
|
||||||
|
"warehouse_group": "_Test Warehouse Group - _TC",
|
||||||
|
"material_request_type": "Purchase",
|
||||||
|
"warehouse": "_Test Warehouse Group-C1 - _TC",
|
||||||
|
"warehouse_reorder_level": 20,
|
||||||
|
"warehouse_reorder_qty": 20
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stock_uom": "_Test UOM",
|
||||||
|
"show_in_website": 1,
|
||||||
|
"website_warehouse": "_Test Warehouse Group-C1 - _TC"
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
@ -3,11 +3,39 @@
|
|||||||
"allow_import": 0,
|
"allow_import": 0,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"autoname": "hash",
|
"autoname": "hash",
|
||||||
|
"beta": 0,
|
||||||
"creation": "2013-03-07 11:42:59",
|
"creation": "2013-03-07 11:42:59",
|
||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"fieldname": "warehouse_group",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "Warehouse Group",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"options": "Warehouse",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -16,6 +44,7 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Warehouse",
|
"label": "Warehouse",
|
||||||
@ -24,6 +53,7 @@
|
|||||||
"options": "Warehouse",
|
"options": "Warehouse",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
@ -39,6 +69,7 @@
|
|||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Re-order Level",
|
"label": "Re-order Level",
|
||||||
@ -46,6 +77,7 @@
|
|||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
@ -61,6 +93,7 @@
|
|||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Re-order Qty",
|
"label": "Re-order Qty",
|
||||||
@ -68,6 +101,7 @@
|
|||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
@ -83,6 +117,7 @@
|
|||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Material Request Type",
|
"label": "Material Request Type",
|
||||||
@ -91,6 +126,7 @@
|
|||||||
"options": "Purchase\nTransfer",
|
"options": "Purchase\nTransfer",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
@ -102,18 +138,21 @@
|
|||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
|
"image_view": 0,
|
||||||
"in_create": 1,
|
"in_create": 1,
|
||||||
"in_dialog": 0,
|
"in_dialog": 0,
|
||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2015-11-16 06:29:48.492627",
|
"modified": "2016-06-20 15:52:01.978593",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Item Reorder",
|
"name": "Item Reorder",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
|
"quick_entry": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"read_only_onload": 0
|
"read_only_onload": 0,
|
||||||
|
"track_seen": 0
|
||||||
}
|
}
|
@ -79,8 +79,11 @@ class TestStockEntry(unittest.TestCase):
|
|||||||
|
|
||||||
def test_auto_material_request_for_variant(self):
|
def test_auto_material_request_for_variant(self):
|
||||||
self._test_auto_material_request("_Test Variant Item-S")
|
self._test_auto_material_request("_Test Variant Item-S")
|
||||||
|
|
||||||
def _test_auto_material_request(self, item_code, material_request_type="Purchase"):
|
def test_auto_material_request_for_warehouse_group(self):
|
||||||
|
self._test_auto_material_request("_Test Item Warehouse Group Wise Reorder", warehouse="_Test Warehouse Group-C1 - _TC")
|
||||||
|
|
||||||
|
def _test_auto_material_request(self, item_code, material_request_type="Purchase", warehouse="_Test Warehouse - _TC"):
|
||||||
item = frappe.get_doc("Item", item_code)
|
item = frappe.get_doc("Item", item_code)
|
||||||
|
|
||||||
if item.variant_of:
|
if item.variant_of:
|
||||||
@ -89,14 +92,14 @@ class TestStockEntry(unittest.TestCase):
|
|||||||
template = item
|
template = item
|
||||||
|
|
||||||
projected_qty, actual_qty = frappe.db.get_value("Bin", {"item_code": item_code,
|
projected_qty, actual_qty = frappe.db.get_value("Bin", {"item_code": item_code,
|
||||||
"warehouse": "_Test Warehouse - _TC"}, ["projected_qty", "actual_qty"]) or [0, 0]
|
"warehouse": warehouse}, ["projected_qty", "actual_qty"]) or [0, 0]
|
||||||
|
|
||||||
# stock entry reqd for auto-reorder
|
# stock entry reqd for auto-reorder
|
||||||
create_stock_reconciliation(item_code=item_code, warehouse="_Test Warehouse - _TC",
|
create_stock_reconciliation(item_code=item_code, warehouse=warehouse,
|
||||||
qty = actual_qty + abs(projected_qty) + 10, rate=100)
|
qty = actual_qty + abs(projected_qty) + 10, rate=100)
|
||||||
|
|
||||||
projected_qty = frappe.db.get_value("Bin", {"item_code": item_code,
|
projected_qty = frappe.db.get_value("Bin", {"item_code": item_code,
|
||||||
"warehouse": "_Test Warehouse - _TC"}, "projected_qty") or 0
|
"warehouse": warehouse}, "projected_qty") or 0
|
||||||
|
|
||||||
frappe.db.set_value("Stock Settings", None, "auto_indent", 1)
|
frappe.db.set_value("Stock Settings", None, "auto_indent", 1)
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ class StockLedgerEntry(Document):
|
|||||||
validate_warehouse_company(self.warehouse, self.company)
|
validate_warehouse_company(self.warehouse, self.company)
|
||||||
self.scrub_posting_time()
|
self.scrub_posting_time()
|
||||||
self.validate_and_set_fiscal_year()
|
self.validate_and_set_fiscal_year()
|
||||||
|
self.block_transactions_against_group_warehouse()
|
||||||
|
|
||||||
from erpnext.accounts.utils import validate_fiscal_year
|
from erpnext.accounts.utils import validate_fiscal_year
|
||||||
validate_fiscal_year(self.posting_date, self.fiscal_year, self.meta.get_label("posting_date"), self)
|
validate_fiscal_year(self.posting_date, self.fiscal_year, self.meta.get_label("posting_date"), self)
|
||||||
@ -117,6 +118,9 @@ class StockLedgerEntry(Document):
|
|||||||
if not self.fiscal_year:
|
if not self.fiscal_year:
|
||||||
self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0]
|
self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0]
|
||||||
|
|
||||||
|
def block_transactions_against_group_warehouse(self):
|
||||||
|
from erpnext.stock.utils import is_group_warehouse
|
||||||
|
is_group_warehouse(self.warehouse)
|
||||||
|
|
||||||
def on_doctype_update():
|
def on_doctype_update():
|
||||||
if not frappe.db.sql("""show index from `tabStock Ledger Entry`
|
if not frappe.db.sql("""show index from `tabStock Ledger Entry`
|
||||||
|
@ -116,10 +116,11 @@ def create_stock_reconciliation(**args):
|
|||||||
def set_valuation_method(item_code, valuation_method):
|
def set_valuation_method(item_code, valuation_method):
|
||||||
frappe.db.set_value("Item", item_code, "valuation_method", valuation_method)
|
frappe.db.set_value("Item", item_code, "valuation_method", valuation_method)
|
||||||
|
|
||||||
for warehouse in frappe.get_all("Warehouse", filters={"company": "_Test Company"}):
|
for warehouse in frappe.get_all("Warehouse", filters={"company": "_Test Company"}, fields=["name", "is_group"]):
|
||||||
update_entries_after({
|
if warehouse.is_group == "No":
|
||||||
"item_code": item_code,
|
update_entries_after({
|
||||||
"warehouse": warehouse.name
|
"item_code": item_code,
|
||||||
}, allow_negative_stock=1)
|
"warehouse": warehouse.name
|
||||||
|
}, allow_negative_stock=1)
|
||||||
|
|
||||||
test_dependencies = ["Item", "Warehouse"]
|
test_dependencies = ["Item", "Warehouse"]
|
||||||
|
@ -3,35 +3,68 @@
|
|||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"create_account_under": "Stock Assets - _TC",
|
"create_account_under": "Stock Assets - _TC",
|
||||||
"doctype": "Warehouse",
|
"doctype": "Warehouse",
|
||||||
"warehouse_name": "_Test Warehouse"
|
"warehouse_name": "_Test Warehouse",
|
||||||
},
|
"is_group": "No"
|
||||||
{
|
|
||||||
"company": "_Test Company",
|
|
||||||
"create_account_under": "Fixed Assets - _TC",
|
|
||||||
"doctype": "Warehouse",
|
|
||||||
"warehouse_name": "_Test Warehouse 1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"company": "_Test Company",
|
|
||||||
"create_account_under": "Fixed Assets - _TC",
|
|
||||||
"doctype": "Warehouse",
|
|
||||||
"warehouse_name": "_Test Warehouse 2"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"create_account_under": "Stock Assets - _TC",
|
"create_account_under": "Stock Assets - _TC",
|
||||||
"doctype": "Warehouse",
|
"doctype": "Warehouse",
|
||||||
"warehouse_name": "_Test Rejected Warehouse"
|
"warehouse_name": "_Test Warehouse",
|
||||||
|
"is_group": "No"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"company": "_Test Company",
|
||||||
|
"create_account_under": "Fixed Assets - _TC",
|
||||||
|
"doctype": "Warehouse",
|
||||||
|
"warehouse_name": "_Test Warehouse 1",
|
||||||
|
"is_group": "No"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"company": "_Test Company",
|
||||||
|
"create_account_under": "Fixed Assets - _TC",
|
||||||
|
"doctype": "Warehouse",
|
||||||
|
"warehouse_name": "_Test Warehouse 2",
|
||||||
|
"is_group": "No"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"company": "_Test Company",
|
||||||
|
"create_account_under": "Stock Assets - _TC",
|
||||||
|
"doctype": "Warehouse",
|
||||||
|
"warehouse_name": "_Test Rejected Warehouse",
|
||||||
|
"is_group": "No"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"company": "_Test Company 1",
|
"company": "_Test Company 1",
|
||||||
"create_account_under": "Stock Assets - _TC1",
|
"create_account_under": "Stock Assets - _TC1",
|
||||||
"doctype": "Warehouse",
|
"doctype": "Warehouse",
|
||||||
"warehouse_name": "_Test Warehouse 2"
|
"warehouse_name": "_Test Warehouse 2",
|
||||||
|
"is_group": "No"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"doctype": "Warehouse",
|
"doctype": "Warehouse",
|
||||||
"warehouse_name": "_Test Warehouse No Account"
|
"warehouse_name": "_Test Warehouse No Account",
|
||||||
|
"is_group": "No"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"company": "_Test Company",
|
||||||
|
"doctype": "Warehouse",
|
||||||
|
"warehouse_name": "_Test Warehouse Group",
|
||||||
|
"is_group": "Yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"company": "_Test Company",
|
||||||
|
"doctype": "Warehouse",
|
||||||
|
"warehouse_name": "_Test Warehouse Group-C1",
|
||||||
|
"is_group": "No",
|
||||||
|
"parent_warehouse": "_Test Warehouse Group - _TC"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"company": "_Test Company",
|
||||||
|
"doctype": "Warehouse",
|
||||||
|
"warehouse_name": "_Test Warehouse Group-C2",
|
||||||
|
"is_group": "No",
|
||||||
|
"parent_warehouse": "_Test Warehouse Group - _TC"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -4,4 +4,22 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
test_records = frappe.get_test_records('Warehouse')
|
import unittest
|
||||||
|
test_records = frappe.get_test_records('Warehouse')
|
||||||
|
|
||||||
|
class TestWarehouse(unittest.TestCase):
|
||||||
|
def test_parent_warehouse(self):
|
||||||
|
parent_warehouse = frappe.get_doc("Warehouse", "_Test Warehouse Group - _TC")
|
||||||
|
self.assertEquals(parent_warehouse.is_group, "Yes")
|
||||||
|
|
||||||
|
def test_warehouse_hierarchy(self):
|
||||||
|
p_warehouse = frappe.get_doc("Warehouse", "_Test Warehouse Group - _TC")
|
||||||
|
|
||||||
|
child_warehouses = frappe.db.sql("""select name, is_group, parent_warehouse from `tabWarehouse` wh
|
||||||
|
where wh.lft > %s and wh.rgt < %s""", (p_warehouse.lft, p_warehouse.rgt), as_dict=1)
|
||||||
|
|
||||||
|
for child_warehouse in child_warehouses:
|
||||||
|
self.assertEquals(p_warehouse.name, child_warehouse.parent_warehouse)
|
||||||
|
self.assertEquals(child_warehouse.is_group, "No")
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
cur_frm.list_route = "Tree/Warehouse";
|
||||||
|
|
||||||
frappe.ui.form.on("Warehouse", {
|
frappe.ui.form.on("Warehouse", {
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
frm.toggle_display('warehouse_name', frm.doc.__islocal);
|
frm.toggle_display('warehouse_name', frm.doc.__islocal);
|
||||||
@ -17,10 +19,20 @@ frappe.ui.form.on("Warehouse", {
|
|||||||
frappe.set_route("query-report", "General Ledger");
|
frappe.set_route("query-report", "General Ledger");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frm.fields_dict['parent_warehouse'].get_query = function(doc) {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
"is_group": "Yes",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cur_frm.set_query("create_account_under", function() {
|
cur_frm.set_query("create_account_under", function() {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 1,
|
"allow_rename": 1,
|
||||||
|
"beta": 0,
|
||||||
"creation": "2013-03-07 18:50:32",
|
"creation": "2013-03-07 18:50:32",
|
||||||
"custom": 0,
|
"custom": 0,
|
||||||
"description": "A logical Warehouse against which stock entries are made.",
|
"description": "A logical Warehouse against which stock entries are made.",
|
||||||
@ -420,6 +421,159 @@
|
|||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"fieldname": "tree_details",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "Tree Details",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"fieldname": "parent_warehouse",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 1,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "Parent Warehouse",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"options": "Warehouse",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 1,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"fieldname": "is_group",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Has Child Node",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"options": "\nYes\nNo",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 1,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"fieldname": "lft",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "lft",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"fieldname": "rgt",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "rgt",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"fieldname": "old_parent",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "Old Parent",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"options": "Warehouse",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
@ -432,7 +586,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2016-04-18 05:44:24.837579",
|
"modified": "2016-05-23 21:25:21.396188",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Warehouse",
|
"name": "Warehouse",
|
||||||
|
@ -5,10 +5,11 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import cint, validate_email_add
|
from frappe.utils import cint, validate_email_add
|
||||||
from frappe import throw, msgprint, _
|
from frappe import throw, msgprint, _
|
||||||
|
from frappe.utils.nestedset import NestedSet
|
||||||
|
|
||||||
from frappe.model.document import Document
|
class Warehouse(NestedSet):
|
||||||
|
nsm_parent_field = 'parent_warehouse'
|
||||||
class Warehouse(Document):
|
|
||||||
def autoname(self):
|
def autoname(self):
|
||||||
suffix = " - " + frappe.db.get_value("Company", self.company, "abbr")
|
suffix = " - " + frappe.db.get_value("Company", self.company, "abbr")
|
||||||
if not self.warehouse_name.endswith(suffix):
|
if not self.warehouse_name.endswith(suffix):
|
||||||
@ -45,6 +46,7 @@ class Warehouse(Document):
|
|||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
self.create_account_head()
|
self.create_account_head()
|
||||||
|
self.update_nsm_model()
|
||||||
|
|
||||||
def create_account_head(self):
|
def create_account_head(self):
|
||||||
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
||||||
@ -55,8 +57,9 @@ class Warehouse(Document):
|
|||||||
ac_doc = frappe.get_doc({
|
ac_doc = frappe.get_doc({
|
||||||
"doctype": "Account",
|
"doctype": "Account",
|
||||||
'account_name': self.warehouse_name,
|
'account_name': self.warehouse_name,
|
||||||
'parent_account': self.create_account_under,
|
'parent_account': self.parent_warehouse if self.parent_warehouse \
|
||||||
'is_group':0,
|
else self.create_account_under,
|
||||||
|
'is_group': 1 if self.is_group=="Yes" else 0 ,
|
||||||
'company':self.company,
|
'company':self.company,
|
||||||
"account_type": "Warehouse",
|
"account_type": "Warehouse",
|
||||||
"warehouse": self.name,
|
"warehouse": self.name,
|
||||||
@ -75,13 +78,16 @@ class Warehouse(Document):
|
|||||||
{"account_name": "Stock Assets", "company": self.company})
|
{"account_name": "Stock Assets", "company": self.company})
|
||||||
|
|
||||||
if parent_account:
|
if parent_account:
|
||||||
|
frappe.db.set_value("Warehouse", self.name, "create_account_under", parent_account)
|
||||||
self.create_account_under = parent_account
|
self.create_account_under = parent_account
|
||||||
else:
|
else:
|
||||||
frappe.throw(_("Please enter parent account group for warehouse {0}").format(self.name))
|
frappe.throw(_("Please enter parent account group for warehouse {0}").format(self.name))
|
||||||
elif frappe.db.get_value("Account", self.create_account_under, "company") != self.company:
|
elif frappe.db.get_value("Account", self.create_account_under, "company") != self.company:
|
||||||
frappe.throw(_("Warehouse {0}: Parent account {1} does not bolong to the company {2}")
|
frappe.throw(_("Warehouse {0}: Parent account {1} does not bolong to the company {2}")
|
||||||
.format(self.name, self.create_account_under, self.company))
|
.format(self.name, self.create_account_under, self.company))
|
||||||
|
|
||||||
|
def update_nsm_model(self):
|
||||||
|
frappe.utils.nestedset.update_nsm(self)
|
||||||
|
|
||||||
def on_trash(self):
|
def on_trash(self):
|
||||||
# delete bin
|
# delete bin
|
||||||
@ -101,6 +107,11 @@ class Warehouse(Document):
|
|||||||
if frappe.db.sql("""select name from `tabStock Ledger Entry`
|
if frappe.db.sql("""select name from `tabStock Ledger Entry`
|
||||||
where warehouse = %s""", self.name):
|
where warehouse = %s""", self.name):
|
||||||
throw(_("Warehouse can not be deleted as stock ledger entry exists for this warehouse."))
|
throw(_("Warehouse can not be deleted as stock ledger entry exists for this warehouse."))
|
||||||
|
|
||||||
|
if frappe.db.sql("""select name from `tabWarehouse` where parent_warehouse = %s""", self.name):
|
||||||
|
throw(_("Child warehouse exists for this warehouse. You can not delete this warehouse."))
|
||||||
|
|
||||||
|
self.update_nsm_model()
|
||||||
|
|
||||||
def before_rename(self, olddn, newdn, merge=False):
|
def before_rename(self, olddn, newdn, merge=False):
|
||||||
# Add company abbr if not provided
|
# Add company abbr if not provided
|
||||||
@ -161,3 +172,51 @@ class Warehouse(Document):
|
|||||||
|
|
||||||
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock)
|
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock)
|
||||||
frappe.db.auto_commit_on_many_writes = 0
|
frappe.db.auto_commit_on_many_writes = 0
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_children():
|
||||||
|
from erpnext.stock.utils import get_stock_value_on
|
||||||
|
doctype = frappe.local.form_dict.get('doctype')
|
||||||
|
company = frappe.local.form_dict.get('company')
|
||||||
|
|
||||||
|
parent_field = 'parent_' + doctype.lower().replace(' ', '_')
|
||||||
|
parent = frappe.form_dict.get("parent") or ""
|
||||||
|
|
||||||
|
if parent == "Warehouses":
|
||||||
|
parent = ""
|
||||||
|
|
||||||
|
warehouses = frappe.db.sql("""select name as value,
|
||||||
|
if(is_group='Yes', 1, 0) as expandable
|
||||||
|
from `tab{doctype}`
|
||||||
|
where docstatus < 2
|
||||||
|
and ifnull(`{parent_field}`,'') = %s and `company` = %s
|
||||||
|
order by name""".format(doctype=frappe.db.escape(doctype), parent_field=frappe.db.escape(parent_field)),
|
||||||
|
(parent, company), as_dict=1)
|
||||||
|
|
||||||
|
# return warehouses
|
||||||
|
for wh in warehouses:
|
||||||
|
wh["balance"] = get_stock_value_on(warehouse=wh.value)
|
||||||
|
return warehouses
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def add_node():
|
||||||
|
doctype = frappe.form_dict.get('doctype')
|
||||||
|
company = frappe.form_dict.get('company')
|
||||||
|
parent_field = 'parent_' + doctype.lower().replace(' ', '_')
|
||||||
|
name_field = doctype.lower().replace(' ', '_') + '_name'
|
||||||
|
|
||||||
|
doc = frappe.new_doc(doctype)
|
||||||
|
|
||||||
|
parent = frappe.form_dict['parent']
|
||||||
|
|
||||||
|
if cint(frappe.form_dict['is_root']):
|
||||||
|
parent = None
|
||||||
|
|
||||||
|
doc.update({
|
||||||
|
name_field: frappe.form_dict['name_field'],
|
||||||
|
parent_field: parent,
|
||||||
|
"is_group": frappe.form_dict['is_group'],
|
||||||
|
"company": company
|
||||||
|
})
|
||||||
|
|
||||||
|
doc.save()
|
||||||
|
20
erpnext/stock/doctype/warehouse/warehouse_tree.js
Normal file
20
erpnext/stock/doctype/warehouse/warehouse_tree.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
frappe.treeview_settings['Warehouse'] = {
|
||||||
|
get_tree_nodes: "erpnext.stock.doctype.warehouse.warehouse.get_children",
|
||||||
|
add_tree_node: "erpnext.stock.doctype.warehouse.warehouse.add_node",
|
||||||
|
get_tree_root: false,
|
||||||
|
root_label: "Warehouses",
|
||||||
|
filters: [{
|
||||||
|
fieldname: "company",
|
||||||
|
fieldtype:"Select",
|
||||||
|
options: $.map(locals[':Company'], function(c) { return c.name; }).sort(),
|
||||||
|
label: __("Company"),
|
||||||
|
default: frappe.defaults.get_default('company') ? frappe.defaults.get_default('company'): ""
|
||||||
|
}],
|
||||||
|
onrender: function(node) {
|
||||||
|
if (node.data && node.data.balance!==undefined) {
|
||||||
|
$('<span class="balance-area pull-right text-muted small">'
|
||||||
|
+ format_currency(Math.abs(node.data.balance), node.data.company_currency)
|
||||||
|
+ '</span>').insertBefore(node.$ul);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -37,7 +37,7 @@ def _reorder_item():
|
|||||||
|
|
||||||
item_warehouse_projected_qty = get_item_warehouse_projected_qty(items_to_consider)
|
item_warehouse_projected_qty = get_item_warehouse_projected_qty(items_to_consider)
|
||||||
|
|
||||||
def add_to_material_request(item_code, warehouse, reorder_level, reorder_qty, material_request_type):
|
def add_to_material_request(item_code, warehouse, reorder_level, reorder_qty, material_request_type, warehouse_group=None):
|
||||||
if warehouse not in warehouse_company:
|
if warehouse not in warehouse_company:
|
||||||
# a disabled warehouse
|
# a disabled warehouse
|
||||||
return
|
return
|
||||||
@ -46,7 +46,10 @@ def _reorder_item():
|
|||||||
reorder_qty = flt(reorder_qty)
|
reorder_qty = flt(reorder_qty)
|
||||||
|
|
||||||
# projected_qty will be 0 if Bin does not exist
|
# projected_qty will be 0 if Bin does not exist
|
||||||
projected_qty = flt(item_warehouse_projected_qty.get(item_code, {}).get(warehouse))
|
if warehouse_group:
|
||||||
|
projected_qty = flt(item_warehouse_projected_qty.get(item_code, {}).get(warehouse_group))
|
||||||
|
else:
|
||||||
|
projected_qty = flt(item_warehouse_projected_qty.get(item_code, {}).get(warehouse))
|
||||||
|
|
||||||
if (reorder_level or reorder_qty) and projected_qty < reorder_level:
|
if (reorder_level or reorder_qty) and projected_qty < reorder_level:
|
||||||
deficiency = reorder_level - projected_qty
|
deficiency = reorder_level - projected_qty
|
||||||
@ -70,7 +73,7 @@ def _reorder_item():
|
|||||||
if item.get("reorder_levels"):
|
if item.get("reorder_levels"):
|
||||||
for d in item.get("reorder_levels"):
|
for d in item.get("reorder_levels"):
|
||||||
add_to_material_request(item_code, d.warehouse, d.warehouse_reorder_level,
|
add_to_material_request(item_code, d.warehouse, d.warehouse_reorder_level,
|
||||||
d.warehouse_reorder_qty, d.material_request_type)
|
d.warehouse_reorder_qty, d.material_request_type, warehouse_group=d.warehouse_group)
|
||||||
|
|
||||||
if material_requests:
|
if material_requests:
|
||||||
return create_material_request(material_requests)
|
return create_material_request(material_requests)
|
||||||
@ -82,9 +85,17 @@ def get_item_warehouse_projected_qty(items_to_consider):
|
|||||||
from tabBin where item_code in ({0})
|
from tabBin where item_code in ({0})
|
||||||
and (warehouse != "" and warehouse is not null)"""\
|
and (warehouse != "" and warehouse is not null)"""\
|
||||||
.format(", ".join(["%s"] * len(items_to_consider))), items_to_consider):
|
.format(", ".join(["%s"] * len(items_to_consider))), items_to_consider):
|
||||||
|
|
||||||
item_warehouse_projected_qty.setdefault(item_code, {})[warehouse] = flt(projected_qty)
|
item_warehouse_projected_qty.setdefault(item_code, {})[warehouse] = flt(projected_qty)
|
||||||
|
|
||||||
|
warehouse_doc = frappe.get_doc("Warehouse", warehouse)
|
||||||
|
|
||||||
|
if warehouse_doc.parent_warehouse:
|
||||||
|
if not item_warehouse_projected_qty.get(item_code, {}).get(warehouse_doc.parent_warehouse):
|
||||||
|
item_warehouse_projected_qty.setdefault(item_code, {})[warehouse_doc.parent_warehouse] = flt(projected_qty)
|
||||||
|
else:
|
||||||
|
item_warehouse_projected_qty[item_code][warehouse_doc.parent_warehouse] += flt(projected_qty)
|
||||||
|
|
||||||
return item_warehouse_projected_qty
|
return item_warehouse_projected_qty
|
||||||
|
|
||||||
def create_material_request(material_requests):
|
def create_material_request(material_requests):
|
||||||
|
@ -71,7 +71,9 @@ def get_conditions(filters):
|
|||||||
conditions += " and item_code = '%s'" % frappe.db.escape(filters.get("item_code"), percent=False)
|
conditions += " and item_code = '%s'" % frappe.db.escape(filters.get("item_code"), percent=False)
|
||||||
|
|
||||||
if filters.get("warehouse"):
|
if filters.get("warehouse"):
|
||||||
conditions += " and warehouse = '%s'" % frappe.db.escape(filters.get("warehouse"), percent=False)
|
lft, rgt = frappe.db.get_value("Warehouse", filters.get("warehouse"), ["lft", "rgt"])
|
||||||
|
conditions += " and exists (select name from `tabWarehouse` wh \
|
||||||
|
where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)"%(lft, rgt)
|
||||||
|
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
@ -79,9 +81,9 @@ def get_stock_ledger_entries(filters):
|
|||||||
conditions = get_conditions(filters)
|
conditions = get_conditions(filters)
|
||||||
return frappe.db.sql("""select item_code, warehouse, posting_date, actual_qty, valuation_rate,
|
return frappe.db.sql("""select item_code, warehouse, posting_date, actual_qty, valuation_rate,
|
||||||
company, voucher_type, qty_after_transaction, stock_value_difference
|
company, voucher_type, qty_after_transaction, stock_value_difference
|
||||||
from `tabStock Ledger Entry` force index (posting_sort_index)
|
from `tabStock Ledger Entry` sle force index (posting_sort_index)
|
||||||
where docstatus < 2 %s order by posting_date, posting_time, name""" %
|
where docstatus < 2 %s order by posting_date, posting_time, name""" %
|
||||||
conditions, as_dict=1)
|
conditions, as_dict=1, debug=1)
|
||||||
|
|
||||||
def get_item_warehouse_map(filters):
|
def get_item_warehouse_map(filters):
|
||||||
iwb_map = {}
|
iwb_map = {}
|
||||||
|
@ -41,7 +41,7 @@ def get_stock_ledger_entries(filters):
|
|||||||
return frappe.db.sql("""select concat_ws(" ", posting_date, posting_time) as date,
|
return frappe.db.sql("""select concat_ws(" ", posting_date, posting_time) as date,
|
||||||
item_code, warehouse, actual_qty, qty_after_transaction, incoming_rate, valuation_rate,
|
item_code, warehouse, actual_qty, qty_after_transaction, incoming_rate, valuation_rate,
|
||||||
stock_value, voucher_type, voucher_no, batch_no, serial_no, company
|
stock_value, voucher_type, voucher_no, batch_no, serial_no, company
|
||||||
from `tabStock Ledger Entry`
|
from `tabStock Ledger Entry` sle
|
||||||
where company = %(company)s and
|
where company = %(company)s and
|
||||||
posting_date between %(from_date)s and %(to_date)s
|
posting_date between %(from_date)s and %(to_date)s
|
||||||
{sle_conditions}
|
{sle_conditions}
|
||||||
@ -73,7 +73,7 @@ def get_sle_conditions(filters):
|
|||||||
conditions.append("""item_code in (select name from tabItem
|
conditions.append("""item_code in (select name from tabItem
|
||||||
{item_conditions})""".format(item_conditions=item_conditions))
|
{item_conditions})""".format(item_conditions=item_conditions))
|
||||||
if filters.get("warehouse"):
|
if filters.get("warehouse"):
|
||||||
conditions.append("warehouse=%(warehouse)s")
|
conditions.append(get_warehouse_condition(filters.get("warehouse")))
|
||||||
if filters.get("voucher_no"):
|
if filters.get("voucher_no"):
|
||||||
conditions.append("voucher_no=%(voucher_no)s")
|
conditions.append("voucher_no=%(voucher_no)s")
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ def get_opening_balance(filters, columns):
|
|||||||
from erpnext.stock.stock_ledger import get_previous_sle
|
from erpnext.stock.stock_ledger import get_previous_sle
|
||||||
last_entry = get_previous_sle({
|
last_entry = get_previous_sle({
|
||||||
"item_code": filters.item_code,
|
"item_code": filters.item_code,
|
||||||
"warehouse": filters.warehouse,
|
"warehouse": get_warehouse_condition(filters.warehouse),
|
||||||
"posting_date": filters.from_date,
|
"posting_date": filters.from_date,
|
||||||
"posting_time": "00:00:00"
|
"posting_time": "00:00:00"
|
||||||
})
|
})
|
||||||
@ -96,4 +96,11 @@ def get_opening_balance(filters, columns):
|
|||||||
for i, v in ((9, 'qty_after_transaction'), (11, 'valuation_rate'), (12, 'stock_value')):
|
for i, v in ((9, 'qty_after_transaction'), (11, 'valuation_rate'), (12, 'stock_value')):
|
||||||
row[i] = last_entry.get(v, 0)
|
row[i] = last_entry.get(v, 0)
|
||||||
|
|
||||||
return row
|
return row
|
||||||
|
|
||||||
|
def get_warehouse_condition(warehouse):
|
||||||
|
lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"])
|
||||||
|
|
||||||
|
return " exists (select name from `tabWarehouse` wh \
|
||||||
|
where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)"%(lft, rgt)
|
||||||
|
|
@ -57,16 +57,20 @@ def get_data(filters):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
def get_bin_list(filters):
|
def get_bin_list(filters):
|
||||||
bin_filters = frappe._dict()
|
conditions = []
|
||||||
|
|
||||||
if filters.item_code:
|
if filters.item_code:
|
||||||
bin_filters.item_code = filters.item_code
|
conditions.append("item_code = '%s' "%filters.item_code)
|
||||||
|
|
||||||
if filters.warehouse:
|
if filters.warehouse:
|
||||||
bin_filters.warehouse = filters.warehouse
|
lft, rgt = frappe.db.get_value("Warehouse", filters.warehouse, ["lft", "rgt"])
|
||||||
|
|
||||||
|
conditions.append(" exists (select name from `tabWarehouse` wh \
|
||||||
|
where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)"%(lft, rgt))
|
||||||
|
|
||||||
bin_list = frappe.get_all("Bin", fields=["item_code", "warehouse",
|
bin_list = frappe.db.sql("""select item_code, warehouse, actual_qty, planned_qty, indented_qty,
|
||||||
"actual_qty", "planned_qty", "indented_qty", "ordered_qty", "reserved_qty",
|
ordered_qty, reserved_qty, reserved_qty_for_production, projected_qty
|
||||||
"reserved_qty_for_production", "projected_qty"],
|
from tabBin where %s order by item_code, warehouse """% " and ".join(conditions), as_dict=1,debug=1)
|
||||||
filters=bin_filters, order_by="item_code, warehouse")
|
|
||||||
|
|
||||||
return bin_list
|
return bin_list
|
||||||
|
|
||||||
|
@ -15,24 +15,34 @@ def get_stock_value_on(warehouse=None, posting_date=None, item_code=None):
|
|||||||
values, condition = [posting_date], ""
|
values, condition = [posting_date], ""
|
||||||
|
|
||||||
if warehouse:
|
if warehouse:
|
||||||
values.append(warehouse)
|
|
||||||
condition += " AND warehouse = %s"
|
lft, rgt, is_group = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt", "is_group"])
|
||||||
|
|
||||||
|
if is_group == "Yes":
|
||||||
|
values.extend([lft, rgt])
|
||||||
|
condition += "and exists (\
|
||||||
|
select name from `tabWarehouse` wh where wh.name = sle.warehouse\
|
||||||
|
and wh.lft >= %s and wh.rgt <= %s)"
|
||||||
|
|
||||||
|
else:
|
||||||
|
values.append(warehouse)
|
||||||
|
condition += " AND warehouse = %s"
|
||||||
|
|
||||||
if item_code:
|
if item_code:
|
||||||
values.append(item_code)
|
values.append(item_code)
|
||||||
condition.append(" AND item_code = %s")
|
condition.append(" AND item_code = %s")
|
||||||
|
|
||||||
stock_ledger_entries = frappe.db.sql("""
|
stock_ledger_entries = frappe.db.sql("""
|
||||||
SELECT item_code, stock_value
|
SELECT item_code, stock_value, name, warehouse
|
||||||
FROM `tabStock Ledger Entry`
|
FROM `tabStock Ledger Entry` sle
|
||||||
WHERE posting_date <= %s {0}
|
WHERE posting_date <= %s {0}
|
||||||
ORDER BY timestamp(posting_date, posting_time) DESC, name DESC
|
ORDER BY timestamp(posting_date, posting_time) DESC, name DESC
|
||||||
""".format(condition), values, as_dict=1)
|
""".format(condition), values, as_dict=1)
|
||||||
|
|
||||||
sle_map = {}
|
sle_map = {}
|
||||||
for sle in stock_ledger_entries:
|
for sle in stock_ledger_entries:
|
||||||
sle_map.setdefault(sle.item_code, flt(sle.stock_value))
|
sle_map[sle.item_code] = sle_map.get(sle.item_code, 0.0) + flt(sle.stock_value)
|
||||||
|
|
||||||
return sum(sle_map.values())
|
return sum(sle_map.values())
|
||||||
|
|
||||||
def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None, with_valuation_rate=False):
|
def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None, with_valuation_rate=False):
|
||||||
@ -177,3 +187,8 @@ def validate_warehouse_company(warehouse, company):
|
|||||||
if warehouse_company and warehouse_company != company:
|
if warehouse_company and warehouse_company != company:
|
||||||
frappe.throw(_("Warehouse {0} does not belong to company {1}").format(warehouse, company),
|
frappe.throw(_("Warehouse {0} does not belong to company {1}").format(warehouse, company),
|
||||||
InvalidWarehouseCompany)
|
InvalidWarehouseCompany)
|
||||||
|
|
||||||
|
def is_group_warehouse(warehouse):
|
||||||
|
if frappe.db.get_value("Warehouse", warehouse, "is_group") == "Yes":
|
||||||
|
frappe.throw(_("Group node warehouse is not allowed to select for transactions"))
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user