Compare commits
158 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27334c28a9 | ||
|
|
ea50c9d1be | ||
|
|
35da7d1fb4 | ||
|
|
ced14cc789 | ||
|
|
51a76885b8 | ||
|
|
a919be111a | ||
|
|
9c42161061 | ||
|
|
79d6266c7b | ||
|
|
f86100a734 | ||
|
|
3951f6971e | ||
|
|
75e65e7079 | ||
|
|
7f95d587b2 | ||
|
|
75b145fe2c | ||
|
|
8f42f60dc9 | ||
|
|
823b3ca540 | ||
|
|
5e75e3ba03 | ||
|
|
113df55e64 | ||
|
|
3e4b2743c6 | ||
|
|
338c28e78e | ||
|
|
7e14996995 | ||
|
|
6e30f04181 | ||
|
|
4a10f18ee3 | ||
|
|
f37d43d0c1 | ||
|
|
aea60f349f | ||
|
|
90bd5681d1 | ||
|
|
30e03cc4c8 | ||
|
|
4c40a416e6 | ||
|
|
3020c8086c | ||
|
|
8b3ef1e70a | ||
|
|
c446bf6117 | ||
|
|
660de515b5 | ||
|
|
e012e24423 | ||
|
|
e2d0d0a0c1 | ||
|
|
22e82dff20 | ||
|
|
b962fc1573 | ||
|
|
fa04236c8d | ||
|
|
36025468a1 | ||
|
|
0e376a464b | ||
|
|
8333b5754b | ||
|
|
dab1172a18 | ||
|
|
ea4497c8d2 | ||
|
|
b994b3dcda | ||
|
|
805a41d06c | ||
|
|
e06526ffff | ||
|
|
2df7db0346 | ||
|
|
c9877c5c1e | ||
|
|
372a881d8c | ||
|
|
71b5250cbd | ||
|
|
ece7881ab1 | ||
|
|
3ceebaec3f | ||
|
|
30e987a835 | ||
|
|
087da2e571 | ||
|
|
ad7eb9d03c | ||
|
|
35d0de8276 | ||
|
|
812853aa86 | ||
|
|
319c58266b | ||
|
|
dcf10ee4f6 | ||
|
|
1394a6557d | ||
|
|
00e825a8af | ||
|
|
ed89a83584 | ||
|
|
2c5b3e83f5 | ||
|
|
8e2531e2bb | ||
|
|
d5dd9f1706 | ||
|
|
394c4d718d | ||
|
|
ae20748dec | ||
|
|
3df2c9421a | ||
|
|
393becce0b | ||
|
|
777b16ffda | ||
|
|
efaf9f59db | ||
|
|
8f2e21def2 | ||
|
|
7231f29e78 | ||
|
|
239c9387d1 | ||
|
|
e74e4b18c7 | ||
|
|
012f5b0a50 | ||
|
|
05d62127d0 | ||
|
|
7549a83b9b | ||
|
|
c3153655eb | ||
|
|
96488b0f34 | ||
|
|
1a60931435 | ||
|
|
8f507a984e | ||
|
|
57d3cecd68 | ||
|
|
de609a2fb6 | ||
|
|
7312186c76 | ||
|
|
0a32b7a6eb | ||
|
|
c1a1e62c0d | ||
|
|
b12f2109b5 | ||
|
|
a13c6a1bef | ||
|
|
79ed58fd36 | ||
|
|
860144feb7 | ||
|
|
1efb05233c | ||
|
|
ef8d6dc8f8 | ||
|
|
79c2191aa3 | ||
|
|
f012a9db70 | ||
|
|
4e1a3c1d58 | ||
|
|
fb8e59234b | ||
|
|
31af0849db | ||
|
|
bfdb726072 | ||
|
|
a8406e1544 | ||
|
|
b2aa867b70 | ||
|
|
30f2bcbccc | ||
|
|
7d885432eb | ||
|
|
3b5f774144 | ||
|
|
3a200bbc44 | ||
|
|
2bedca04ae | ||
|
|
1a0536bff4 | ||
|
|
cdba021802 | ||
|
|
3fe5ecc611 | ||
|
|
296fbfeaac | ||
|
|
4a7b4efbec | ||
|
|
b1f0fd4ac3 | ||
|
|
f7d2a59c18 | ||
|
|
0ac8542eaa | ||
|
|
c8b6d3badb | ||
|
|
cdf4320b3b | ||
|
|
5b2d3222f3 | ||
|
|
5d202ca31a | ||
|
|
7088db9e1f | ||
|
|
ec344ffa96 | ||
|
|
a52e726b6b | ||
|
|
cf82c3828e | ||
|
|
6fcfbaa1f9 | ||
|
|
a6c733d06c | ||
|
|
46ef26df71 | ||
|
|
99d571a786 | ||
|
|
e3ae600277 | ||
|
|
dd7a723214 | ||
|
|
ccaf36a00f | ||
|
|
101a021f7b | ||
|
|
68ed0488a3 | ||
|
|
75a233b472 | ||
|
|
5a174d61bc | ||
|
|
7a2815299e | ||
|
|
195d2b577f | ||
|
|
8c85562ceb | ||
|
|
77aa4762b8 | ||
|
|
35ecab6a52 | ||
|
|
097da8cc89 | ||
|
|
1d52a4df22 | ||
|
|
cd61a20fb4 | ||
|
|
8f7eb358b8 | ||
|
|
0e285265b1 | ||
|
|
b866fcf14f | ||
|
|
3d190a15ab | ||
|
|
ab59e4769b | ||
|
|
7b5ca3e494 | ||
|
|
8f2c8f6e9d | ||
|
|
76c5924cbe | ||
|
|
6eb55042d8 | ||
|
|
9589527784 | ||
|
|
dba3f0048b | ||
|
|
3f6a5b2539 | ||
|
|
cf7f72e586 | ||
|
|
74d07c695b | ||
|
|
5cf3868d03 | ||
|
|
1b36336fc3 | ||
|
|
934e69fe0b | ||
|
|
19d9381197 | ||
|
|
7640858510 |
50
.travis.yml
@@ -1,6 +1,12 @@
|
|||||||
language: python
|
language: python
|
||||||
dist: trusty
|
dist: trusty
|
||||||
group: deprecated-2017Q2
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- google-chrome
|
||||||
|
packages:
|
||||||
|
- google-chrome-stable
|
||||||
|
|
||||||
python:
|
python:
|
||||||
- "2.7"
|
- "2.7"
|
||||||
@@ -8,43 +14,43 @@ python:
|
|||||||
services:
|
services:
|
||||||
- mysql
|
- mysql
|
||||||
|
|
||||||
before_install:
|
|
||||||
- "export DISPLAY=:99.0"
|
|
||||||
- "sh -e /etc/init.d/xvfb start"
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
- sudo rm /etc/apt/sources.list.d/docker.list
|
||||||
- sudo apt-get purge -y mysql-common mysql-server mysql-client
|
- sudo apt-get purge -y mysql-common mysql-server mysql-client
|
||||||
- nvm install v7.10.0
|
- nvm install v7.10.0
|
||||||
# - wget https://raw.githubusercontent.com/frappe/bench/master/install_scripts/setup_frappe.sh
|
|
||||||
# - sudo bash setup_frappe.sh --skip-setup-bench --mysql-root-password travis --bench-branch develop
|
|
||||||
- wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
|
- wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
|
||||||
- sudo python install.py --develop --user travis --without-bench-setup
|
- sudo python install.py --develop --user travis --without-bench-setup
|
||||||
- sudo pip install -e ~/bench
|
- sudo pip install -e ~/bench
|
||||||
|
|
||||||
# - sudo pip install --upgrade pip
|
|
||||||
- rm $TRAVIS_BUILD_DIR/.git/shallow
|
- rm $TRAVIS_BUILD_DIR/.git/shallow
|
||||||
- bash $TRAVIS_BUILD_DIR/travis/bench_init.sh
|
- bash $TRAVIS_BUILD_DIR/travis/bench_init.sh
|
||||||
- cp -r $TRAVIS_BUILD_DIR/test_sites/test_site ~/frappe-bench/sites/
|
- cp -r $TRAVIS_BUILD_DIR/test_sites/test_site ~/frappe-bench/sites/
|
||||||
|
|
||||||
script:
|
before_script:
|
||||||
|
- wget http://chromedriver.storage.googleapis.com/2.27/chromedriver_linux64.zip
|
||||||
|
- unzip chromedriver_linux64.zip
|
||||||
|
- sudo apt-get install libnss3
|
||||||
|
- sudo apt-get --only-upgrade install google-chrome-stable
|
||||||
|
- sudo cp chromedriver /usr/local/bin/.
|
||||||
|
- sudo chmod +x /usr/local/bin/chromedriver
|
||||||
|
- export DISPLAY=:99.0
|
||||||
|
- sh -e /etc/init.d/xvfb start
|
||||||
|
- sleep 3
|
||||||
|
- mysql -u root -ptravis -e 'create database test_frappe'
|
||||||
|
- echo "USE mysql;\nCREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe';\nFLUSH PRIVILEGES;\n" | mysql -u root -ptravis
|
||||||
|
- echo "USE mysql;\nGRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost';\n" | mysql -u root -ptravis
|
||||||
|
|
||||||
- cd ~/frappe-bench
|
- cd ~/frappe-bench
|
||||||
- bench get-app erpnext $TRAVIS_BUILD_DIR
|
- bench get-app erpnext $TRAVIS_BUILD_DIR
|
||||||
- bench use test_site
|
- bench use test_site
|
||||||
- bench reinstall --yes
|
- bench reinstall --yes
|
||||||
- bench build
|
- bench build
|
||||||
|
- bench scheduler disable
|
||||||
- bench start &
|
- bench start &
|
||||||
- sleep 10
|
- sleep 10
|
||||||
- bench --verbose run-tests --driver Firefox
|
|
||||||
|
|
||||||
before_script:
|
script:
|
||||||
- mysql -u root -ptravis -e 'create database test_frappe'
|
- set -e
|
||||||
- echo "USE mysql;\nCREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe';\nFLUSH PRIVILEGES;\n" | mysql -u root -ptravis
|
- bench --verbose run-tests
|
||||||
- echo "USE mysql;\nGRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost';\n" | mysql -u root -ptravis
|
- sleep 5
|
||||||
|
- bench --verbose run-ui-tests --app erpnext
|
||||||
notifications:
|
|
||||||
webhooks:
|
|
||||||
urls:
|
|
||||||
- https://webhooks.gitter.im/e/92b3bea86d8c5397beef
|
|
||||||
on_success: always
|
|
||||||
on_failure: always
|
|
||||||
on_start: never
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
import inspect
|
||||||
import frappe
|
import frappe
|
||||||
|
from erpnext.hooks import regional_overrides
|
||||||
|
|
||||||
__version__ = '8.3.2'
|
__version__ = '8.5.4'
|
||||||
|
|
||||||
def get_default_company(user=None):
|
def get_default_company(user=None):
|
||||||
'''Get default company for user'''
|
'''Get default company for user'''
|
||||||
@@ -65,3 +67,34 @@ def is_perpetual_inventory_enabled(company):
|
|||||||
company, "enable_perpetual_inventory") or 0
|
company, "enable_perpetual_inventory") or 0
|
||||||
|
|
||||||
return frappe.local.enable_perpetual_inventory[company]
|
return frappe.local.enable_perpetual_inventory[company]
|
||||||
|
|
||||||
|
def get_region(company=None):
|
||||||
|
'''Return the default country based on flag, company or global settings
|
||||||
|
|
||||||
|
You can also set global company flag in `frappe.flags.company`
|
||||||
|
'''
|
||||||
|
if company or frappe.flags.company:
|
||||||
|
return frappe.db.get_value('Company',
|
||||||
|
company or frappe.flags.company, 'country')
|
||||||
|
elif frappe.flags.country:
|
||||||
|
return frappe.flags.country
|
||||||
|
else:
|
||||||
|
return frappe.get_system_settings('country')
|
||||||
|
|
||||||
|
def allow_regional(fn):
|
||||||
|
'''Decorator to make a function regionally overridable
|
||||||
|
|
||||||
|
Example:
|
||||||
|
@erpnext.allow_regional
|
||||||
|
def myfunction():
|
||||||
|
pass'''
|
||||||
|
def caller(*args, **kwargs):
|
||||||
|
region = get_region()
|
||||||
|
fn_name = inspect.getmodule(fn).__name__ + '.' + fn.__name__
|
||||||
|
if region in regional_overrides and fn_name in regional_overrides[region]:
|
||||||
|
return frappe.get_attr(regional_overrides[region][fn_name])(*args, **kwargs)
|
||||||
|
else:
|
||||||
|
return fn(*args, **kwargs)
|
||||||
|
|
||||||
|
return caller
|
||||||
|
|
||||||
|
|||||||
@@ -1,94 +1,94 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on('Account', {
|
||||||
cur_frm.cscript.refresh = function (doc, cdt, cdn) {
|
setup: function(frm) {
|
||||||
if (doc.__islocal) {
|
frm.add_fetch('parent_account', 'report_type', 'report_type');
|
||||||
frappe.msgprint(__("Please create new account from Chart of Accounts."));
|
frm.add_fetch('parent_account', 'root_type', 'root_type');
|
||||||
throw "cannot create";
|
},
|
||||||
}
|
onload: function(frm) {
|
||||||
|
frm.set_query('parent_account', function(doc) {
|
||||||
cur_frm.toggle_display('account_name', doc.__islocal);
|
return {
|
||||||
|
filters: {
|
||||||
// hide fields if group
|
"is_group": 1,
|
||||||
cur_frm.toggle_display(['account_type', 'tax_rate'], cint(doc.is_group) == 0)
|
"company": doc.company
|
||||||
|
}
|
||||||
// disable fields
|
|
||||||
cur_frm.toggle_enable(['account_name', 'is_group', 'company'], false);
|
|
||||||
|
|
||||||
if (cint(doc.is_group) == 0) {
|
|
||||||
cur_frm.toggle_display('freeze_account', doc.__onload && doc.__onload.can_freeze_account);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read-only for root accounts
|
|
||||||
if (!doc.parent_account) {
|
|
||||||
cur_frm.set_read_only();
|
|
||||||
cur_frm.set_intro(__("This is a root account and cannot be edited."));
|
|
||||||
} else {
|
|
||||||
// credit days and type if customer or supplier
|
|
||||||
cur_frm.set_intro(null);
|
|
||||||
|
|
||||||
cur_frm.cscript.account_type(doc, cdt, cdn);
|
|
||||||
|
|
||||||
// show / hide convert buttons
|
|
||||||
cur_frm.cscript.add_toolbar_buttons(doc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.add_fetch('parent_account', 'report_type', 'report_type');
|
|
||||||
cur_frm.add_fetch('parent_account', 'root_type', 'root_type');
|
|
||||||
|
|
||||||
cur_frm.cscript.account_type = function (doc, cdt, cdn) {
|
|
||||||
if (doc.is_group == 0) {
|
|
||||||
cur_frm.toggle_display(['tax_rate'], doc.account_type == 'Tax');
|
|
||||||
cur_frm.toggle_display('warehouse', doc.account_type == 'Stock');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.cscript.add_toolbar_buttons = function (doc) {
|
|
||||||
cur_frm.add_custom_button(__('Chart of Accounts'),
|
|
||||||
function () { frappe.set_route("Tree", "Account"); });
|
|
||||||
|
|
||||||
if (doc.is_group == 1) {
|
|
||||||
cur_frm.add_custom_button(__('Group to Non-Group'),
|
|
||||||
function () { cur_frm.cscript.convert_to_ledger(); }, 'fa fa-retweet', 'btn-default');
|
|
||||||
} else if (cint(doc.is_group) == 0) {
|
|
||||||
cur_frm.add_custom_button(__('Ledger'), function () {
|
|
||||||
frappe.route_options = {
|
|
||||||
"account": doc.name,
|
|
||||||
"from_date": frappe.sys_defaults.year_start_date,
|
|
||||||
"to_date": frappe.sys_defaults.year_end_date,
|
|
||||||
"company": doc.company
|
|
||||||
};
|
};
|
||||||
frappe.set_route("query-report", "General Ledger");
|
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
refresh: function(frm) {
|
||||||
|
if (frm.doc.__islocal) {
|
||||||
|
frappe.msgprint(__("Please create new account from Chart of Accounts."));
|
||||||
|
throw "cannot create";
|
||||||
|
}
|
||||||
|
|
||||||
|
frm.toggle_display('account_name', frm.doc.__islocal);
|
||||||
|
|
||||||
|
// hide fields if group
|
||||||
|
frm.toggle_display(['account_type', 'tax_rate'], cint(frm.doc.is_group) == 0);
|
||||||
|
|
||||||
|
// disable fields
|
||||||
|
frm.toggle_enable(['account_name', 'is_group', 'company'], false);
|
||||||
|
|
||||||
|
if (cint(frm.doc.is_group) == 0) {
|
||||||
|
frm.toggle_display('freeze_account', frm.doc.__onload
|
||||||
|
&& frm.doc.__onload.can_freeze_account);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read-only for root accounts
|
||||||
|
if (!frm.doc.parent_account) {
|
||||||
|
frm.set_read_only();
|
||||||
|
frm.set_intro(__("This is a root account and cannot be edited."));
|
||||||
|
} else {
|
||||||
|
// credit days and type if customer or supplier
|
||||||
|
frm.set_intro(null);
|
||||||
|
frm.trigger('account_type');
|
||||||
|
|
||||||
|
// show / hide convert buttons
|
||||||
|
frm.trigger('add_toolbar_buttons');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
account_type: function (frm) {
|
||||||
|
if (frm.doc.is_group == 0) {
|
||||||
|
frm.toggle_display(['tax_rate'], frm.doc.account_type == 'Tax');
|
||||||
|
frm.toggle_display('warehouse', frm.doc.account_type == 'Stock');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
add_toolbar_buttons: function(frm) {
|
||||||
|
frm.add_custom_button(__('Chart of Accounts'),
|
||||||
|
function () { frappe.set_route("Tree", "Account"); });
|
||||||
|
|
||||||
|
if (frm.doc.is_group == 1) {
|
||||||
|
frm.add_custom_button(__('Group to Non-Group'), function () {
|
||||||
|
return frappe.call({
|
||||||
|
doc: frm.doc,
|
||||||
|
method: 'convert_group_to_ledger',
|
||||||
|
callback: function() {
|
||||||
|
frm.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (cint(frm.doc.is_group) == 0) {
|
||||||
|
cur_frm.add_custom_button(__('Ledger'), function () {
|
||||||
|
frappe.route_options = {
|
||||||
|
"account": frm.doc.name,
|
||||||
|
"from_date": frappe.sys_defaults.year_start_date,
|
||||||
|
"to_date": frappe.sys_defaults.year_end_date,
|
||||||
|
"company": frm.doc.company
|
||||||
|
};
|
||||||
|
frappe.set_route("query-report", "General Ledger");
|
||||||
|
});
|
||||||
|
|
||||||
|
frm.add_custom_button(__('Non-Group to Group'), function () {
|
||||||
|
return frappe.call({
|
||||||
|
doc: frm.doc,
|
||||||
|
method: 'convert_ledger_to_group',
|
||||||
|
callback: function() {
|
||||||
|
frm.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
cur_frm.add_custom_button(__('Non-Group to Group'),
|
|
||||||
function () { cur_frm.cscript.convert_to_group(); }, 'fa fa-retweet', 'btn-default')
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
cur_frm.cscript.convert_to_ledger = function (doc, cdt, cdn) {
|
|
||||||
return $c_obj(cur_frm.doc, 'convert_group_to_ledger', '', function (r, rt) {
|
|
||||||
if (r.message == 1) {
|
|
||||||
cur_frm.refresh();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.cscript.convert_to_group = function (doc, cdt, cdn) {
|
|
||||||
return $c_obj(cur_frm.doc, 'convert_ledger_to_group', '', function (r, rt) {
|
|
||||||
if (r.message == 1) {
|
|
||||||
cur_frm.refresh();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.fields_dict['parent_account'].get_query = function (doc) {
|
|
||||||
return {
|
|
||||||
filters: {
|
|
||||||
"is_group": 1,
|
|
||||||
"company": doc.company
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -83,7 +83,7 @@ def validate_expense_against_budget(args):
|
|||||||
|
|
||||||
budget_records = frappe.db.sql("""
|
budget_records = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
b.{budget_against_field}, ba.budget_amount, b.monthly_distribution,
|
b.{budget_against_field} as budget_against, ba.budget_amount, b.monthly_distribution,
|
||||||
b.action_if_annual_budget_exceeded,
|
b.action_if_annual_budget_exceeded,
|
||||||
b.action_if_accumulated_monthly_budget_exceeded
|
b.action_if_accumulated_monthly_budget_exceeded
|
||||||
from
|
from
|
||||||
@@ -111,15 +111,15 @@ def validate_budget_records(args, budget_records):
|
|||||||
args["month_end_date"] = get_last_day(args.posting_date)
|
args["month_end_date"] = get_last_day(args.posting_date)
|
||||||
|
|
||||||
compare_expense_with_budget(args, budget_amount,
|
compare_expense_with_budget(args, budget_amount,
|
||||||
_("Accumulated Monthly"), monthly_action)
|
_("Accumulated Monthly"), monthly_action, budget.budget_against)
|
||||||
|
|
||||||
if yearly_action in ("Stop", "Warn") and monthly_action != "Stop" \
|
if yearly_action in ("Stop", "Warn") and monthly_action != "Stop" \
|
||||||
and yearly_action != monthly_action:
|
and yearly_action != monthly_action:
|
||||||
compare_expense_with_budget(args, flt(budget.budget_amount),
|
compare_expense_with_budget(args, flt(budget.budget_amount),
|
||||||
_("Annual"), yearly_action)
|
_("Annual"), yearly_action, budget.budget_against)
|
||||||
|
|
||||||
|
|
||||||
def compare_expense_with_budget(args, budget_amount, action_for, action):
|
def compare_expense_with_budget(args, budget_amount, action_for, action, budget_against):
|
||||||
actual_expense = get_actual_expense(args)
|
actual_expense = get_actual_expense(args)
|
||||||
if actual_expense > budget_amount:
|
if actual_expense > budget_amount:
|
||||||
diff = actual_expense - budget_amount
|
diff = actual_expense - budget_amount
|
||||||
@@ -127,7 +127,7 @@ def compare_expense_with_budget(args, budget_amount, action_for, action):
|
|||||||
|
|
||||||
msg = _("{0} Budget for Account {1} against {2} {3} is {4}. It will exceed by {5}").format(
|
msg = _("{0} Budget for Account {1} against {2} {3} is {4}. It will exceed by {5}").format(
|
||||||
_(action_for), frappe.bold(args.account), args.budget_against_field,
|
_(action_for), frappe.bold(args.account), args.budget_against_field,
|
||||||
frappe.bold(args.budget_against),
|
frappe.bold(budget_against),
|
||||||
frappe.bold(fmt_money(budget_amount, currency=currency)),
|
frappe.bold(fmt_money(budget_amount, currency=currency)),
|
||||||
frappe.bold(fmt_money(diff, currency=currency)))
|
frappe.bold(fmt_money(diff, currency=currency)))
|
||||||
|
|
||||||
|
|||||||
@@ -140,6 +140,33 @@ class TestBudget(unittest.TestCase):
|
|||||||
budget.load_from_db()
|
budget.load_from_db()
|
||||||
budget.cancel()
|
budget.cancel()
|
||||||
|
|
||||||
|
def test_monthly_budget_against_parent_group_cost_center(self):
|
||||||
|
cost_center = "_Test Cost Center 3 - _TC"
|
||||||
|
|
||||||
|
if not frappe.db.exists("Cost Center", cost_center):
|
||||||
|
frappe.get_doc({
|
||||||
|
'doctype': 'Cost Center',
|
||||||
|
'cost_center_name': '_Test Cost Center 3',
|
||||||
|
'parent_cost_center': "_Test Company - _TC",
|
||||||
|
'company': '_Test Company',
|
||||||
|
'is_group': 0
|
||||||
|
}).insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
budget = make_budget("Cost Center", cost_center)
|
||||||
|
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||||
|
|
||||||
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
|
"_Test Bank - _TC", 40000, cost_center)
|
||||||
|
|
||||||
|
self.assertRaises(BudgetError, jv.submit)
|
||||||
|
|
||||||
|
budget.load_from_db()
|
||||||
|
budget.cancel()
|
||||||
|
jv.cancel()
|
||||||
|
|
||||||
|
frappe.delete_doc('Journal Entry', jv.name)
|
||||||
|
frappe.delete_doc('Cost Center', cost_center)
|
||||||
|
|
||||||
def set_total_expense_zero(posting_date, budget_against_field=None, budget_against_CC=None):
|
def set_total_expense_zero(posting_date, budget_against_field=None, budget_against_CC=None):
|
||||||
if budget_against_field == "Project":
|
if budget_against_field == "Project":
|
||||||
budget_against = "_Test Project"
|
budget_against = "_Test Project"
|
||||||
@@ -167,7 +194,8 @@ def make_budget(budget_against=None, cost_center=None):
|
|||||||
if budget_against == "Project":
|
if budget_against == "Project":
|
||||||
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", "_Test Project/_Test Fiscal Year 2013%")})
|
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", "_Test Project/_Test Fiscal Year 2013%")})
|
||||||
else:
|
else:
|
||||||
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", "_Test Cost Center - _TC/_Test Fiscal Year 2013%")})
|
cost_center_name = "{0}%".format(cost_center or "_Test Cost Center - _TC/_Test Fiscal Year 2013")
|
||||||
|
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", cost_center_name)})
|
||||||
for d in budget_list:
|
for d in budget_list:
|
||||||
frappe.db.sql("delete from `tabBudget` where name = %(name)s", d)
|
frappe.db.sql("delete from `tabBudget` where name = %(name)s", d)
|
||||||
frappe.db.sql("delete from `tabBudget Account` where parent = %(name)s", d)
|
frappe.db.sql("delete from `tabBudget Account` where parent = %(name)s", d)
|
||||||
|
|||||||
@@ -96,7 +96,14 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
|||||||
|
|
||||||
// expense claim
|
// expense claim
|
||||||
if(jvd.reference_type==="Expense Claim") {
|
if(jvd.reference_type==="Expense Claim") {
|
||||||
return {};
|
return {
|
||||||
|
filters: {
|
||||||
|
'approval_status': 'Approved',
|
||||||
|
'total_sanctioned_amount': ['>', 0],
|
||||||
|
'status': ['!=', 'Paid'],
|
||||||
|
'docstatus': 1
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// journal entry
|
// journal entry
|
||||||
|
|||||||
@@ -291,37 +291,39 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
|
|
||||||
set_account_currency_and_balance: function(frm, account, currency_field,
|
set_account_currency_and_balance: function(frm, account, currency_field,
|
||||||
balance_field, callback_function) {
|
balance_field, callback_function) {
|
||||||
frappe.call({
|
if (frm.doc.posting_date && account) {
|
||||||
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_details",
|
frappe.call({
|
||||||
args: {
|
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_details",
|
||||||
"account": account,
|
args: {
|
||||||
"date": frm.doc.posting_date
|
"account": account,
|
||||||
},
|
"date": frm.doc.posting_date
|
||||||
callback: function(r, rt) {
|
},
|
||||||
if(r.message) {
|
callback: function(r, rt) {
|
||||||
frm.set_value(currency_field, r.message['account_currency']);
|
if(r.message) {
|
||||||
frm.set_value(balance_field, r.message['account_balance']);
|
frm.set_value(currency_field, r.message['account_currency']);
|
||||||
|
frm.set_value(balance_field, r.message['account_balance']);
|
||||||
|
|
||||||
if(frm.doc.payment_type=="Receive" && currency_field=="paid_to_account_currency") {
|
if(frm.doc.payment_type=="Receive" && currency_field=="paid_to_account_currency") {
|
||||||
frm.toggle_reqd(["reference_no", "reference_date"],
|
frm.toggle_reqd(["reference_no", "reference_date"],
|
||||||
(r.message['account_type'] == "Bank" ? 1 : 0));
|
(r.message['account_type'] == "Bank" ? 1 : 0));
|
||||||
if(!frm.doc.received_amount && frm.doc.paid_amount)
|
if(!frm.doc.received_amount && frm.doc.paid_amount)
|
||||||
frm.events.paid_amount(frm);
|
frm.events.paid_amount(frm);
|
||||||
} else if(frm.doc.payment_type=="Pay" && currency_field=="paid_from_account_currency") {
|
} else if(frm.doc.payment_type=="Pay" && currency_field=="paid_from_account_currency") {
|
||||||
frm.toggle_reqd(["reference_no", "reference_date"],
|
frm.toggle_reqd(["reference_no", "reference_date"],
|
||||||
(r.message['account_type'] == "Bank" ? 1 : 0));
|
(r.message['account_type'] == "Bank" ? 1 : 0));
|
||||||
|
|
||||||
if(!frm.doc.paid_amount && frm.doc.received_amount)
|
if(!frm.doc.paid_amount && frm.doc.received_amount)
|
||||||
frm.events.received_amount(frm);
|
frm.events.received_amount(frm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(callback_function) callback_function(frm);
|
||||||
|
|
||||||
|
frm.events.hide_unhide_fields(frm);
|
||||||
|
frm.events.set_dynamic_labels(frm);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(callback_function) callback_function(frm);
|
|
||||||
|
|
||||||
frm.events.hide_unhide_fields(frm);
|
|
||||||
frm.events.set_dynamic_labels(frm);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
paid_from_account_currency: function(frm) {
|
paid_from_account_currency: function(frm) {
|
||||||
|
|||||||
@@ -492,9 +492,13 @@ def get_outstanding_reference_documents(args):
|
|||||||
|
|
||||||
for d in outstanding_invoices:
|
for d in outstanding_invoices:
|
||||||
d["exchange_rate"] = 1
|
d["exchange_rate"] = 1
|
||||||
if party_account_currency != company_currency \
|
if party_account_currency != company_currency:
|
||||||
and d.voucher_type in ("Sales Invoice", "Purchase Invoice"):
|
if d.voucher_type in ("Sales Invoice", "Purchase Invoice"):
|
||||||
d["exchange_rate"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "conversion_rate")
|
d["exchange_rate"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "conversion_rate")
|
||||||
|
elif d.voucher_type == "Journal Entry":
|
||||||
|
d["exchange_rate"] = get_exchange_rate(
|
||||||
|
party_account_currency, company_currency, d.posting_date
|
||||||
|
)
|
||||||
|
|
||||||
# Get all SO / PO which are not fully billed or aginst which full advance not paid
|
# Get all SO / PO which are not fully billed or aginst which full advance not paid
|
||||||
orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"), args.get("party"),
|
orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"), args.get("party"),
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ def get_pricing_rule_for_item(args):
|
|||||||
"discount_percentage": 0.0
|
"discount_percentage": 0.0
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
item_details.discount_percentage = pricing_rule.discount_percentage
|
item_details.discount_percentage = pricing_rule.discount_percentage or args.discount_percentage
|
||||||
elif args.get('pricing_rule'):
|
elif args.get('pricing_rule'):
|
||||||
item_details = remove_pricing_rule_for_item(args.get("pricing_rule"), item_details)
|
item_details = remove_pricing_rule_for_item(args.get("pricing_rule"), item_details)
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
|
|||||||
import unittest
|
import unittest
|
||||||
import frappe
|
import frappe
|
||||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||||
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
from erpnext.stock.get_item_details import get_item_details
|
from erpnext.stock.get_item_details import get_item_details
|
||||||
from frappe import MandatoryError
|
from frappe import MandatoryError
|
||||||
|
|
||||||
@@ -249,3 +250,50 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
so = frappe.get_doc('Sales Order', so.name)
|
so = frappe.get_doc('Sales Order', so.name)
|
||||||
self.assertEquals(so.items[0].discount_percentage, 0)
|
self.assertEquals(so.items[0].discount_percentage, 0)
|
||||||
self.assertEquals(so.items[0].rate, 100)
|
self.assertEquals(so.items[0].rate, 100)
|
||||||
|
|
||||||
|
def test_pricing_rule_with_margin_and_discount(self):
|
||||||
|
make_pricing_rule(selling=1, margin_type="Percentage", margin_rate_or_amount=10)
|
||||||
|
si = create_sales_invoice(do_not_save=True)
|
||||||
|
si.items[0].price_list_rate = 1000
|
||||||
|
si.insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
item = si.items[0]
|
||||||
|
self.assertEquals(item.rate, 1100)
|
||||||
|
self.assertEquals(item.margin_rate_or_amount, 10)
|
||||||
|
|
||||||
|
# With discount
|
||||||
|
item.discount_percentage = 10
|
||||||
|
si.save()
|
||||||
|
item = si.items[0]
|
||||||
|
self.assertEquals(item.rate, 990)
|
||||||
|
self.assertEquals(item.discount_percentage, 10)
|
||||||
|
frappe.db.sql("delete from `tabPricing Rule`")
|
||||||
|
|
||||||
|
def make_pricing_rule(**args):
|
||||||
|
args = frappe._dict(args)
|
||||||
|
|
||||||
|
doc = frappe.get_doc({
|
||||||
|
"doctype": "Pricing Rule",
|
||||||
|
"title": args.title or "_Test Pricing Rule",
|
||||||
|
"company": args.company or "_Test Company",
|
||||||
|
"apply_on": args.apply_on or "Item Code",
|
||||||
|
"item_code": args.item_code or "_Test Item",
|
||||||
|
"applicable_for": args.applicable_for,
|
||||||
|
"selling": args.selling or 0,
|
||||||
|
"buying": args.buying or 0,
|
||||||
|
"min_qty": args.min_qty or 0.0,
|
||||||
|
"max_qty": args.max_qty or 0.0,
|
||||||
|
"price_or_discount": args.price_or_discount or "Discount Percentage",
|
||||||
|
"discount_percentage": args.discount_percentage or 0.0,
|
||||||
|
"price": args.price or 0.0,
|
||||||
|
"margin_type": args.margin_type,
|
||||||
|
"margin_rate_or_amount": args.margin_rate_or_amount or 0.0
|
||||||
|
}).insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
apply_on = doc.apply_on.replace(' ', '_').lower()
|
||||||
|
if args.get(apply_on) and apply_on != "item_code":
|
||||||
|
doc.db_set(apply_on, args.get(apply_on))
|
||||||
|
|
||||||
|
applicable_for = doc.applicable_for.replace(' ', '_').lower()
|
||||||
|
if args.get(applicable_for):
|
||||||
|
doc.db_set(applicable_for, args.get(applicable_for))
|
||||||
@@ -1516,6 +1516,36 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 1,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "sec_tax_breakup",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Tax Breakup",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@@ -1523,7 +1553,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "other_charges_calculation",
|
"fieldname": "other_charges_calculation",
|
||||||
"fieldtype": "HTML",
|
"fieldtype": "Text",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
@@ -1533,12 +1563,12 @@
|
|||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Taxes and Charges Calculation",
|
"label": "Taxes and Charges Calculation",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"oldfieldtype": "HTML",
|
"oldfieldtype": "HTML",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 1,
|
||||||
"remember_last_selected_value": 0,
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
@@ -3767,7 +3797,7 @@
|
|||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
"modified": "2017-06-29 10:48:09.707735",
|
"modified": "2017-07-19 13:53:48.673757",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice",
|
"name": "Purchase Invoice",
|
||||||
|
|||||||
@@ -98,6 +98,26 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
this.set_default_print_format();
|
this.set_default_print_format();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
on_submit: function(doc, dt, dn) {
|
||||||
|
var me = this;
|
||||||
|
|
||||||
|
$.each(doc["items"], function(i, row) {
|
||||||
|
if(row.delivery_note) frappe.model.clear_doc("Delivery Note", row.delivery_note)
|
||||||
|
})
|
||||||
|
|
||||||
|
if(this.frm.doc.is_pos) {
|
||||||
|
this.frm.msgbox = frappe.msgprint(
|
||||||
|
`<a class="btn btn-primary" onclick="cur_frm.print_preview.printit(true)" style="margin-right: 5px;">
|
||||||
|
${__('Print')}</a>
|
||||||
|
<a class="btn btn-default" href="javascript:frappe.new_doc(cur_frm.doctype);">
|
||||||
|
${__('New')}</a>`
|
||||||
|
);
|
||||||
|
|
||||||
|
} else if(cint(frappe.boot.notification_settings.sales_invoice)) {
|
||||||
|
this.frm.email_doc(frappe.boot.notification_settings.sales_invoice_message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
set_default_print_format: function() {
|
set_default_print_format: function() {
|
||||||
// set default print format to POS type
|
// set default print format to POS type
|
||||||
if(cur_frm.doc.is_pos) {
|
if(cur_frm.doc.is_pos) {
|
||||||
@@ -343,13 +363,6 @@ cur_frm.cscript.hide_fields = function(doc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var item_fields_stock = ['batch_no', 'actual_batch_qty', 'actual_qty', 'expense_account',
|
|
||||||
'warehouse', 'expense_account', 'quality_inspection']
|
|
||||||
cur_frm.fields_dict['items'].grid.set_column_disp(item_fields_stock,
|
|
||||||
(cint(doc.update_stock)==1 || cint(doc.is_return)==1 ? true : false));
|
|
||||||
|
|
||||||
|
|
||||||
// India related fields
|
// India related fields
|
||||||
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
|
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
|
||||||
else hide_field(['c_form_applicable', 'c_form_no']);
|
else hide_field(['c_form_applicable', 'c_form_no']);
|
||||||
@@ -445,24 +458,6 @@ cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
|
|||||||
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center");
|
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center");
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
|
||||||
$.each(doc["items"], function(i, row) {
|
|
||||||
if(row.delivery_note) frappe.model.clear_doc("Delivery Note", row.delivery_note)
|
|
||||||
})
|
|
||||||
|
|
||||||
if(cur_frm.doc.is_pos) {
|
|
||||||
cur_frm.msgbox = frappe.msgprint(
|
|
||||||
`<a class="btn btn-primary" onclick="cur_frm.print_preview.printit(true)" style="margin-right: 5px;">
|
|
||||||
${__('Print')}</a>
|
|
||||||
<a class="btn btn-default" href="javascript:frappe.new_doc(cur_frm.doctype);">
|
|
||||||
${__('New')}</a>`
|
|
||||||
);
|
|
||||||
|
|
||||||
} else if(cint(frappe.boot.notification_settings.sales_invoice)) {
|
|
||||||
cur_frm.email_doc(frappe.boot.notification_settings.sales_invoice_message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.set_query("debit_to", function(doc) {
|
cur_frm.set_query("debit_to", function(doc) {
|
||||||
// filter on Account
|
// filter on Account
|
||||||
if (doc.customer) {
|
if (doc.customer) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timeshe
|
|||||||
from erpnext.accounts.doctype.asset.depreciation \
|
from erpnext.accounts.doctype.asset.depreciation \
|
||||||
import get_disposal_account_and_cost_center, get_gl_entries_on_asset_disposal
|
import get_disposal_account_and_cost_center, get_gl_entries_on_asset_disposal
|
||||||
from erpnext.stock.doctype.batch.batch import set_batch_nos
|
from erpnext.stock.doctype.batch.batch import set_batch_nos
|
||||||
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, get_delivery_note_serial_no
|
||||||
|
|
||||||
form_grid_templates = {
|
form_grid_templates = {
|
||||||
"items": "templates/form_grid/item_grid.html"
|
"items": "templates/form_grid/item_grid.html"
|
||||||
@@ -139,6 +140,8 @@ class SalesInvoice(SellingController):
|
|||||||
|
|
||||||
self.update_time_sheet(self.name)
|
self.update_time_sheet(self.name)
|
||||||
|
|
||||||
|
frappe.enqueue('erpnext.setup.doctype.company.company.update_company_current_month_sales', company=self.company)
|
||||||
|
|
||||||
def validate_pos_paid_amount(self):
|
def validate_pos_paid_amount(self):
|
||||||
if len(self.payments) == 0 and self.is_pos:
|
if len(self.payments) == 0 and self.is_pos:
|
||||||
frappe.throw(_("At least one mode of payment is required for POS invoice."))
|
frappe.throw(_("At least one mode of payment is required for POS invoice."))
|
||||||
@@ -803,17 +806,25 @@ class SalesInvoice(SellingController):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
for serial_no in item.serial_no.split("\n"):
|
for serial_no in item.serial_no.split("\n"):
|
||||||
sno = frappe.get_doc('Serial No', serial_no)
|
if serial_no and frappe.db.exists('Serial No', serial_no):
|
||||||
sno.sales_invoice = invoice
|
sno = frappe.get_doc('Serial No', serial_no)
|
||||||
sno.db_update()
|
sno.sales_invoice = invoice
|
||||||
|
sno.db_update()
|
||||||
|
|
||||||
def validate_serial_numbers(self):
|
def validate_serial_numbers(self):
|
||||||
"""
|
"""
|
||||||
validate serial number agains Delivery Note and Sales Invoice
|
validate serial number agains Delivery Note and Sales Invoice
|
||||||
"""
|
"""
|
||||||
|
self.set_serial_no_against_delivery_note()
|
||||||
self.validate_serial_against_delivery_note()
|
self.validate_serial_against_delivery_note()
|
||||||
self.validate_serial_against_sales_invoice()
|
self.validate_serial_against_sales_invoice()
|
||||||
|
|
||||||
|
def set_serial_no_against_delivery_note(self):
|
||||||
|
for item in self.items:
|
||||||
|
if item.serial_no and item.delivery_note and \
|
||||||
|
item.qty != len(get_serial_nos(item.serial_no)):
|
||||||
|
item.serial_no = get_delivery_note_serial_no(item.item_code, item.qty, item.delivery_note)
|
||||||
|
|
||||||
def validate_serial_against_delivery_note(self):
|
def validate_serial_against_delivery_note(self):
|
||||||
"""
|
"""
|
||||||
validate if the serial numbers in Sales Invoice Items are same as in
|
validate if the serial numbers in Sales Invoice Items are same as in
|
||||||
@@ -825,14 +836,18 @@ class SalesInvoice(SellingController):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
serial_nos = frappe.db.get_value("Delivery Note Item", item.dn_detail, "serial_no") or ""
|
serial_nos = frappe.db.get_value("Delivery Note Item", item.dn_detail, "serial_no") or ""
|
||||||
dn_serial_nos = set(serial_nos.split("\n"))
|
dn_serial_nos = set(get_serial_nos(serial_nos))
|
||||||
|
|
||||||
serial_nos = item.serial_no or ""
|
serial_nos = item.serial_no or ""
|
||||||
si_serial_nos = set(serial_nos.split("\n"))
|
si_serial_nos = set(get_serial_nos(serial_nos))
|
||||||
|
|
||||||
if si_serial_nos - dn_serial_nos:
|
if si_serial_nos - dn_serial_nos:
|
||||||
frappe.throw(_("Serial Numbers in row {0} does not match with Delivery Note".format(item.idx)))
|
frappe.throw(_("Serial Numbers in row {0} does not match with Delivery Note".format(item.idx)))
|
||||||
|
|
||||||
|
if item.serial_no and cint(item.qty) != len(si_serial_nos):
|
||||||
|
frappe.throw(_("Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.".format(
|
||||||
|
item.idx, item.qty, item.item_code, len(si_serial_nos))))
|
||||||
|
|
||||||
def validate_serial_against_sales_invoice(self):
|
def validate_serial_against_sales_invoice(self):
|
||||||
""" check if serial number is already used in other sales invoice """
|
""" check if serial number is already used in other sales invoice """
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
@@ -917,7 +932,6 @@ def make_delivery_note(source_name, target_doc=None):
|
|||||||
|
|
||||||
return doclist
|
return doclist
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_sales_return(source_name, target_doc=None):
|
def make_sales_return(source_name, target_doc=None):
|
||||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ def get_data():
|
|||||||
'Sales Invoice': 'return_against'
|
'Sales Invoice': 'return_against'
|
||||||
},
|
},
|
||||||
'internal_links': {
|
'internal_links': {
|
||||||
'Sales Order': ['items', 'sales_order'],
|
'Sales Order': ['items', 'sales_order']
|
||||||
'Delivery Note': ['items', 'delivery_note']
|
|
||||||
},
|
},
|
||||||
'transactions': [
|
'transactions': [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
|
|||||||
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
|
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
|
||||||
from frappe.model.naming import make_autoname
|
from frappe.model.naming import make_autoname
|
||||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
|
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
|
||||||
|
|
||||||
class TestSalesInvoice(unittest.TestCase):
|
class TestSalesInvoice(unittest.TestCase):
|
||||||
def make(self):
|
def make(self):
|
||||||
@@ -1105,8 +1106,83 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
for i, k in enumerate(expected_values["keys"]):
|
for i, k in enumerate(expected_values["keys"]):
|
||||||
self.assertEquals(d.get(k), expected_values[d.item_code][i])
|
self.assertEquals(d.get(k), expected_values[d.item_code][i])
|
||||||
|
|
||||||
def test_item_wise_tax_breakup(self):
|
def test_item_wise_tax_breakup_india(self):
|
||||||
|
frappe.flags.country = "India"
|
||||||
|
|
||||||
|
si = self.create_si_to_test_tax_breakup()
|
||||||
|
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si)
|
||||||
|
|
||||||
|
expected_itemised_tax = {
|
||||||
|
"999800": {
|
||||||
|
"Service Tax": {
|
||||||
|
"tax_rate": 10.0,
|
||||||
|
"tax_amount": 1500.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expected_itemised_taxable_amount = {
|
||||||
|
"999800": 15000.0
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertEqual(itemised_tax, expected_itemised_tax)
|
||||||
|
self.assertEqual(itemised_taxable_amount, expected_itemised_taxable_amount)
|
||||||
|
|
||||||
|
frappe.flags.country = None
|
||||||
|
|
||||||
|
def test_item_wise_tax_breakup_outside_india(self):
|
||||||
|
frappe.flags.country = "United States"
|
||||||
|
|
||||||
|
si = self.create_si_to_test_tax_breakup()
|
||||||
|
|
||||||
|
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si)
|
||||||
|
|
||||||
|
expected_itemised_tax = {
|
||||||
|
"_Test Item": {
|
||||||
|
"Service Tax": {
|
||||||
|
"tax_rate": 10.0,
|
||||||
|
"tax_amount": 1000.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"_Test Item 2": {
|
||||||
|
"Service Tax": {
|
||||||
|
"tax_rate": 10.0,
|
||||||
|
"tax_amount": 500.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expected_itemised_taxable_amount = {
|
||||||
|
"_Test Item": 10000.0,
|
||||||
|
"_Test Item 2": 5000.0
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertEqual(itemised_tax, expected_itemised_tax)
|
||||||
|
self.assertEqual(itemised_taxable_amount, expected_itemised_taxable_amount)
|
||||||
|
|
||||||
|
frappe.flags.country = None
|
||||||
|
|
||||||
|
def create_si_to_test_tax_breakup(self):
|
||||||
si = create_sales_invoice(qty=100, rate=50, do_not_save=True)
|
si = create_sales_invoice(qty=100, rate=50, do_not_save=True)
|
||||||
|
si.append("items", {
|
||||||
|
"item_code": "_Test Item",
|
||||||
|
"gst_hsn_code": "999800",
|
||||||
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
|
"qty": 100,
|
||||||
|
"rate": 50,
|
||||||
|
"income_account": "Sales - _TC",
|
||||||
|
"expense_account": "Cost of Goods Sold - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC"
|
||||||
|
})
|
||||||
|
si.append("items", {
|
||||||
|
"item_code": "_Test Item 2",
|
||||||
|
"gst_hsn_code": "999800",
|
||||||
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
|
"qty": 100,
|
||||||
|
"rate": 50,
|
||||||
|
"income_account": "Sales - _TC",
|
||||||
|
"expense_account": "Cost of Goods Sold - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC"
|
||||||
|
})
|
||||||
|
|
||||||
si.append("taxes", {
|
si.append("taxes", {
|
||||||
"charge_type": "On Net Total",
|
"charge_type": "On Net Total",
|
||||||
"account_head": "_Test Account Service Tax - _TC",
|
"account_head": "_Test Account Service Tax - _TC",
|
||||||
@@ -1115,11 +1191,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
"rate": 10
|
"rate": 10
|
||||||
})
|
})
|
||||||
si.insert()
|
si.insert()
|
||||||
|
return si
|
||||||
tax_breakup_html = '''\n<div class="tax-break-up" style="overflow-x: auto;">\n\t<table class="table table-bordered table-hover">\n\t\t<thead><tr><th class="text-left" style="min-width: 120px;">Item Name</th><th class="text-right" style="min-width: 80px;">Taxable Amount</th><th class="text-right" style="min-width: 80px;">_Test Account Service Tax - _TC</th></tr></thead>\n\t\t<tbody><tr><td>_Test Item</td><td class="text-right">\u20b9 5,000.00</td><td class="text-right">(10.0%) \u20b9 500.00</td></tr></tbody>\n\t</table>\n</div>'''
|
|
||||||
|
|
||||||
self.assertEqual(si.other_charges_calculation, tax_breakup_html)
|
|
||||||
|
|
||||||
|
|
||||||
def create_sales_invoice(**args):
|
def create_sales_invoice(**args):
|
||||||
si = frappe.new_doc("Sales Invoice")
|
si = frappe.new_doc("Sales Invoice")
|
||||||
@@ -1140,6 +1212,7 @@ def create_sales_invoice(**args):
|
|||||||
|
|
||||||
si.append("items", {
|
si.append("items", {
|
||||||
"item_code": args.item or args.item_code or "_Test Item",
|
"item_code": args.item or args.item_code or "_Test Item",
|
||||||
|
"gst_hsn_code": "999800",
|
||||||
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||||
"qty": args.qty or 1,
|
"qty": args.qty or 1,
|
||||||
"rate": args.rate or 100,
|
"rate": args.rate or 100,
|
||||||
|
|||||||
@@ -1424,7 +1424,7 @@
|
|||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"collapsible_depends_on": "eval:doc.serial_no || doc.batch_no",
|
"collapsible_depends_on": "eval:doc.serial_no || doc.batch_no",
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval: parent.update_stock",
|
"depends_on": "",
|
||||||
"fieldname": "warehouse_and_reference",
|
"fieldname": "warehouse_and_reference",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -2166,7 +2166,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-07-06 17:54:03.347700",
|
"modified": "2017-07-17 17:54:48.246507",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice Item",
|
"name": "Sales Invoice Item",
|
||||||
|
|||||||
@@ -1078,7 +1078,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
|||||||
} else if (item.barcode == me.serach_item.$input.val()) {
|
} else if (item.barcode == me.serach_item.$input.val()) {
|
||||||
search_status = false;
|
search_status = false;
|
||||||
return item.barcode == me.serach_item.$input.val();
|
return item.barcode == me.serach_item.$input.val();
|
||||||
} else if (reg.test(item.item_code.toLowerCase()) || reg.test(item.description.toLowerCase()) ||
|
} else if (reg.test(item.item_code.toLowerCase()) || (item.description && reg.test(item.description.toLowerCase())) ||
|
||||||
reg.test(item.item_name.toLowerCase()) || reg.test(item.item_group.toLowerCase())) {
|
reg.test(item.item_name.toLowerCase()) || reg.test(item.item_group.toLowerCase())) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -1351,7 +1351,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
|||||||
this.child.item_name = this.items[0].item_name;
|
this.child.item_name = this.items[0].item_name;
|
||||||
this.child.stock_uom = this.items[0].stock_uom;
|
this.child.stock_uom = this.items[0].stock_uom;
|
||||||
this.child.brand = this.items[0].brand;
|
this.child.brand = this.items[0].brand;
|
||||||
this.child.description = this.items[0].description;
|
this.child.description = this.items[0].description || this.items[0].item_name;
|
||||||
this.child.discount_percentage = 0.0;
|
this.child.discount_percentage = 0.0;
|
||||||
this.child.qty = 1;
|
this.child.qty = 1;
|
||||||
this.child.item_group = this.items[0].item_group;
|
this.child.item_group = this.items[0].item_group;
|
||||||
@@ -1398,10 +1398,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
|||||||
return erpnext.get_currency(this.frm.doc.company);
|
return erpnext.get_currency(this.frm.doc.company);
|
||||||
},
|
},
|
||||||
|
|
||||||
show_item_wise_taxes: function () {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
show_items_in_item_cart: function () {
|
show_items_in_item_cart: function () {
|
||||||
var me = this;
|
var me = this;
|
||||||
var $items = this.wrapper.find(".items").empty();
|
var $items = this.wrapper.find(".items").empty();
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import datetime
|
|||||||
from frappe import _, msgprint, scrub
|
from frappe import _, msgprint, scrub
|
||||||
from frappe.defaults import get_user_permissions
|
from frappe.defaults import get_user_permissions
|
||||||
from frappe.model.utils import get_fetch_values
|
from frappe.model.utils import get_fetch_values
|
||||||
from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff, \
|
from frappe.utils import (add_days, getdate, formatdate, get_first_day, date_diff,
|
||||||
add_years, get_timestamp, nowdate, flt
|
add_years, get_timestamp, nowdate, flt)
|
||||||
from frappe.contacts.doctype.address.address import get_address_display, get_default_address
|
from frappe.contacts.doctype.address.address import (get_address_display,
|
||||||
|
get_default_address, get_company_address)
|
||||||
from frappe.contacts.doctype.contact.contact import get_contact_details, get_default_contact
|
from frappe.contacts.doctype.contact.contact import get_contact_details, get_default_contact
|
||||||
from erpnext.exceptions import PartyFrozen, PartyDisabled, InvalidAccountCurrency
|
from erpnext.exceptions import PartyFrozen, PartyDisabled, InvalidAccountCurrency
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
@@ -77,8 +78,9 @@ def set_address_details(out, party, party_type, doctype=None, company=None):
|
|||||||
out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name))
|
out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name))
|
||||||
|
|
||||||
if doctype and doctype in ['Sales Invoice']:
|
if doctype and doctype in ['Sales Invoice']:
|
||||||
out.company_address = get_default_address('Company', company)
|
out.update(get_company_address(company))
|
||||||
out.update(get_fetch_values(doctype, 'company_address', out.company_address))
|
if out.company_address:
|
||||||
|
out.update(get_fetch_values(doctype, 'company_address', out.company_address))
|
||||||
|
|
||||||
def set_contact_details(out, party, party_type):
|
def set_contact_details(out, party, party_type):
|
||||||
out.contact_person = get_default_contact(party_type, party.name)
|
out.contact_person = get_default_contact(party_type, party.name)
|
||||||
|
|||||||
@@ -1546,6 +1546,36 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 1,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "sec_tax_breakup",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Tax Breakup",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@@ -1553,7 +1583,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "other_charges_calculation",
|
"fieldname": "other_charges_calculation",
|
||||||
"fieldtype": "HTML",
|
"fieldtype": "Text",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
@@ -1568,7 +1598,7 @@
|
|||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 1,
|
||||||
"remember_last_selected_value": 0,
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
@@ -3305,7 +3335,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-06-13 14:29:21.066814",
|
"modified": "2017-07-19 14:03:51.838328",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order",
|
"name": "Purchase Order",
|
||||||
|
|||||||
@@ -11,3 +11,6 @@ from erpnext.controllers.print_settings import print_settings_for_item_table
|
|||||||
class PurchaseOrderItem(Document):
|
class PurchaseOrderItem(Document):
|
||||||
def __setup__(self):
|
def __setup__(self):
|
||||||
print_settings_for_item_table(self)
|
print_settings_for_item_table(self)
|
||||||
|
|
||||||
|
def on_doctype_update():
|
||||||
|
frappe.db.add_index("Purchase Order Item", ["item_code", "warehouse"])
|
||||||
@@ -1120,6 +1120,36 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 1,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "tax_breakup",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Tax Breakup",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@@ -1127,7 +1157,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "other_charges_calculation",
|
"fieldname": "other_charges_calculation",
|
||||||
"fieldtype": "HTML",
|
"fieldtype": "Text",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
@@ -1142,7 +1172,7 @@
|
|||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 1,
|
||||||
"remember_last_selected_value": 0,
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
@@ -2217,7 +2247,7 @@
|
|||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
"modified": "2017-06-13 14:28:54.466450",
|
"modified": "2017-07-19 13:51:18.929697",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Supplier Quotation",
|
"name": "Supplier Quotation",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 0,
|
"allow_import": 0,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"autoname": "hash",
|
"autoname": "hash",
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 1,
|
"bold": 1,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -73,34 +76,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_bulk_edit": 0,
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_3",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -131,6 +107,66 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "column_break_3",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "lead_time_days",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Lead Time in days",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
@@ -160,6 +196,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -192,6 +229,7 @@
|
|||||||
"width": "300px"
|
"width": "300px"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -219,6 +257,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -248,6 +287,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -278,6 +318,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -306,6 +347,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 1,
|
"bold": 1,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -338,6 +380,7 @@
|
|||||||
"width": "60px"
|
"width": "60px"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -368,6 +411,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -397,6 +441,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -426,6 +471,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -453,6 +499,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -486,6 +533,7 @@
|
|||||||
"width": "100px"
|
"width": "100px"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -515,6 +563,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -544,6 +593,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -571,6 +621,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 1,
|
"bold": 1,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -602,6 +653,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -633,6 +685,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -660,6 +713,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -694,6 +748,7 @@
|
|||||||
"width": "100px"
|
"width": "100px"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -725,6 +780,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -754,6 +810,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -782,6 +839,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -811,6 +869,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -841,6 +900,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -869,6 +929,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -899,6 +960,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -929,6 +991,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -957,6 +1020,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -988,6 +1052,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1017,6 +1082,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1047,6 +1113,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1080,6 +1147,7 @@
|
|||||||
"width": "120px"
|
"width": "120px"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1110,6 +1178,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1137,6 +1206,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1167,6 +1237,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1196,6 +1267,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1227,6 +1299,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1259,6 +1332,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1290,6 +1364,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1318,6 +1393,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1347,6 +1423,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1377,17 +1454,17 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"has_web_view": 0,
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"image_view": 0,
|
"image_view": 0,
|
||||||
"in_create": 0,
|
"in_create": 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": "2017-02-17 16:43:59.582188",
|
"modified": "2017-07-10 09:08:52.015387",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Supplier Quotation Item",
|
"name": "Supplier Quotation Item",
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ class AccountsController(TransactionBase):
|
|||||||
def set_missing_item_details(self, for_validate=False):
|
def set_missing_item_details(self, for_validate=False):
|
||||||
"""set missing item values"""
|
"""set missing item values"""
|
||||||
from erpnext.stock.get_item_details import get_item_details
|
from erpnext.stock.get_item_details import get_item_details
|
||||||
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
|
|
||||||
if hasattr(self, "items"):
|
if hasattr(self, "items"):
|
||||||
parent_dict = {}
|
parent_dict = {}
|
||||||
@@ -196,7 +197,7 @@ class AccountsController(TransactionBase):
|
|||||||
|
|
||||||
elif fieldname == "serial_no":
|
elif fieldname == "serial_no":
|
||||||
stock_qty = item.get("stock_qty") * -1 if item.get("stock_qty") < 0 else item.get("stock_qty")
|
stock_qty = item.get("stock_qty") * -1 if item.get("stock_qty") < 0 else item.get("stock_qty")
|
||||||
if stock_qty != len(item.get('serial_no').split('\n')):
|
if stock_qty != len(get_serial_nos(item.get('serial_no'))):
|
||||||
item.set(fieldname, value)
|
item.set(fieldname, value)
|
||||||
|
|
||||||
elif fieldname == "conversion_factor" and not item.get("conversion_factor"):
|
elif fieldname == "conversion_factor" and not item.get("conversion_factor"):
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
|||||||
import json
|
import json
|
||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
from frappe import _, scrub
|
from frappe import _, scrub
|
||||||
from frappe.utils import cint, flt, cstr, fmt_money, round_based_on_smallest_currency_fraction
|
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
|
||||||
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
|
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
|
||||||
validate_taxes_and_charges, validate_inclusive_tax
|
validate_taxes_and_charges, validate_inclusive_tax
|
||||||
|
|
||||||
@@ -509,103 +509,75 @@ class calculate_taxes_and_totals(object):
|
|||||||
return rate_with_margin
|
return rate_with_margin
|
||||||
|
|
||||||
def set_item_wise_tax_breakup(self):
|
def set_item_wise_tax_breakup(self):
|
||||||
item_tax = {}
|
self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
|
||||||
tax_accounts = []
|
|
||||||
company_currency = erpnext.get_company_currency(self.doc.company)
|
|
||||||
|
|
||||||
item_tax, tax_accounts = self.get_item_tax(item_tax, tax_accounts, company_currency)
|
def get_itemised_tax_breakup_html(doc):
|
||||||
|
if not doc.taxes:
|
||||||
|
return
|
||||||
|
frappe.flags.company = doc.company
|
||||||
|
|
||||||
headings = get_table_column_headings(tax_accounts)
|
# get headers
|
||||||
|
tax_accounts = list(set([d.description for d in doc.taxes]))
|
||||||
|
headers = get_itemised_tax_breakup_header(doc.doctype + " Item", tax_accounts)
|
||||||
|
|
||||||
distinct_items = self.get_distinct_items()
|
# get tax breakup data
|
||||||
|
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(doc)
|
||||||
|
|
||||||
rows = get_table_rows(distinct_items, item_tax, tax_accounts, company_currency)
|
frappe.flags.company = None
|
||||||
|
|
||||||
if not rows:
|
return frappe.render_template(
|
||||||
self.doc.other_charges_calculation = ""
|
"templates/includes/itemised_tax_breakup.html", dict(
|
||||||
else:
|
headers=headers,
|
||||||
self.doc.other_charges_calculation = '''
|
itemised_tax=itemised_tax,
|
||||||
<div class="tax-break-up" style="overflow-x: auto;">
|
itemised_taxable_amount=itemised_taxable_amount,
|
||||||
<table class="table table-bordered table-hover">
|
tax_accounts=tax_accounts,
|
||||||
<thead><tr>{headings}</tr></thead>
|
company_currency=erpnext.get_company_currency(doc.company)
|
||||||
<tbody>{rows}</tbody>
|
)
|
||||||
</table>
|
)
|
||||||
</div>'''.format(**{
|
|
||||||
"headings": "".join(headings),
|
|
||||||
"rows": "".join(rows)
|
|
||||||
})
|
|
||||||
|
|
||||||
def get_item_tax(self, item_tax, tax_accounts, company_currency):
|
@erpnext.allow_regional
|
||||||
for tax in self.doc.taxes:
|
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
|
||||||
tax_amount_precision = tax.precision("tax_amount")
|
return [_("Item"), _("Taxable Amount")] + tax_accounts
|
||||||
tax_rate_precision = tax.precision("rate");
|
|
||||||
|
|
||||||
item_tax_map = self._load_item_tax_rate(tax.item_wise_tax_detail)
|
@erpnext.allow_regional
|
||||||
for item_code, tax_data in item_tax_map.items():
|
def get_itemised_tax_breakup_data(doc):
|
||||||
if not item_tax.get(item_code):
|
itemised_tax = get_itemised_tax(doc.taxes)
|
||||||
item_tax[item_code] = {}
|
|
||||||
|
|
||||||
if isinstance(tax_data, list):
|
itemised_taxable_amount = get_itemised_taxable_amount(doc.items)
|
||||||
tax_rate = ""
|
|
||||||
if tax_data[0]:
|
|
||||||
if tax.charge_type == "Actual":
|
|
||||||
tax_rate = fmt_money(flt(tax_data[0], tax_amount_precision),
|
|
||||||
tax_amount_precision, company_currency)
|
|
||||||
else:
|
|
||||||
tax_rate = cstr(flt(tax_data[0], tax_rate_precision)) + "%"
|
|
||||||
|
|
||||||
tax_amount = fmt_money(flt(tax_data[1], tax_amount_precision),
|
return itemised_tax, itemised_taxable_amount
|
||||||
tax_amount_precision, company_currency)
|
|
||||||
|
|
||||||
item_tax[item_code][tax.name] = [tax_rate, tax_amount]
|
def get_itemised_tax(taxes):
|
||||||
else:
|
itemised_tax = {}
|
||||||
item_tax[item_code][tax.name] = [cstr(flt(tax_data, tax_rate_precision)) + "%", ""]
|
for tax in taxes:
|
||||||
tax_accounts.append([tax.name, tax.account_head])
|
tax_amount_precision = tax.precision("tax_amount")
|
||||||
|
tax_rate_precision = tax.precision("rate")
|
||||||
|
|
||||||
return item_tax, tax_accounts
|
item_tax_map = json.loads(tax.item_wise_tax_detail) if tax.item_wise_tax_detail else {}
|
||||||
|
|
||||||
|
for item_code, tax_data in item_tax_map.items():
|
||||||
|
itemised_tax.setdefault(item_code, frappe._dict())
|
||||||
|
|
||||||
def get_distinct_items(self):
|
if isinstance(tax_data, list) and tax_data[0]:
|
||||||
distinct_item_names = []
|
precision = tax_amount_precision if tax.charge_type == "Actual" else tax_rate_precision
|
||||||
distinct_items = []
|
|
||||||
for item in self.doc.items:
|
|
||||||
item_code = item.item_code or item.item_name
|
|
||||||
if item_code not in distinct_item_names:
|
|
||||||
distinct_item_names.append(item_code)
|
|
||||||
distinct_items.append(item)
|
|
||||||
|
|
||||||
return distinct_items
|
itemised_tax[item_code][tax.description] = frappe._dict(dict(
|
||||||
|
tax_rate=flt(tax_data[0], precision),
|
||||||
def get_table_column_headings(tax_accounts):
|
tax_amount=flt(tax_data[1], tax_amount_precision)
|
||||||
headings_name = [_("Item Name"), _("Taxable Amount")] + [d[1] for d in tax_accounts]
|
))
|
||||||
headings = []
|
|
||||||
for head in headings_name:
|
|
||||||
if head == _("Item Name"):
|
|
||||||
headings.append('<th style="min-width: 120px;" class="text-left">' + (head or "") + "</th>")
|
|
||||||
else:
|
|
||||||
headings.append('<th style="min-width: 80px;" class="text-right">' + (head or "") + "</th>")
|
|
||||||
|
|
||||||
return headings
|
|
||||||
|
|
||||||
def get_table_rows(distinct_items, item_tax, tax_accounts, company_currency):
|
|
||||||
rows = []
|
|
||||||
for item in distinct_items:
|
|
||||||
item_tax_record = item_tax.get(item.item_code or item.item_name)
|
|
||||||
if not item_tax_record:
|
|
||||||
continue
|
|
||||||
|
|
||||||
taxes = []
|
|
||||||
for head in tax_accounts:
|
|
||||||
if item_tax_record[head[0]]:
|
|
||||||
taxes.append("<td class='text-right'>(" + item_tax_record[head[0]][0] + ") "
|
|
||||||
+ item_tax_record[head[0]][1] + "</td>")
|
|
||||||
else:
|
else:
|
||||||
taxes.append("<td></td>")
|
itemised_tax[item_code][tax.description] = frappe._dict(dict(
|
||||||
|
tax_rate=flt(tax_data, tax_rate_precision),
|
||||||
|
tax_amount=0.0
|
||||||
|
))
|
||||||
|
|
||||||
rows.append("<tr><td>{item_name}</td><td class='text-right'>{taxable_amount}</td>{taxes}</tr>".format(**{
|
return itemised_tax
|
||||||
"item_name": item.item_name,
|
|
||||||
"taxable_amount": fmt_money(item.net_amount, item.precision("net_amount"), company_currency),
|
|
||||||
"taxes": "".join(taxes)
|
|
||||||
}))
|
|
||||||
|
|
||||||
return rows
|
def get_itemised_taxable_amount(items):
|
||||||
|
itemised_taxable_amount = frappe._dict()
|
||||||
|
for item in items:
|
||||||
|
item_code = item.item_code or item.item_name
|
||||||
|
itemised_taxable_amount.setdefault(item_code, 0)
|
||||||
|
itemised_taxable_amount[item_code] += item.net_amount
|
||||||
|
|
||||||
|
return itemised_taxable_amount
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Series",
|
"label": "Series",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Opportunity From",
|
"label": "Opportunity From",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
@@ -277,8 +277,8 @@
|
|||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 0,
|
||||||
"label": "Opportunity Type",
|
"label": "Opportunity Type",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
@@ -310,7 +310,7 @@
|
|||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Status",
|
"label": "Status",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
@@ -1189,7 +1189,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-06-13 14:29:07.077697",
|
"modified": "2017-07-10 15:29:23.921967",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Opportunity",
|
"name": "Opportunity",
|
||||||
|
|||||||
@@ -272,4 +272,6 @@ def auto_close_opportunity():
|
|||||||
for opportunity in opportunities:
|
for opportunity in opportunities:
|
||||||
doc = frappe.get_doc("Opportunity", opportunity.get("name"))
|
doc = frappe.get_doc("Opportunity", opportunity.get("name"))
|
||||||
doc.status = "Closed"
|
doc.status = "Closed"
|
||||||
doc.save(ignore_permissions=True)
|
doc.flags.ignore_permissions = True
|
||||||
|
doc.flags.ignore_mandatory = True
|
||||||
|
doc.save()
|
||||||
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 215 KiB |
BIN
erpnext/docs/assets/img/sales_goal/sales_goal_notification.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
erpnext/docs/assets/img/sales_goal/sales_history_graph.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
erpnext/docs/assets/img/sales_goal/setting_sales_goal.gif
Normal file
|
After Width: | Height: | Size: 7.8 MiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 38 KiB |
@@ -15,5 +15,6 @@ third-party-backups
|
|||||||
workflows
|
workflows
|
||||||
bar-code
|
bar-code
|
||||||
company-setup
|
company-setup
|
||||||
|
setting-company-sales-goal
|
||||||
calculate-incentive-for-sales-team
|
calculate-incentive-for-sales-team
|
||||||
articles
|
articles
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Setting Company Sales Goal
|
||||||
|
|
||||||
|
Monthly sales targets can be set for a company via the Company master. By default, the Company master dashboard features past sales stats.
|
||||||
|
|
||||||
|
<img class="screenshot" alt="Sales Graph" src="{{docs_base_url}}/assets/img/sales_goal/sales_history_graph.png">
|
||||||
|
|
||||||
|
You can set the **Sales Target** field to track progress to track progress with respect to it.
|
||||||
|
|
||||||
|
<img class="screenshot" alt="Setting Sales Goal" src="{{docs_base_url}}/assets/img/sales_goal/setting_sales_goal.gif">
|
||||||
|
|
||||||
|
The target progress is also shown in notifications:
|
||||||
|
|
||||||
|
<img class="screenshot" alt="Sales Notification" src="{{docs_base_url}}/assets/img/sales_goal/sales_goal_notification.png">
|
||||||
|
|
||||||
|
{next}
|
||||||
@@ -9,4 +9,4 @@ WORK IN PROGRESS
|
|||||||
|
|
||||||
**Trabajo en progreso.**
|
**Trabajo en progreso.**
|
||||||
|
|
||||||
[The Spanish Translation of the ERPNext manual is in progress. Click here to see the english manual]({{ docs_base_url }}/user/manual/en)
|
[La traducción al Español del manual de ERPNext está en progreso. Click aquí para ver el manual en ingles]({{ docs_base_url }}/user/manual/en)
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
introduction
|
||||||
accounts
|
accounts
|
||||||
|
|||||||
20
erpnext/docs/user/manual/es/introduction/do-i-need-an-erp.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
ERPNext es una herramienta moderna que no solo abarca el módulo de contabilidad,
|
||||||
|
sino que también, cubre todas las otras funciones de su negocio en una plataforma integrada.
|
||||||
|
Tiene muchos beneficios sobre los sistemas tradicionales de contabilidad y otros ERP en el mercado.
|
||||||
|
|
||||||
|
### Beneficios sobre los sistemas de contabilidad tradicionales:
|
||||||
|
|
||||||
|
* Es más que solo contabilidad! Gestionar inventario, facturación, cotizaciones, clientes potenciales, nómina y mucho más.
|
||||||
|
* Mantiene toda tu información segura y en un solo lugar. No siga buscando sus datos cuando más lo necesitas en diferente hojas de calculo y en diferentes ordenadores.
|
||||||
|
Gestiona a todos tus empleados en el mismo lugar. Todos los usuarios obtienen información actualizada.
|
||||||
|
* No más trabajo doble. No introduzcas la misma información desde su procesador de textos a su herramienta de contabilidad. Todo está integrado!
|
||||||
|
* Manten un historial. Obten el historial completo de un cliente o un acuerdo en un solo lugar
|
||||||
|
|
||||||
|
### Beneficios sobre ERPs más grandes
|
||||||
|
|
||||||
|
* $$$ - Ahorra dinero.
|
||||||
|
* **Más facíl de configurar:** Grandes ERP son extramadamente complicados para configurar y van a preguntar demasiadas preguntas amtes de que puedas hacer algo utíl.
|
||||||
|
* **Más facíl de usar:** Una moderna y limpia interfaz web va a mantener sus usuarios contentos y en un entorno mas familiar.
|
||||||
|
* **Código Abierto :** Este sistema es completamente gratis y puedes instalarlo/configurarlo donde desees.
|
||||||
|
|
||||||
|
{next}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
Hay muchas manera de comenzar a utilizar ERPNext.
|
||||||
|
|
||||||
|
### 1\. Ver el Demo
|
||||||
|
|
||||||
|
Si deseas entrar en contacto con la interfaz de usuario de ERPNext y **sentir** la aplicación, solo tienes que ver el demo en:
|
||||||
|
see the demo at:
|
||||||
|
|
||||||
|
* <https://demo.erpnext.com>
|
||||||
|
|
||||||
|
### 2\. Comienza con una cuenta gratis en ERPNext.com
|
||||||
|
|
||||||
|
|
||||||
|
ERPNext.com es manejado por la organización (Frappe) que publicó ERPNext.
|
||||||
|
Puedes iniciar con su propia cuenta en [registrandote en la página](https://erpnext.com).
|
||||||
|
|
||||||
|
También, puedes hostear tu aplicación en erpnext.com comprando un plan de alojamiento.
|
||||||
|
De esta forma, estas aportando a la organización que desarrolla y mejora ERPNext.
|
||||||
|
También obten soporte de uno-a-uno con los planes de alojamiento.
|
||||||
|
|
||||||
|
### 3\. Descarga una Maquina Virtual
|
||||||
|
|
||||||
|
Para evitar las molestias de instalar el sistema, ERPNext está disponible como una image virtual (un sistema operativo completo con ERPNext instalado).
|
||||||
|
Puedes usarla en **cualquier** plataforma incluyendo Microsoft Windows.
|
||||||
|
|
||||||
|
[Click aquí para ver las instrucciones de como usar la imagen](https://erpnext.com/download)
|
||||||
|
|
||||||
|
### 4\. Instalar ERPNext en su ordenador Unix/Linux/Mac
|
||||||
|
|
||||||
|
En caso de estar relacionado con la instalación de aplicaciones en plataformas *nix, leer las instrucciones de como instalarlo usando [Frappe Bench](https://github.com/frappe/bench).
|
||||||
|
|
||||||
|
{next}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
Antes de que empieces a manejar todas tus operaciones en ERPNext, primero
|
||||||
|
deberías estar familiarizado con el sistema y los términos que utiliza.
|
||||||
|
Por esa razón recomendamos que la implementación pase en dos fases.
|
||||||
|
|
||||||
|
* La **Fase de Prueba**, donde introduces información de prueba que representan sus transacciones del día a día y la **Fase de Producción**, donde comenzamos a introducir información real.
|
||||||
|
|
||||||
|
### Fase de Prueba
|
||||||
|
|
||||||
|
* Leer el manual
|
||||||
|
* Crea una cuenta gratis en [https://erpnext.com](https://erpnext.com) (La forma más facíl de experimental).
|
||||||
|
* Crea su primer Cliente, Suplidor y Producto. Agrega varios de estos para que se familiarice con ellos.
|
||||||
|
* Crea un Grupo de Clientes, Grupo de Productos, Almacenes, Grupo de Suplidores, para que puedas clasificar sus productos.
|
||||||
|
* Completar un ciclo estandar de ventas - Iniciativa > Oportunidad > Cotización > Orden de Venta > Nota de Entrega > Factura de Venta > Pago (Entrada de diario)
|
||||||
|
* Completa un ciclo estandar de compra - Solicitud de Material > Orden de Compra > Recibo de Compra > Pagos (Entrada de diario).
|
||||||
|
* Completar un ciclo de manofactura (si aplica) - BOM > Herramienta de Planificación de Producción > Orden de Producción > Problema de material
|
||||||
|
* Replicar un escenario de su día a día dentro del sistema.
|
||||||
|
* Crea un custom fields, formato de impresión, etc como sea requerido.
|
||||||
|
|
||||||
|
### Fase de Producción
|
||||||
|
|
||||||
|
Una vez ya estes falimiliarizado con ERPNext, inicia introduciendo la información real!
|
||||||
|
|
||||||
|
* Borra toda la información de prueba de la cuenta o inicia con una nueva instalación.
|
||||||
|
* Si solo quieres borrar las transacciones y no las demás informaciones sobre Productos, Clientes, Suplidores, BOM etc, puedes dar click en Eliminar Transacciones de su compañia y inicia desde cero. Para hacerlo, abre el registro de la compañia via Setup > Masters > Company y eliminar las transacciones de su compañia clickeando en el botón **Eliminar las transacciones de la compañia** al final del formulario de la compañia.
|
||||||
|
* También puedes configurar una nueva cuenta en [https://erpnext.com](https://erpnext.com), y usa los 30 días gratis. [Encuentra mas formas de usar ERPNext](/introduction/getting-started-with-erpnext)
|
||||||
|
* Configura todos los módulos con Grupos de Clientes, Grupos de Productos, Almacenes, BOMs etc.
|
||||||
|
* Importar Clientes, Suplidores, Productos, Contactos y Direcciones usando la Herramienta de Importación de Data.
|
||||||
|
* Importar el inventario de apertura usando la Herramienta de Reconciliación de Inventario.
|
||||||
|
* Crear la entrada de apertura de cuenta usando la Entrada de Diario y crea facturas de ventas pendientes y facturas de compra.
|
||||||
|
* Si necesitas ayuda, [puedes pagar por soporte](https://erpnext.com/pricing) o [preguntar en el foro de la comunidad](https://discuss.erpnext.com).
|
||||||
|
|
||||||
|
{next}
|
||||||
40
erpnext/docs/user/manual/es/introduction/index.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
## ¿Qué es un ERP y Por qué debería interesarme?
|
||||||
|
|
||||||
|
(Si ya sabes que necesitas un sistema todo-en-uno para su compañia, puedes pasar a la siguiente página)
|
||||||
|
|
||||||
|
Si eres dueño de una pequeña empresa que tiene varios empleados, debes entender que es difícil manejar la naturaleza dinámica de hacer negocios.
|
||||||
|
Pequeñas empresas no son tan diferentes que las grandes empresas. Las pequeñas empresas contienen la mayoria de las complejidades que posee una empresa grande junto a otras reestricciones.
|
||||||
|
Las pequeñas empresas tienen que comunicarse con clientes, hacer contabilidad, pagar impuestos, pagar nómina, gestionar tiempos,
|
||||||
|
proporsionar bienes y servicios de calidad, responder preguntar, y mantener a todos contentos como lo hacen las grandes empresas.
|
||||||
|
|
||||||
|
Grandes empresas tienen la venraja de usar sistemas avanzados para manejar sus procesos de una forma mas eficiente.
|
||||||
|
Pequeñas empresas, sin embargo, luchan para mantener las cosas organizadas. Normalmente usan un conjuntos de aplicaciones como hojas de calculos, sistemas de contabilidad,
|
||||||
|
un CRM etc para administrarse. El problema es que no todos estan en la misma página. Un ERP cambia todo eso.
|
||||||
|
|
||||||
|
## ¿Qué es ERPNext?
|
||||||
|
|
||||||
|
ERPNext es una solución de negocio de extremo a extremo que te ayuda a manejar toda la información de su negocio en una sola aplicación
|
||||||
|
y usado no solo para manejar operaciones, sino que tambien le permite tomar decisiones efectivas y bien documentadas justo en el momento que las necesites.
|
||||||
|
Forma una columna vertebral de su negocio para agregar fuerza, transparencia y control a su compañia.
|
||||||
|
|
||||||
|
Junto con otras cosas, ERPNext te ayudará con todo lo siguiente:
|
||||||
|
|
||||||
|
* Mantener registro de todas sus facturas y pagos.
|
||||||
|
* Saber que cantidad de cada producto hay disponible en almacen.
|
||||||
|
* Identificar y hacer seguimiento de los indicadores de rendimientos (KPI's)
|
||||||
|
* Identificar consultas abiertas de los clientes.
|
||||||
|
* Gestionar Nómina.
|
||||||
|
* Asignar tareas y hacer seguimiento de las mismas.
|
||||||
|
* Mantener una base de datos de todos sus clientes, suplidores y sus contactos.
|
||||||
|
* Preparar presupuestos.
|
||||||
|
* Hacer seguimiento a su presupuesto y sus gastos.
|
||||||
|
* Determinar el precio efectivo para ventas basado en la materia prima disponible, maquinaria y costo de esfuerzo.
|
||||||
|
* Obtener recordatorios sobre el calendario de mantenimientos.
|
||||||
|
* Publicar su página web.
|
||||||
|
|
||||||
|
Y Mucho mucho más.
|
||||||
|
|
||||||
|
|
||||||
|
### Temas
|
||||||
|
|
||||||
|
{index}
|
||||||
7
erpnext/docs/user/manual/es/introduction/index.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
do-i-need-an-erp
|
||||||
|
open-source
|
||||||
|
getting-started-with-erpnext
|
||||||
|
the-champion
|
||||||
|
implementation-strategy
|
||||||
|
key-workflows
|
||||||
|
concepts-and-terms
|
||||||
13
erpnext/docs/user/manual/es/introduction/key-workflows.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Flujo De Transacciones En ERPNext
|
||||||
|
|
||||||
|
Este diagrama cubre como ERPNext hace el seguimiento de la información de su compañia a través de funciones claves.
|
||||||
|
Este diagrama no cubre toda la funcionalidad o características de ERPNext.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
<img class="screenshot" alt="Workflow" src="{{docs_base_url}}/assets/img/setup/overview.png">
|
||||||
|
|
||||||
|
_Nota: No todos los pasos son obligatorios. ERPNext te permite pasar algunos pasos si deseas simplificar el proceso._
|
||||||
|
|
||||||
|
{next}
|
||||||
34
erpnext/docs/user/manual/es/introduction/open-source.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
El código fuente de ERPNext es de código abierto. Está abierto para que todos
|
||||||
|
podamos entenderlo, extenderlo o mejorarlo. Y es gratis!
|
||||||
|
|
||||||
|
Las ventajas de un Sistema de Código Abierto:
|
||||||
|
|
||||||
|
1. Puedes cambiar tu proveedor de servicios cuando quieras.
|
||||||
|
2. Puedas hostear la aplicación donde quieras, incluyendo en tu propio servidor para tener completa propiedad y privacidad de la información.
|
||||||
|
3. Puedes pedir ayuda a la comunidad en caso de necesitarla. No estas atado a un proveedor de servicios.
|
||||||
|
4. Te puedes beneficiar de un producto que es criticado y usado por una gran cantidad de personas,
|
||||||
|
quienes han reportado cientos de fallos y sugerencias para mejorarlo, y esto siempre va a continuar así.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Código Fuente de ERPNext
|
||||||
|
|
||||||
|
El repositorio que contiene el código fuente de ERPnext está disponible en GitHub y puede ser encontrado aquí
|
||||||
|
|
||||||
|
- [https://github.com/frappe/erpnext](https://github.com/frappe/erpnext)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Alternativas
|
||||||
|
|
||||||
|
Hay muchas soluciones ERP que puedes considerar. Los más populares son:
|
||||||
|
|
||||||
|
1. Odoo
|
||||||
|
2. OpenBravo
|
||||||
|
3. Apache OfBiz
|
||||||
|
4. xTuple
|
||||||
|
5. Compiere (y clones)
|
||||||
|
|
||||||
|
{next}
|
||||||
41
erpnext/docs/user/manual/es/introduction/the-champion.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<!-- no-heading -->
|
||||||
|
|
||||||
|
<h1 class="white">El campeón</h1>
|
||||||
|
|
||||||
|
<img alt="Champion" class="screenshot" src="{{docs_base_url}}/assets/img/setup/implementation-image.png">
|
||||||
|
|
||||||
|
Hemos visto docenas de implementaciones de sistemas ERP en los últimos años
|
||||||
|
y nos hemos dado cuenta que una implementación exitosa es más sobre cosas intangibles y actitudes.
|
||||||
|
|
||||||
|
**Los ERP no son requeridos.**
|
||||||
|
|
||||||
|
Como el ejercicio.
|
||||||
|
|
||||||
|
El cuerpo humano puede que parezca que no requiere ejercicio hoy ni quizas mañana, pero con el pasar del tiempo,
|
||||||
|
si desea mantener su cuerpo y su salud deberá comenzar a hacer ejercicio.
|
||||||
|
|
||||||
|
En esta misma forma, ERPs mejoran la salud de su compañia a largo plazo manteniendola ajustada y eficiente.
|
||||||
|
Mientas más demores en poner las cosas en orden, más tiempo pierdes, y estas más cerca de una desastre mayor.
|
||||||
|
|
||||||
|
Por tanto, cuando comienzas a implementar un ERP, manten la visión en beneficios a largo plazo.
|
||||||
|
Como el ejercicio, es doloroso al comienzo, pero va a hacer cosas maravillosas si te mantienes haciendolo.
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
## El Campeón
|
||||||
|
|
||||||
|
Un ERP significa un cambio en la organización y un cambio no sucede sin exfuerzo.
|
||||||
|
Cada cambio requiere un campeón y es la responsabilidad de el campeón el
|
||||||
|
organizar y motivar al equipo completo durante la implementación.
|
||||||
|
El campeón necesita ser activo en caso que algo salga mal.
|
||||||
|
|
||||||
|
En muchas organizaciones que hemos visto, frecuentemente el campeón es el dueño o un Administrador.
|
||||||
|
Ocasionalmente, el campeón es una persona externa quien es contratado con un propósito específico.
|
||||||
|
|
||||||
|
En cualquier caso, debes identificar su campeón primero.
|
||||||
|
|
||||||
|
Lo más seguro es que sea **usted!**
|
||||||
|
|
||||||
|
Comencemos!
|
||||||
|
|
||||||
|
{next}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# User Interface and Navigation
|
# User Interface and Navigation
|
||||||
|
|
||||||
<iframe width="660" height="371" src="https://www.youtube.com/embed/HdblX7kOWWs" frameborder="0" allowfullscreen></iframe>
|
<iframe width="660" height="371" src="https://www.youtube.com/embed/vKjHRzMEei0" frameborder="0" allowfullscreen></iframe>
|
||||||
|
|
||||||
**Duration: 2:17**
|
**Duration: 2:41**
|
||||||
|
|
||||||
This video walks you through using the ERPNext "Desk" interface. The ERPNext User Interface is very web friendly and if you have used a website or mobile app before, the navigation should be very intuitive.
|
This video walks you through using the ERPNext "Desk" interface. The ERPNext User Interface is very web friendly and if you have used a website or mobile app before, the navigation should be very intuitive.
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from . import __version__ as app_version
|
|
||||||
|
|
||||||
app_name = "erpnext"
|
app_name = "erpnext"
|
||||||
app_title = "ERPNext"
|
app_title = "ERPNext"
|
||||||
@@ -80,6 +79,7 @@ website_route_rules = [
|
|||||||
"parents": [{"title": _("Supplier Quotation"), "name": "quotations"}]
|
"parents": [{"title": _("Supplier Quotation"), "name": "quotations"}]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{"from_route": "/quotation", "to_route": "Quotation"},
|
||||||
{"from_route": "/shipments", "to_route": "Delivery Note"},
|
{"from_route": "/shipments", "to_route": "Delivery Note"},
|
||||||
{"from_route": "/shipments/<path:name>", "to_route": "order",
|
{"from_route": "/shipments/<path:name>", "to_route": "order",
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -110,6 +110,7 @@ standard_portal_menu_items = [
|
|||||||
{"title": _("Projects"), "route": "/project", "reference_doctype": "Project"},
|
{"title": _("Projects"), "route": "/project", "reference_doctype": "Project"},
|
||||||
{"title": _("Request for Quotations"), "route": "/rfq", "reference_doctype": "Request for Quotation", "role": "Supplier"},
|
{"title": _("Request for Quotations"), "route": "/rfq", "reference_doctype": "Request for Quotation", "role": "Supplier"},
|
||||||
{"title": _("Supplier Quotation"), "route": "/quotations", "reference_doctype": "Supplier Quotation", "role": "Supplier"},
|
{"title": _("Supplier Quotation"), "route": "/quotations", "reference_doctype": "Supplier Quotation", "role": "Supplier"},
|
||||||
|
{"title": _("Quotations"), "route": "/quotation", "reference_doctype": "Quotation", "role":"Customer"},
|
||||||
{"title": _("Orders"), "route": "/orders", "reference_doctype": "Sales Order", "role":"Customer"},
|
{"title": _("Orders"), "route": "/orders", "reference_doctype": "Sales Order", "role":"Customer"},
|
||||||
{"title": _("Invoices"), "route": "/invoices", "reference_doctype": "Sales Invoice", "role":"Customer"},
|
{"title": _("Invoices"), "route": "/invoices", "reference_doctype": "Sales Invoice", "role":"Customer"},
|
||||||
{"title": _("Shipments"), "route": "/shipments", "reference_doctype": "Delivery Note", "role":"Customer"},
|
{"title": _("Shipments"), "route": "/shipments", "reference_doctype": "Delivery Note", "role":"Customer"},
|
||||||
@@ -182,10 +183,13 @@ scheduler_events = {
|
|||||||
"erpnext.projects.doctype.task.task.set_tasks_as_overdue",
|
"erpnext.projects.doctype.task.task.set_tasks_as_overdue",
|
||||||
"erpnext.accounts.doctype.asset.depreciation.post_depreciation_entries",
|
"erpnext.accounts.doctype.asset.depreciation.post_depreciation_entries",
|
||||||
"erpnext.hr.doctype.daily_work_summary_settings.daily_work_summary_settings.send_summary",
|
"erpnext.hr.doctype.daily_work_summary_settings.daily_work_summary_settings.send_summary",
|
||||||
"erpnext.stock.doctype.serial_no.serial_no.update_maintenance_status"
|
"erpnext.stock.doctype.serial_no.serial_no.update_maintenance_status",
|
||||||
|
"erpnext.setup.doctype.company.company.cache_companies_monthly_sales_history"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
email_brand_image = "assets/erpnext/images/erpnext-logo.jpg"
|
||||||
|
|
||||||
default_mail_footer = """<div style="text-align: center;">
|
default_mail_footer = """<div style="text-align: center;">
|
||||||
<a href="https://erpnext.com?source=via_email_footer" target="_blank" style="color: #8d99a6;">
|
<a href="https://erpnext.com?source=via_email_footer" target="_blank" style="color: #8d99a6;">
|
||||||
Sent via ERPNext
|
Sent via ERPNext
|
||||||
@@ -203,3 +207,11 @@ bot_parsers = [
|
|||||||
get_site_info = 'erpnext.utilities.get_site_info'
|
get_site_info = 'erpnext.utilities.get_site_info'
|
||||||
|
|
||||||
payment_gateway_enabled = "erpnext.accounts.utils.create_payment_gateway_account"
|
payment_gateway_enabled = "erpnext.accounts.utils.create_payment_gateway_account"
|
||||||
|
|
||||||
|
regional_overrides = {
|
||||||
|
'India': {
|
||||||
|
'erpnext.tests.test_regional.test_method': 'erpnext.regional.india.utils.test_method',
|
||||||
|
'erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_header': 'erpnext.regional.india.utils.get_itemised_tax_breakup_header',
|
||||||
|
'erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_data': 'erpnext.regional.india.utils.get_itemised_tax_breakup_data'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from frappe.model.document import Document
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from email_reply_parser import EmailReplyParser
|
from email_reply_parser import EmailReplyParser
|
||||||
from erpnext.hr.doctype.employee.employee import is_holiday
|
from erpnext.hr.doctype.employee.employee import is_holiday
|
||||||
from frappe.utils import formatdate
|
from frappe.utils import global_date_format
|
||||||
from markdown2 import markdown
|
from markdown2 import markdown
|
||||||
|
|
||||||
class DailyWorkSummary(Document):
|
class DailyWorkSummary(Document):
|
||||||
@@ -24,17 +24,18 @@ class DailyWorkSummary(Document):
|
|||||||
|
|
||||||
def send_summary(self):
|
def send_summary(self):
|
||||||
'''Send summary of all replies. Called at midnight'''
|
'''Send summary of all replies. Called at midnight'''
|
||||||
message = self.get_summary_message()
|
args = self.get_message_details()
|
||||||
|
|
||||||
frappe.sendmail(recipients = get_employee_emails(self.company, False),
|
frappe.sendmail(recipients = get_employee_emails(self.company, False),
|
||||||
message = message,
|
template='daily_work_summary',
|
||||||
|
args=args,
|
||||||
subject = _('Daily Work Summary for {0}').format(self.company),
|
subject = _('Daily Work Summary for {0}').format(self.company),
|
||||||
reference_doctype=self.doctype, reference_name=self.name)
|
reference_doctype=self.doctype, reference_name=self.name)
|
||||||
|
|
||||||
self.db_set('status', 'Sent')
|
self.db_set('status', 'Sent')
|
||||||
|
|
||||||
def get_summary_message(self):
|
def get_message_details(self):
|
||||||
'''Return summary of replies as HTML'''
|
'''Return args for template'''
|
||||||
settings = frappe.get_doc('Daily Work Summary Settings')
|
settings = frappe.get_doc('Daily Work Summary Settings')
|
||||||
|
|
||||||
replies = frappe.get_all('Communication', fields=['content', 'text_content', 'sender'],
|
replies = frappe.get_all('Communication', fields=['content', 'text_content', 'sender'],
|
||||||
@@ -45,8 +46,12 @@ class DailyWorkSummary(Document):
|
|||||||
did_not_reply = self.email_sent_to.split()
|
did_not_reply = self.email_sent_to.split()
|
||||||
|
|
||||||
for d in replies:
|
for d in replies:
|
||||||
d.sender_name = frappe.db.get_value("Employee", {"user_id": d.sender},
|
emp = frappe.db.get_values("Employee", {"user_id": d.sender},
|
||||||
"employee_name") or d.sender
|
["employee_name", "image"], as_dict=True)
|
||||||
|
|
||||||
|
d.sender_name = emp[0].employee_name if emp else d.sender
|
||||||
|
d.image = emp[0].image if emp and emp[0].image else None
|
||||||
|
|
||||||
if d.sender in did_not_reply:
|
if d.sender in did_not_reply:
|
||||||
did_not_reply.remove(d.sender)
|
did_not_reply.remove(d.sender)
|
||||||
if d.text_content:
|
if d.text_content:
|
||||||
@@ -56,30 +61,12 @@ class DailyWorkSummary(Document):
|
|||||||
did_not_reply = [(frappe.db.get_value("Employee", {"user_id": email}, "employee_name") or email)
|
did_not_reply = [(frappe.db.get_value("Employee", {"user_id": email}, "employee_name") or email)
|
||||||
for email in did_not_reply]
|
for email in did_not_reply]
|
||||||
|
|
||||||
return frappe.render_template(self.get_summary_template(),
|
return dict(replies=replies,
|
||||||
dict(replies=replies,
|
original_message=settings.message,
|
||||||
original_message=settings.message,
|
title=_('Daily Work Summary for {0}'.format(global_date_format(self.creation))),
|
||||||
title=_('Daily Work Summary for {0}'.format(formatdate(self.creation))),
|
did_not_reply= ', '.join(did_not_reply) or '',
|
||||||
did_not_reply= ', '.join(did_not_reply) or '',
|
did_not_reply_title = _('No replies from'))
|
||||||
did_not_reply_title = _('No replies from')))
|
|
||||||
|
|
||||||
def get_summary_template(self):
|
|
||||||
return '''
|
|
||||||
<h3>{{ title }}</h3>
|
|
||||||
|
|
||||||
{% for reply in replies %}
|
|
||||||
<h4>{{ reply.sender_name }}</h4>
|
|
||||||
<p style="padding-bottom: 20px">
|
|
||||||
{{ reply.content }}
|
|
||||||
</p>
|
|
||||||
<hr>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% if did_not_reply %}
|
|
||||||
<p>{{ did_not_reply_title }}: {{ did_not_reply }}</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
def get_employee_emails(company, only_working=True):
|
def get_employee_emails(company, only_working=True):
|
||||||
'''Returns list of Employee user ids for the given company who are working today
|
'''Returns list of Employee user ids for the given company who are working today
|
||||||
|
|||||||
@@ -12,32 +12,31 @@ import frappe.utils
|
|||||||
|
|
||||||
class TestDailyWorkSummary(unittest.TestCase):
|
class TestDailyWorkSummary(unittest.TestCase):
|
||||||
def test_email_trigger(self):
|
def test_email_trigger(self):
|
||||||
settings, employees, emails = self.setup_and_prepare_test()
|
self.setup_and_prepare_test()
|
||||||
|
for d in self.employees:
|
||||||
for d in employees:
|
|
||||||
# check that email is sent to this employee
|
# check that email is sent to this employee
|
||||||
self.assertTrue(d.user_id in [d.recipient for d in emails
|
self.assertTrue(d.user_id in [d.recipient for d in self.emails
|
||||||
if settings.subject in d.message])
|
if self.settings.subject in d.message])
|
||||||
|
|
||||||
def test_email_trigger_failed(self):
|
def test_email_trigger_failed(self):
|
||||||
hour = '00'
|
hour = '00'
|
||||||
if frappe.utils.nowtime().split(':')[0]=='00':
|
if frappe.utils.nowtime().split(':')[0]=='00':
|
||||||
hour = '01'
|
hour = '01'
|
||||||
|
|
||||||
settings, employees, emails = self.setup_and_prepare_test(hour)
|
self.setup_and_prepare_test(hour)
|
||||||
|
|
||||||
for d in employees:
|
for d in self.employees:
|
||||||
# check that email is sent to this employee
|
# check that email is sent to this employee
|
||||||
self.assertFalse(d.user_id in [d.recipient for d in emails
|
self.assertFalse(d.user_id in [d.recipient for d in self.emails
|
||||||
if settings.subject in d.message])
|
if self.settings.subject in d.message])
|
||||||
|
|
||||||
def test_incoming(self):
|
def test_incoming(self):
|
||||||
settings, employees, emails = self.setup_and_prepare_test()
|
|
||||||
|
|
||||||
# get test mail with message-id as in-reply-to
|
# get test mail with message-id as in-reply-to
|
||||||
|
self.setup_and_prepare_test()
|
||||||
|
|
||||||
with open(os.path.join(os.path.dirname(__file__), "test_data", "test-reply.raw"), "r") as f:
|
with open(os.path.join(os.path.dirname(__file__), "test_data", "test-reply.raw"), "r") as f:
|
||||||
test_mails = [f.read().replace('{{ sender }}', employees[-1].user_id)\
|
test_mails = [f.read().replace('{{ sender }}', self.employees[-1].user_id)\
|
||||||
.replace('{{ message_id }}', emails[-1].message_id)]
|
.replace('{{ message_id }}', self.emails[-1].message_id)]
|
||||||
|
|
||||||
# pull the mail
|
# pull the mail
|
||||||
email_account = frappe.get_doc("Email Account", "_Test Email Account 1")
|
email_account = frappe.get_doc("Email Account", "_Test Email Account 1")
|
||||||
@@ -47,35 +46,39 @@ class TestDailyWorkSummary(unittest.TestCase):
|
|||||||
daily_work_summary = frappe.get_doc('Daily Work Summary',
|
daily_work_summary = frappe.get_doc('Daily Work Summary',
|
||||||
frappe.get_all('Daily Work Summary')[0].name)
|
frappe.get_all('Daily Work Summary')[0].name)
|
||||||
|
|
||||||
summary = daily_work_summary.get_summary_message()
|
args = daily_work_summary.get_message_details()
|
||||||
|
|
||||||
self.assertTrue('I built Daily Work Summary!' in summary)
|
self.assertTrue('I built Daily Work Summary!' in args.get('replies')[0].content)
|
||||||
|
|
||||||
def setup_and_prepare_test(self, hour=None):
|
def setup_and_prepare_test(self, hour=None):
|
||||||
if not hour:
|
|
||||||
hour = frappe.utils.nowtime().split(':')[0]
|
|
||||||
frappe.db.sql('delete from `tabDaily Work Summary`')
|
frappe.db.sql('delete from `tabDaily Work Summary`')
|
||||||
frappe.db.sql('delete from `tabEmail Queue`')
|
frappe.db.sql('delete from `tabEmail Queue`')
|
||||||
frappe.db.sql('delete from `tabEmail Queue Recipient`')
|
frappe.db.sql('delete from `tabEmail Queue Recipient`')
|
||||||
frappe.db.sql('delete from `tabCommunication`')
|
frappe.db.sql('delete from `tabCommunication`')
|
||||||
|
|
||||||
# setup email to trigger at this our
|
self.setup_settings(hour)
|
||||||
settings = frappe.get_doc('Daily Work Summary Settings')
|
|
||||||
settings.companies = []
|
|
||||||
|
|
||||||
settings.append('companies', dict(company='_Test Company',
|
|
||||||
send_emails_at=hour + ':00'))
|
|
||||||
settings.test_subject = 'this is a subject for testing summary emails'
|
|
||||||
settings.save()
|
|
||||||
|
|
||||||
from erpnext.hr.doctype.daily_work_summary_settings.daily_work_summary_settings \
|
from erpnext.hr.doctype.daily_work_summary_settings.daily_work_summary_settings \
|
||||||
import trigger_emails
|
import trigger_emails
|
||||||
trigger_emails()
|
trigger_emails()
|
||||||
|
|
||||||
# check if emails are created
|
# check if emails are created
|
||||||
employees = frappe.get_all('Employee', fields = ['user_id'],
|
self.employees = frappe.get_all('Employee', fields = ['user_id'],
|
||||||
filters=dict(company='_Test Company', status='Active'))
|
filters=dict(company='_Test Company', status='Active', user_id=('!=', 'test@example.com')))
|
||||||
|
|
||||||
emails = frappe.db.sql("""select r.recipient, q.message, q.message_id from `tabEmail Queue` as q, `tabEmail Queue Recipient` as r where q.name = r.parent""", as_dict=1)
|
self.emails = frappe.db.sql("""select r.recipient, q.message, q.message_id from `tabEmail Queue` as q, `tabEmail Queue Recipient` as r where q.name = r.parent""", as_dict=1)
|
||||||
|
|
||||||
|
frappe.db.commit()
|
||||||
|
|
||||||
|
def setup_settings(self, hour=None):
|
||||||
|
# setup email to trigger at this our
|
||||||
|
if not hour:
|
||||||
|
hour = frappe.utils.nowtime().split(':')[0]
|
||||||
|
self.settings = frappe.get_doc('Daily Work Summary Settings')
|
||||||
|
self.settings.companies = []
|
||||||
|
|
||||||
|
self.settings.append('companies', dict(company='_Test Company',
|
||||||
|
send_emails_at=hour + ':00'))
|
||||||
|
self.settings.test_subject = 'this is a subject for testing summary emails'
|
||||||
|
self.settings.save()
|
||||||
|
|
||||||
return settings, employees, emails
|
|
||||||
@@ -27,6 +27,10 @@ erpnext.hr.ExpenseClaimController = frappe.ui.form.Controller.extend({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!d.expense_type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return frappe.call({
|
return frappe.call({
|
||||||
method: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_claim_account",
|
method: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_claim_account",
|
||||||
args: {
|
args: {
|
||||||
@@ -226,7 +230,7 @@ frappe.ui.form.on("Expense Claim",{
|
|||||||
frm.fields_dict["payable_account"].get_query = function() {
|
frm.fields_dict["payable_account"].get_query = function() {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
"root_type": "Liability",
|
"report_type": "Balance Sheet",
|
||||||
"account_type": "Payable"
|
"account_type": "Payable"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -905,7 +905,7 @@
|
|||||||
"label": "Status",
|
"label": "Status",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Draft\nPaid\nUnpaid\nSubmitted\nCancelled",
|
"options": "Draft\nPaid\nUnpaid\nRejected\nSubmitted\nCancelled",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
@@ -964,7 +964,7 @@
|
|||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
"modified": "2017-06-13 14:29:16.914609",
|
"modified": "2017-07-17 15:47:23.255142",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Expense Claim",
|
"name": "Expense Claim",
|
||||||
|
|||||||
@@ -39,10 +39,13 @@ class ExpenseClaim(AccountsController):
|
|||||||
"2": "Cancelled"
|
"2": "Cancelled"
|
||||||
}[cstr(self.docstatus or 0)]
|
}[cstr(self.docstatus or 0)]
|
||||||
|
|
||||||
if self.total_sanctioned_amount == self.total_amount_reimbursed and self.docstatus == 1:
|
if self.total_sanctioned_amount > 0 and self.total_sanctioned_amount == self.total_amount_reimbursed \
|
||||||
|
and self.docstatus == 1 and self.approval_status == 'Approved':
|
||||||
self.status = "Paid"
|
self.status = "Paid"
|
||||||
elif self.docstatus == 1:
|
elif self.total_sanctioned_amount > 0 and self.docstatus == 1 and self.approval_status == 'Approved':
|
||||||
self.status = "Unpaid"
|
self.status = "Unpaid"
|
||||||
|
elif self.docstatus == 1 and self.approval_status == 'Rejected':
|
||||||
|
self.status = 'Rejected'
|
||||||
|
|
||||||
def set_payable_account(self):
|
def set_payable_account(self):
|
||||||
if not self.payable_account and not self.is_paid:
|
if not self.payable_account and not self.is_paid:
|
||||||
@@ -157,6 +160,9 @@ class ExpenseClaim(AccountsController):
|
|||||||
self.total_claimed_amount = 0
|
self.total_claimed_amount = 0
|
||||||
self.total_sanctioned_amount = 0
|
self.total_sanctioned_amount = 0
|
||||||
for d in self.get('expenses'):
|
for d in self.get('expenses'):
|
||||||
|
if self.approval_status == 'Rejected':
|
||||||
|
d.sanctioned_amount = 0.0
|
||||||
|
|
||||||
self.total_claimed_amount += flt(d.claim_amount)
|
self.total_claimed_amount += flt(d.claim_amount)
|
||||||
self.total_sanctioned_amount += flt(d.sanctioned_amount)
|
self.total_sanctioned_amount += flt(d.sanctioned_amount)
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ frappe.listview_settings['Expense Claim'] = {
|
|||||||
get_indicator: function(doc) {
|
get_indicator: function(doc) {
|
||||||
if(doc.status == "Paid") {
|
if(doc.status == "Paid") {
|
||||||
return [__("Paid"), "green", "status,=,'Paid'"];
|
return [__("Paid"), "green", "status,=,'Paid'"];
|
||||||
} else {
|
}else if(doc.status == "Unpaid") {
|
||||||
return [__("Unpaid"), "orange"];
|
return [__("Unpaid"), "orange"];
|
||||||
|
} else if(doc.status == "Rejected") {
|
||||||
|
return [__("Rejected"), "grey"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -113,5 +113,23 @@ class TestExpenseClaim(unittest.TestCase):
|
|||||||
self.assertEquals(expected_values[gle.account][1], gle.debit)
|
self.assertEquals(expected_values[gle.account][1], gle.debit)
|
||||||
self.assertEquals(expected_values[gle.account][2], gle.credit)
|
self.assertEquals(expected_values[gle.account][2], gle.credit)
|
||||||
|
|
||||||
|
def test_rejected_expense_claim(self):
|
||||||
|
payable_account = get_payable_account("Wind Power LLC")
|
||||||
|
expense_claim = frappe.get_doc({
|
||||||
|
"doctype": "Expense Claim",
|
||||||
|
"employee": "_T-Employee-0001",
|
||||||
|
"payable_account": payable_account,
|
||||||
|
"approval_status": "Rejected",
|
||||||
|
"expenses":
|
||||||
|
[{ "expense_type": "Travel", "default_account": "Travel Expenses - WP", "claim_amount": 300, "sanctioned_amount": 200 }]
|
||||||
|
})
|
||||||
|
expense_claim.submit()
|
||||||
|
|
||||||
|
self.assertEquals(expense_claim.status, 'Rejected')
|
||||||
|
self.assertEquals(expense_claim.total_sanctioned_amount, 0.0)
|
||||||
|
|
||||||
|
gl_entry = frappe.get_all('GL Entry', {'voucher_type': 'Expense Claim', 'voucher_no': expense_claim.name})
|
||||||
|
self.assertEquals(len(gl_entry), 0)
|
||||||
|
|
||||||
def get_payable_account(company):
|
def get_payable_account(company):
|
||||||
return frappe.db.get_value('Company', company, 'default_payable_account')
|
return frappe.db.get_value('Company', company, 'default_payable_account')
|
||||||
|
|||||||
@@ -69,27 +69,17 @@ def get_events(start, end, filters=None):
|
|||||||
:param end: End date-time.
|
:param end: End date-time.
|
||||||
:param filters: Filters (JSON).
|
:param filters: Filters (JSON).
|
||||||
"""
|
"""
|
||||||
condition = ''
|
|
||||||
values = {
|
|
||||||
"start_date": getdate(start),
|
|
||||||
"end_date": getdate(end)
|
|
||||||
}
|
|
||||||
|
|
||||||
if filters:
|
if filters:
|
||||||
if isinstance(filters, basestring):
|
filters = json.loads(filters)
|
||||||
filters = json.loads(filters)
|
else:
|
||||||
|
filters = []
|
||||||
|
|
||||||
if filters.get('holiday_list'):
|
if start:
|
||||||
condition = 'and hlist.name=%(holiday_list)s'
|
filters.append(['Holiday', 'holiday_date', '>', getdate(start)])
|
||||||
values['holiday_list'] = filters['holiday_list']
|
if end:
|
||||||
|
filters.append(['Holiday', 'holiday_date', '<', getdate(end)])
|
||||||
|
|
||||||
data = frappe.db.sql("""select hlist.name, h.holiday_date, h.description
|
return frappe.get_list('Holiday List',
|
||||||
from `tabHoliday List` hlist, tabHoliday h
|
fields=['name', '`tabHoliday`.holiday_date', '`tabHoliday`.description'],
|
||||||
where h.parent = hlist.name
|
filters = filters,
|
||||||
and h.holiday_date is not null
|
update={"allDay": 1})
|
||||||
and h.holiday_date >= %(start_date)s
|
|
||||||
and h.holiday_date <= %(end_date)s
|
|
||||||
{condition}""".format(condition=condition),
|
|
||||||
values, as_dict=True, update={"allDay": 1})
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|||||||
@@ -400,7 +400,7 @@ def is_lwp(leave_type):
|
|||||||
return lwp and cint(lwp[0][0]) or 0
|
return lwp and cint(lwp[0][0]) or 0
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_events(start, end):
|
def get_events(start, end, filters=None):
|
||||||
events = []
|
events = []
|
||||||
|
|
||||||
employee = frappe.db.get_value("Employee", {"user_id": frappe.session.user}, ["name", "company"],
|
employee = frappe.db.get_value("Employee", {"user_id": frappe.session.user}, ["name", "company"],
|
||||||
@@ -411,14 +411,14 @@ def get_events(start, end):
|
|||||||
employee=''
|
employee=''
|
||||||
company=frappe.db.get_value("Global Defaults", None, "default_company")
|
company=frappe.db.get_value("Global Defaults", None, "default_company")
|
||||||
|
|
||||||
from frappe.desk.reportview import build_match_conditions
|
from frappe.desk.reportview import get_filters_cond
|
||||||
match_conditions = build_match_conditions("Leave Application")
|
conditions = get_filters_cond("Leave Application", filters, [])
|
||||||
|
|
||||||
# show department leaves for employee
|
# show department leaves for employee
|
||||||
if "Employee" in frappe.get_roles():
|
if "Employee" in frappe.get_roles():
|
||||||
add_department_leaves(events, start, end, employee, company)
|
add_department_leaves(events, start, end, employee, company)
|
||||||
|
|
||||||
add_leaves(events, start, end, match_conditions)
|
add_leaves(events, start, end, conditions)
|
||||||
|
|
||||||
add_block_dates(events, start, end, employee, company)
|
add_block_dates(events, start, end, employee, company)
|
||||||
add_holidays(events, start, end, employee, company)
|
add_holidays(events, start, end, employee, company)
|
||||||
@@ -435,7 +435,7 @@ def add_department_leaves(events, start, end, employee, company):
|
|||||||
department_employees = frappe.db.sql_list("""select name from tabEmployee where department=%s
|
department_employees = frappe.db.sql_list("""select name from tabEmployee where department=%s
|
||||||
and company=%s""", (department, company))
|
and company=%s""", (department, company))
|
||||||
|
|
||||||
match_conditions = "employee in (\"%s\")" % '", "'.join(department_employees)
|
match_conditions = "and employee in (\"%s\")" % '", "'.join(department_employees)
|
||||||
add_leaves(events, start, end, match_conditions=match_conditions)
|
add_leaves(events, start, end, match_conditions=match_conditions)
|
||||||
|
|
||||||
def add_leaves(events, start, end, match_conditions=None):
|
def add_leaves(events, start, end, match_conditions=None):
|
||||||
@@ -446,7 +446,7 @@ def add_leaves(events, start, end, match_conditions=None):
|
|||||||
and docstatus < 2
|
and docstatus < 2
|
||||||
and status!="Rejected" """
|
and status!="Rejected" """
|
||||||
if match_conditions:
|
if match_conditions:
|
||||||
query += " and " + match_conditions
|
query += match_conditions
|
||||||
|
|
||||||
for d in frappe.db.sql(query, {"start":start, "end": end}, as_dict=True):
|
for d in frappe.db.sql(query, {"start":start, "end": end}, as_dict=True):
|
||||||
e = {
|
e = {
|
||||||
|
|||||||
@@ -365,9 +365,6 @@ class BOM(WebsiteGenerator):
|
|||||||
base_total_rm_cost = 0
|
base_total_rm_cost = 0
|
||||||
|
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if d.bom_no:
|
|
||||||
d.rate = self.get_bom_unitcost(d.bom_no)
|
|
||||||
|
|
||||||
d.base_rate = flt(d.rate) * flt(self.conversion_rate)
|
d.base_rate = flt(d.rate) * flt(self.conversion_rate)
|
||||||
d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.stock_qty, self.precision("stock_qty", d))
|
d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.stock_qty, self.precision("stock_qty", d))
|
||||||
d.base_amount = d.amount * flt(self.conversion_rate)
|
d.base_amount = d.amount * flt(self.conversion_rate)
|
||||||
|
|||||||
@@ -151,26 +151,28 @@ frappe.ui.form.on("Production Order", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
production_item: function(frm) {
|
production_item: function(frm) {
|
||||||
frappe.call({
|
if (frm.doc.production_item) {
|
||||||
method: "erpnext.manufacturing.doctype.production_order.production_order.get_item_details",
|
frappe.call({
|
||||||
args: {
|
method: "erpnext.manufacturing.doctype.production_order.production_order.get_item_details",
|
||||||
item: frm.doc.production_item,
|
args: {
|
||||||
project: frm.doc.project
|
item: frm.doc.production_item,
|
||||||
},
|
project: frm.doc.project
|
||||||
callback: function(r) {
|
},
|
||||||
if(r.message) {
|
callback: function(r) {
|
||||||
erpnext.in_production_item_onchange = true;
|
if(r.message) {
|
||||||
$.each(["description", "stock_uom", "project", "bom_no"], function(i, field) {
|
erpnext.in_production_item_onchange = true;
|
||||||
frm.set_value(field, r.message[field]);
|
$.each(["description", "stock_uom", "project", "bom_no"], function(i, field) {
|
||||||
});
|
frm.set_value(field, r.message[field]);
|
||||||
|
});
|
||||||
|
|
||||||
if(r.message["set_scrap_wh_mandatory"]){
|
if(r.message["set_scrap_wh_mandatory"]){
|
||||||
frm.toggle_reqd("scrap_warehouse", true);
|
frm.toggle_reqd("scrap_warehouse", true);
|
||||||
|
}
|
||||||
|
erpnext.in_production_item_onchange = false;
|
||||||
}
|
}
|
||||||
erpnext.in_production_item_onchange = false;
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
project: function(frm) {
|
project: function(frm) {
|
||||||
@@ -210,7 +212,9 @@ frappe.ui.form.on("Production Order", {
|
|||||||
frappe.ui.form.on("Production Order Item", {
|
frappe.ui.form.on("Production Order Item", {
|
||||||
source_warehouse: function(frm, cdt, cdn) {
|
source_warehouse: function(frm, cdt, cdn) {
|
||||||
var row = locals[cdt][cdn];
|
var row = locals[cdt][cdn];
|
||||||
if(row.source_warehouse) {
|
if(!row.item_code) {
|
||||||
|
frappe.throw(__("Please set the Item Code first"));
|
||||||
|
} else if(row.source_warehouse) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
"method": "erpnext.stock.utils.get_latest_stock_qty",
|
"method": "erpnext.stock.utils.get_latest_stock_qty",
|
||||||
args: {
|
args: {
|
||||||
@@ -272,7 +276,7 @@ erpnext.production_order = {
|
|||||||
erpnext.production_order.make_se(frm, 'Material Transfer for Manufacture');
|
erpnext.production_order.make_se(frm, 'Material Transfer for Manufacture');
|
||||||
});
|
});
|
||||||
start_btn.addClass('btn-primary');
|
start_btn.addClass('btn-primary');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!frm.doc.skip_transfer){
|
if(!frm.doc.skip_transfer){
|
||||||
@@ -291,8 +295,9 @@ erpnext.production_order = {
|
|||||||
} else {
|
} else {
|
||||||
if ((flt(doc.produced_qty) < flt(doc.qty)) && frm.doc.status != 'Stopped') {
|
if ((flt(doc.produced_qty) < flt(doc.qty)) && frm.doc.status != 'Stopped') {
|
||||||
frm.has_finish_btn = true;
|
frm.has_finish_btn = true;
|
||||||
var finish_btn = frm.add_custom_button(__('Finish'),
|
var finish_btn = frm.add_custom_button(__('Finish'), function() {
|
||||||
cur_frm.cscript['Update Finished Goods']);
|
erpnext.production_order.make_se(frm, 'Manufacture');
|
||||||
|
});
|
||||||
finish_btn.addClass('btn-primary');
|
finish_btn.addClass('btn-primary');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1358,7 +1358,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-06-13 14:29:00.457874",
|
"modified": "2017-07-10 14:29:00.457874",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Production Order",
|
"name": "Production Order",
|
||||||
|
|||||||
@@ -353,7 +353,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-05-15 17:37:20.212361",
|
"modified": "2017-07-10 17:37:20.212361",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Production Order Item",
|
"name": "Production Order Item",
|
||||||
|
|||||||
@@ -8,3 +8,6 @@ from frappe.model.document import Document
|
|||||||
|
|
||||||
class ProductionOrderItem(Document):
|
class ProductionOrderItem(Document):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def on_doctype_update():
|
||||||
|
frappe.db.add_index("Production Order Item", ["item_code", "source_warehouse"])
|
||||||
@@ -415,3 +415,11 @@ erpnext.patches.v8_1.gst_fixes #2017-07-06
|
|||||||
erpnext.patches.v8_0.update_production_orders
|
erpnext.patches.v8_0.update_production_orders
|
||||||
erpnext.patches.v8_1.remove_sales_invoice_from_returned_serial_no
|
erpnext.patches.v8_1.remove_sales_invoice_from_returned_serial_no
|
||||||
erpnext.patches.v8_1.allow_invoice_copy_to_edit_after_submit
|
erpnext.patches.v8_1.allow_invoice_copy_to_edit_after_submit
|
||||||
|
erpnext.patches.v8_1.add_hsn_sac_codes
|
||||||
|
erpnext.patches.v8_1.update_gst_state #17-07-2017
|
||||||
|
erpnext.patches.v8_1.removed_report_support_hours
|
||||||
|
erpnext.patches.v8_1.add_indexes_in_transaction_doctypes
|
||||||
|
erpnext.patches.v8_3.set_restrict_to_domain_for_module_def
|
||||||
|
erpnext.patches.v8_1.update_expense_claim_status
|
||||||
|
erpnext.patches.v8_3.update_company_total_sales
|
||||||
|
erpnext.patches.v8_5.fix_tax_breakup_for_non_invoice_docs
|
||||||
@@ -51,7 +51,7 @@ def check_is_warehouse_associated_with_company():
|
|||||||
def make_warehouse_nestedset(company=None):
|
def make_warehouse_nestedset(company=None):
|
||||||
validate_parent_account_for_warehouse(company)
|
validate_parent_account_for_warehouse(company)
|
||||||
stock_account_group = get_stock_account_group(company.name)
|
stock_account_group = get_stock_account_group(company.name)
|
||||||
enable_perpetual_inventory = cint(erpnext.is_perpetual_inventory_enabled(company)) or 0
|
enable_perpetual_inventory = cint(erpnext.is_perpetual_inventory_enabled(company.name)) or 0
|
||||||
if not stock_account_group and enable_perpetual_inventory:
|
if not stock_account_group and enable_perpetual_inventory:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import frappe, erpnext
|
|||||||
def execute():
|
def execute():
|
||||||
frappe.reload_doctype("Account")
|
frappe.reload_doctype("Account")
|
||||||
|
|
||||||
warehouses = frappe.db.sql_list("""select name, company from tabAccount
|
warehouses = frappe.db.sql("""select name, company from tabAccount
|
||||||
where account_type = 'Stock' and is_group = 0
|
where account_type = 'Stock' and is_group = 0
|
||||||
and (warehouse is null or warehouse = '')""", as_dict)
|
and (warehouse is null or warehouse = '')""", as_dict=1)
|
||||||
warehouses = [d.name for d in warehouses if erpnext.is_perpetual_inventory_enabled(d.company)]
|
warehouses = [d.name for d in warehouses if erpnext.is_perpetual_inventory_enabled(d.company)]
|
||||||
|
|
||||||
if len(warehouses) > 0:
|
if len(warehouses) > 0:
|
||||||
warehouses = set_warehouse_for_stock_account(warehouses)
|
warehouses = set_warehouse_for_stock_account(warehouses)
|
||||||
if not warehouses:
|
if not warehouses:
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ def execute():
|
|||||||
for dt in ("assessment", "course", "fees"):
|
for dt in ("assessment", "course", "fees"):
|
||||||
frappe.reload_doc("schools", "doctype", dt)
|
frappe.reload_doc("schools", "doctype", dt)
|
||||||
|
|
||||||
|
for dt in ("domain", "has_domain", "domain_settings"):
|
||||||
|
frappe.reload_doc("core", "doctype", dt)
|
||||||
|
|
||||||
frappe.reload_doc('website', 'doctype', 'portal_menu_item')
|
frappe.reload_doc('website', 'doctype', 'portal_menu_item')
|
||||||
|
|
||||||
frappe.get_doc('Portal Settings').sync_menu()
|
frappe.get_doc('Portal Settings').sync_menu()
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Copyright (c) 2017, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
# new field address_html is created in place of address field for the company's address in PR #8754 (without patch)
|
||||||
|
# so here is the patch for moving the address details in the address doc
|
||||||
|
company_list = []
|
||||||
|
if 'address' in frappe.db.get_table_columns('Company'):
|
||||||
|
company_list = frappe.db.sql('''select name, address from `tabCompany`
|
||||||
|
where address is not null and address != ""''', as_dict=1)
|
||||||
|
|
||||||
|
for company in company_list:
|
||||||
|
add_list = company.address.split(" ")
|
||||||
|
if ',' in company.address:
|
||||||
|
add_list = company.address.rpartition(',')
|
||||||
|
elif ' ' in company.address:
|
||||||
|
add_list = company.address.rpartition(' ')
|
||||||
|
else:
|
||||||
|
add_list = [company.address, None, company.address]
|
||||||
|
|
||||||
|
doc = frappe.get_doc({
|
||||||
|
"doctype":"Address",
|
||||||
|
"address_line1": add_list[0],
|
||||||
|
"city": add_list[2],
|
||||||
|
"links": [{
|
||||||
|
"link_doctype": "Company",
|
||||||
|
"link_name": company.name
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
doc.save()
|
||||||
@@ -9,8 +9,8 @@ from frappe.model.mapper import get_mapped_doc
|
|||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
# for converting student batch into student group
|
# for converting student batch into student group
|
||||||
for doctype in ["Student Group", "Student Group Student", "Student Group Instructor", "Student Attendance"]:
|
for doctype in ["Student Group", "Student Group Student", "Student Group Instructor", "Student Attendance", "Student"]:
|
||||||
frappe.reload_doc("schools", "doctype", doctype)
|
frappe.reload_doc("schools", "doctype", frappe.scrub(doctype))
|
||||||
|
|
||||||
if frappe.db.table_exists("Student Batch"):
|
if frappe.db.table_exists("Student Batch"):
|
||||||
student_batches = frappe.db.sql('''select name as student_group_name, student_batch_name as batch,
|
student_batches = frappe.db.sql('''select name as student_group_name, student_batch_name as batch,
|
||||||
|
|||||||
10
erpnext/patches/v8_1/add_hsn_sac_codes.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import frappe
|
||||||
|
from erpnext.regional.india.setup import setup
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||||
|
if not company:
|
||||||
|
return
|
||||||
|
|
||||||
|
# call setup for india
|
||||||
|
setup(patch=True)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
for dt in ("Sales Order Item", "Purchase Order Item",
|
||||||
|
"Material Request Item", "Production Order Item", "Packed Item"):
|
||||||
|
frappe.get_doc("DocType", dt).run_module_method("on_doctype_update")
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
inv_copy_options = "ORIGINAL FOR RECIPIENT\nDUPLICATE FOR TRANSPORTER\nDUPLICATE FOR SUPPLIER\nTRIPLICATE FOR SUPPLIER"
|
||||||
|
|
||||||
|
frappe.db.sql("""update `tabCustom Field` set allow_on_submit=1, options=%s
|
||||||
|
where fieldname='invoice_copy' and dt = 'Sales Invoice'
|
||||||
|
""", inv_copy_options)
|
||||||
|
|
||||||
|
frappe.db.sql("""update `tabCustom Field` set read_only=1
|
||||||
|
where fieldname='gst_state_number' and dt = 'Address'
|
||||||
|
""")
|
||||||
14
erpnext/patches/v8_1/removed_report_support_hours.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Copyright (c) 2017, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.db.sql(""" update `tabAuto Email Report` set report = %s
|
||||||
|
where name = %s""", ('Support Hour Distribution', 'Support Hours'))
|
||||||
|
|
||||||
|
frappe.db.sql(""" update `tabCustom Role` set report = %s
|
||||||
|
where report = %s""", ('Support Hour Distribution', 'Support Hours'))
|
||||||
|
|
||||||
|
frappe.delete_doc('Report', 'Support Hours')
|
||||||
@@ -5,6 +5,7 @@ def execute():
|
|||||||
frappe.reload_doc('regional', 'doctype', 'gst_settings')
|
frappe.reload_doc('regional', 'doctype', 'gst_settings')
|
||||||
frappe.reload_doc('regional', 'doctype', 'gst_hsn_code')
|
frappe.reload_doc('regional', 'doctype', 'gst_hsn_code')
|
||||||
frappe.reload_doc('stock', 'doctype', 'item')
|
frappe.reload_doc('stock', 'doctype', 'item')
|
||||||
|
frappe.reload_doc("stock", "doctype", "customs_tariff_number")
|
||||||
|
|
||||||
for report_name in ('GST Sales Register', 'GST Purchase Register',
|
for report_name in ('GST Sales Register', 'GST Purchase Register',
|
||||||
'GST Itemised Sales Register', 'GST Itemised Purchase Register'):
|
'GST Itemised Sales Register', 'GST Itemised Purchase Register'):
|
||||||
|
|||||||
23
erpnext/patches/v8_1/update_expense_claim_status.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Copyright (c) 2017, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doctype('Expense Claim')
|
||||||
|
|
||||||
|
for data in frappe.db.sql(""" select name from `tabExpense Claim`
|
||||||
|
where (docstatus=1 and total_sanctioned_amount=0 and status = 'Paid') or
|
||||||
|
(docstatus = 1 and approval_status = 'Rejected' and total_sanctioned_amount > 0)""", as_dict=1):
|
||||||
|
doc = frappe.get_doc('Expense Claim', data.name)
|
||||||
|
if doc.approval_status == 'Rejected':
|
||||||
|
for d in doc.expenses:
|
||||||
|
d.db_set("sanctioned_amount", 0, update_modified = False)
|
||||||
|
doc.db_set("total_sanctioned_amount", 0, update_modified = False)
|
||||||
|
|
||||||
|
frappe.db.sql(""" delete from `tabGL Entry` where voucher_type = 'Expense Claim'
|
||||||
|
and voucher_no = %s""", (doc.name))
|
||||||
|
|
||||||
|
doc.set_status()
|
||||||
|
doc.db_set("status", doc.status, update_modified = False)
|
||||||
14
erpnext/patches/v8_1/update_gst_state.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import frappe
|
||||||
|
from erpnext.regional.india import states
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||||
|
if not company:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not frappe.db.get_value("Custom Field", filters={'fieldname':'gst_state'}):
|
||||||
|
return
|
||||||
|
|
||||||
|
frappe.db.sql("update `tabCustom Field` set options=%s where fieldname='gst_state'", '\n'.join(states))
|
||||||
|
frappe.db.sql("update `tabAddress` set gst_state='Chhattisgarh' where gst_state='Chattisgarh'")
|
||||||
|
frappe.db.sql("update `tabAddress` set gst_state_number='05' where gst_state='Uttarakhand'")
|
||||||
0
erpnext/patches/v8_3/__init__.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Copyright (c) 2017, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
from erpnext.setup.setup_wizard.domainify import update_module_def_restrict_to_domain
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
""" set the restrict to domain in module def """
|
||||||
|
|
||||||
|
frappe.reload_doc("core", "doctype", "module_def")
|
||||||
|
if frappe.db.get_single_value('System Settings', 'setup_complete'):
|
||||||
|
update_module_def_restrict_to_domain()
|
||||||
15
erpnext/patches/v8_3/update_company_total_sales.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Copyright (c) 2017, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from erpnext.setup.doctype.company.company import update_company_current_month_sales, update_company_monthly_sales
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
'''Update company monthly sales history based on sales invoices'''
|
||||||
|
frappe.reload_doctype("Company")
|
||||||
|
companies = [d['name'] for d in frappe.get_list("Company")]
|
||||||
|
|
||||||
|
for company in companies:
|
||||||
|
update_company_current_month_sales(company)
|
||||||
|
update_company_monthly_sales(company)
|
||||||
0
erpnext/patches/v8_5/__init__.py
Normal file
47
erpnext/patches/v8_5/fix_tax_breakup_for_non_invoice_docs.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import frappe
|
||||||
|
from erpnext.regional.india.setup import make_custom_fields
|
||||||
|
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_html
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
companies = [d.name for d in frappe.get_all('Company', filters = {'country': 'India'})]
|
||||||
|
if not companies:
|
||||||
|
return
|
||||||
|
|
||||||
|
make_custom_fields()
|
||||||
|
|
||||||
|
# update invoice copy value
|
||||||
|
values = ["Original for Recipient", "Duplicate for Transporter",
|
||||||
|
"Duplicate for Supplier", "Triplicate for Supplier"]
|
||||||
|
for d in values:
|
||||||
|
frappe.db.sql("update `tabSales Invoice` set invoice_copy=%s where invoice_copy=%s", (d, d))
|
||||||
|
|
||||||
|
# update tax breakup in transactions made after 1st July 2017
|
||||||
|
doctypes = ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice",
|
||||||
|
"Supplier Quotation", "Purchase Order", "Purchase Receipt", "Purchase Invoice"]
|
||||||
|
|
||||||
|
for doctype in doctypes:
|
||||||
|
frappe.reload_doctype(doctype)
|
||||||
|
|
||||||
|
date_field = "posting_date"
|
||||||
|
if doctype in ["Quotation", "Sales Order", "Supplier Quotation", "Purchase Order"]:
|
||||||
|
date_field = "transaction_date"
|
||||||
|
|
||||||
|
records = [d.name for d in frappe.get_all(doctype, filters={
|
||||||
|
"docstatus": ["!=", 2],
|
||||||
|
date_field: [">=", "2017-07-01"],
|
||||||
|
"company": ["in", companies],
|
||||||
|
"total_taxes_and_charges": [">", 0],
|
||||||
|
"other_charges_calculation": ""
|
||||||
|
})]
|
||||||
|
if records:
|
||||||
|
frappe.db.sql("""
|
||||||
|
update `tab%s Item` dt_item
|
||||||
|
set gst_hsn_code = (select gst_hsn_code from tabItem where name=dt_item.item_code)
|
||||||
|
where parent in (%s)
|
||||||
|
and (gst_hsn_code is null or gst_hsn_code = '')
|
||||||
|
""" % (doctype, ', '.join(['%s']*len(records))), tuple(records))
|
||||||
|
|
||||||
|
for record in records:
|
||||||
|
doc = frappe.get_doc(doctype, record)
|
||||||
|
html = get_itemised_tax_breakup_html(doc)
|
||||||
|
doc.db_set("other_charges_calculation", html, update_modified=False)
|
||||||
@@ -9,9 +9,8 @@ from frappe import _
|
|||||||
import json
|
import json
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from erpnext.controllers.queries import get_match_cond
|
from erpnext.controllers.queries import get_match_cond
|
||||||
from frappe.utils import flt, time_diff_in_hours, get_datetime, getdate, cint, get_datetime_str
|
from frappe.utils import flt, time_diff_in_hours, get_datetime, getdate, cint
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.model.mapper import get_mapped_doc
|
|
||||||
from erpnext.manufacturing.doctype.workstation.workstation import (check_if_within_operating_hours,
|
from erpnext.manufacturing.doctype.workstation.workstation import (check_if_within_operating_hours,
|
||||||
WorkstationHolidayError)
|
WorkstationHolidayError)
|
||||||
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
|
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
|
||||||
@@ -364,8 +363,9 @@ def get_events(start, end, filters=None):
|
|||||||
:param filters: Filters (JSON).
|
:param filters: Filters (JSON).
|
||||||
"""
|
"""
|
||||||
filters = json.loads(filters)
|
filters = json.loads(filters)
|
||||||
|
from frappe.desk.calendar import get_event_conditions
|
||||||
|
conditions = get_event_conditions("Timesheet", filters)
|
||||||
|
|
||||||
conditions = get_conditions(filters)
|
|
||||||
return frappe.db.sql("""select `tabTimesheet Detail`.name as name,
|
return frappe.db.sql("""select `tabTimesheet Detail`.name as name,
|
||||||
`tabTimesheet Detail`.docstatus as status, `tabTimesheet Detail`.parent as parent,
|
`tabTimesheet Detail`.docstatus as status, `tabTimesheet Detail`.parent as parent,
|
||||||
from_time as start_date, hours, activity_type,
|
from_time as start_date, hours, activity_type,
|
||||||
@@ -381,15 +381,3 @@ def get_events(start, end, filters=None):
|
|||||||
"end": end
|
"end": end
|
||||||
}, as_dict=True, update={"allDay": 0})
|
}, as_dict=True, update={"allDay": 0})
|
||||||
|
|
||||||
def get_conditions(filters):
|
|
||||||
conditions = []
|
|
||||||
for key in filters:
|
|
||||||
if filters.get(key):
|
|
||||||
if frappe.get_meta("Timesheet").has_field(key):
|
|
||||||
dt = 'tabTimesheet'
|
|
||||||
elif frappe.get_meta("Timesheet Detail").has_field(key):
|
|
||||||
dt = 'tabTimesheet Detail'
|
|
||||||
|
|
||||||
conditions.append("`%s`.%s = '%s'"%(dt, key, filters.get(key)))
|
|
||||||
|
|
||||||
return " and {}".format(" and ".join(conditions)) if conditions else ""
|
|
||||||
|
|||||||
@@ -89,7 +89,15 @@ frappe.ui.form.on('Salary Structure', {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
var get_payment_mode_account = function(frm, mode_of_payment, callback){
|
var get_payment_mode_account = function(frm, mode_of_payment, callback) {
|
||||||
|
if(!frm.doc.company) {
|
||||||
|
frappe.throw(__("Please select the Company first"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mode_of_payment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return frappe.call({
|
return frappe.call({
|
||||||
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.get_bank_cash_account",
|
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.get_bank_cash_account",
|
||||||
args: {
|
args: {
|
||||||
|
|||||||
@@ -228,6 +228,8 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
|||||||
items: my_items
|
items: my_items
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
|
if(r.exc) return;
|
||||||
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
var item_length = cur_frm.doc.items.length;
|
var item_length = cur_frm.doc.items.length;
|
||||||
while (i < item_length) {
|
while (i < item_length) {
|
||||||
@@ -244,35 +246,26 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
|||||||
cur_frm.doc.items[i].qty = my_qty;
|
cur_frm.doc.items[i].qty = my_qty;
|
||||||
|
|
||||||
frappe.msgprint("Assigning " + d.mr_name + " to " + d.item_code + " (row " + cur_frm.doc.items[i].idx + ")");
|
frappe.msgprint("Assigning " + d.mr_name + " to " + d.item_code + " (row " + cur_frm.doc.items[i].idx + ")");
|
||||||
if (qty > 0)
|
if (qty > 0) {
|
||||||
{
|
|
||||||
frappe.msgprint("Splitting " + qty + " units of " + d.item_code);
|
frappe.msgprint("Splitting " + qty + " units of " + d.item_code);
|
||||||
var newrow = frappe.model.add_child(cur_frm.doc, cur_frm.doc.items[i].doctype, "items");
|
var newrow = frappe.model.add_child(cur_frm.doc, cur_frm.doc.items[i].doctype, "items");
|
||||||
item_length++;
|
item_length++;
|
||||||
|
|
||||||
for (var key in cur_frm.doc.items[i])
|
for (var key in cur_frm.doc.items[i]) {
|
||||||
{
|
|
||||||
newrow[key] = cur_frm.doc.items[i][key];
|
newrow[key] = cur_frm.doc.items[i][key];
|
||||||
}
|
}
|
||||||
|
|
||||||
newrow.idx = item_length;
|
newrow.idx = item_length;
|
||||||
newrow["stock_qty"] = newrow.conversion_factor*qty;
|
newrow["stock_qty"] = newrow.conversion_factor*qty;
|
||||||
newrow["qty"] = qty;
|
newrow["qty"] = qty;
|
||||||
|
|
||||||
newrow["material_request"] = "";
|
newrow["material_request"] = "";
|
||||||
newrow["material_request_item"] = "";
|
newrow["material_request_item"] = "";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
refresh_field("items");
|
refresh_field("items");
|
||||||
//cur_frm.save();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
|||||||
this.manipulate_grand_total_for_inclusive_tax();
|
this.manipulate_grand_total_for_inclusive_tax();
|
||||||
this.calculate_totals();
|
this.calculate_totals();
|
||||||
this._cleanup();
|
this._cleanup();
|
||||||
this.show_item_wise_taxes();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
validate_conversion_rate: function() {
|
validate_conversion_rate: function() {
|
||||||
@@ -634,92 +633,5 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.calculate_outstanding_amount(false)
|
this.calculate_outstanding_amount(false)
|
||||||
},
|
|
||||||
|
|
||||||
show_item_wise_taxes: function() {
|
|
||||||
if(this.frm.fields_dict.other_charges_calculation) {
|
|
||||||
this.frm.toggle_display("other_charges_calculation", this.frm.doc.other_charges_calculation);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
set_item_wise_tax_breakup: function() {
|
|
||||||
if(this.frm.fields_dict.other_charges_calculation) {
|
|
||||||
var html = this.get_item_wise_taxes_html();
|
|
||||||
// console.log(html);
|
|
||||||
this.frm.set_value("other_charges_calculation", html);
|
|
||||||
this.show_item_wise_taxes();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
get_item_wise_taxes_html: function() {
|
|
||||||
var item_tax = {};
|
|
||||||
var tax_accounts = [];
|
|
||||||
var company_currency = this.get_company_currency();
|
|
||||||
|
|
||||||
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
|
|
||||||
var tax_amount_precision = precision("tax_amount", tax);
|
|
||||||
var tax_rate_precision = precision("rate", tax);
|
|
||||||
$.each(JSON.parse(tax.item_wise_tax_detail || '{}'),
|
|
||||||
function(item_code, tax_data) {
|
|
||||||
if(!item_tax[item_code]) item_tax[item_code] = {};
|
|
||||||
if($.isArray(tax_data)) {
|
|
||||||
var tax_rate = "";
|
|
||||||
if(tax_data[0] != null) {
|
|
||||||
tax_rate = (tax.charge_type === "Actual") ?
|
|
||||||
format_currency(flt(tax_data[0], tax_amount_precision),
|
|
||||||
company_currency, tax_amount_precision) :
|
|
||||||
(flt(tax_data[0], tax_rate_precision) + "%");
|
|
||||||
}
|
|
||||||
var tax_amount = format_currency(flt(tax_data[1], tax_amount_precision),
|
|
||||||
company_currency, tax_amount_precision);
|
|
||||||
|
|
||||||
item_tax[item_code][tax.name] = [tax_rate, tax_amount];
|
|
||||||
} else {
|
|
||||||
item_tax[item_code][tax.name] = [flt(tax_data, tax_rate_precision) + "%", ""];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tax_accounts.push([tax.name, tax.account_head]);
|
|
||||||
});
|
|
||||||
|
|
||||||
var headings = $.map([__("Item Name"), __("Taxable Amount")].concat($.map(tax_accounts,
|
|
||||||
function(head) { return head[1]; })), function(head) {
|
|
||||||
if(head==__("Item Name")) {
|
|
||||||
return '<th style="min-width: 100px;" class="text-left">' + (head || "") + "</th>";
|
|
||||||
} else {
|
|
||||||
return '<th style="min-width: 80px;" class="text-right">' + (head || "") + "</th>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).join("");
|
|
||||||
|
|
||||||
var distinct_item_names = [];
|
|
||||||
var distinct_items = [];
|
|
||||||
$.each(this.frm.doc["items"] || [], function(i, item) {
|
|
||||||
if(distinct_item_names.indexOf(item.item_code || item.item_name)===-1) {
|
|
||||||
distinct_item_names.push(item.item_code || item.item_name);
|
|
||||||
distinct_items.push(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var rows = $.map(distinct_items, function(item) {
|
|
||||||
var item_tax_record = item_tax[item.item_code || item.item_name];
|
|
||||||
if(!item_tax_record) { return null; }
|
|
||||||
return repl("<tr><td>%(item_name)s</td><td class='text-right'>%(taxable_amount)s</td>%(taxes)s</tr>", {
|
|
||||||
item_name: item.item_name,
|
|
||||||
taxable_amount: format_currency(item.net_amount,
|
|
||||||
company_currency, precision("net_amount", item)),
|
|
||||||
taxes: $.map(tax_accounts, function(head) {
|
|
||||||
return item_tax_record[head[0]] ?
|
|
||||||
"<td class='text-right'>(" + item_tax_record[head[0]][0] + ") " + item_tax_record[head[0]][1] + "</td>" :
|
|
||||||
"<td></td>";
|
|
||||||
}).join("")
|
|
||||||
});
|
|
||||||
}).join("");
|
|
||||||
|
|
||||||
if(!rows) return "";
|
|
||||||
return '<div class="tax-break-up" style="overflow-x: auto;">\
|
|
||||||
<table class="table table-bordered table-hover">\
|
|
||||||
<thead><tr>' + headings + '</tr></thead> \
|
|
||||||
<tbody>' + rows + '</tbody> \
|
|
||||||
</table></div>';
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -210,7 +210,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
refresh: function() {
|
refresh: function() {
|
||||||
erpnext.toggle_naming_series();
|
erpnext.toggle_naming_series();
|
||||||
erpnext.hide_company();
|
erpnext.hide_company();
|
||||||
this.show_item_wise_taxes();
|
|
||||||
this.set_dynamic_labels();
|
this.set_dynamic_labels();
|
||||||
this.setup_sms();
|
this.setup_sms();
|
||||||
},
|
},
|
||||||
@@ -338,7 +337,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
this.frm.trigger("item_code", cdt, cdn);
|
this.frm.trigger("item_code", cdt, cdn);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var sr_no = [];
|
var valid_serial_nos = [];
|
||||||
|
|
||||||
// Replacing all occurences of comma with carriage return
|
// Replacing all occurences of comma with carriage return
|
||||||
var serial_nos = item.serial_no.trim().replace(/,/g, '\n');
|
var serial_nos = item.serial_no.trim().replace(/,/g, '\n');
|
||||||
@@ -347,21 +346,19 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
// Trim each string and push unique string to new list
|
// Trim each string and push unique string to new list
|
||||||
for (var x=0; x<=serial_nos.length - 1; x++) {
|
for (var x=0; x<=serial_nos.length - 1; x++) {
|
||||||
if (serial_nos[x].trim() != "" && sr_no.indexOf(serial_nos[x].trim()) == -1) {
|
if (serial_nos[x].trim() != "" && valid_serial_nos.indexOf(serial_nos[x].trim()) == -1) {
|
||||||
sr_no.push(serial_nos[x].trim());
|
valid_serial_nos.push(serial_nos[x].trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the new list to the serial no. field in grid with each in new line
|
// Add the new list to the serial no. field in grid with each in new line
|
||||||
item.serial_no = "";
|
item.serial_no = valid_serial_nos.join('\n');
|
||||||
for (var x=0; x<=sr_no.length - 1; x++)
|
|
||||||
item.serial_no += sr_no[x] + '\n';
|
|
||||||
|
|
||||||
refresh_field("serial_no", item.name, item.parentfield);
|
refresh_field("serial_no", item.name, item.parentfield);
|
||||||
if(!doc.is_return) {
|
if(!doc.is_return) {
|
||||||
frappe.model.set_value(item.doctype, item.name,
|
frappe.model.set_value(item.doctype, item.name,
|
||||||
"qty", sr_no.length / item.conversion_factor);
|
"qty", valid_serial_nos.length / item.conversion_factor);
|
||||||
frappe.model.set_value(item.doctype, item.name, "stock_qty", sr_no.length);
|
frappe.model.set_value(item.doctype, item.name, "stock_qty", valid_serial_nos.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,7 +366,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
validate: function() {
|
validate: function() {
|
||||||
this.calculate_taxes_and_totals(false);
|
this.calculate_taxes_and_totals(false);
|
||||||
this.set_item_wise_tax_breakup();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
company: function() {
|
company: function() {
|
||||||
@@ -861,6 +857,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
"pricing_rule": d.pricing_rule,
|
"pricing_rule": d.pricing_rule,
|
||||||
"warehouse": d.warehouse,
|
"warehouse": d.warehouse,
|
||||||
"serial_no": d.serial_no,
|
"serial_no": d.serial_no,
|
||||||
|
"discount_percentage": d.discount_percentage || 0.0,
|
||||||
"conversion_factor": d.conversion_factor || 1.0
|
"conversion_factor": d.conversion_factor || 1.0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -68,13 +68,13 @@ var erpnext_slides = [
|
|||||||
slide.get_input("company_name").on("change", function () {
|
slide.get_input("company_name").on("change", function () {
|
||||||
var parts = slide.get_input("company_name").val().split(" ");
|
var parts = slide.get_input("company_name").val().split(" ");
|
||||||
var abbr = $.map(parts, function (p) { return p ? p.substr(0, 1) : null }).join("");
|
var abbr = $.map(parts, function (p) { return p ? p.substr(0, 1) : null }).join("");
|
||||||
slide.get_field("company_abbr").set_input(abbr.slice(0, 5).toUpperCase());
|
slide.get_field("company_abbr").set_value(abbr.slice(0, 5).toUpperCase());
|
||||||
}).val(frappe.boot.sysdefaults.company_name || "").trigger("change");
|
}).val(frappe.boot.sysdefaults.company_name || "").trigger("change");
|
||||||
|
|
||||||
slide.get_input("company_abbr").on("change", function () {
|
slide.get_input("company_abbr").on("change", function () {
|
||||||
if (slide.get_input("company_abbr").val().length > 5) {
|
if (slide.get_input("company_abbr").val().length > 5) {
|
||||||
frappe.msgprint("Company Abbreviation cannot have more than 5 characters");
|
frappe.msgprint("Company Abbreviation cannot have more than 5 characters");
|
||||||
slide.get_field("company_abbr").set_input("");
|
slide.get_field("company_abbr").set_value("");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ var erpnext_slides = [
|
|||||||
options: "", fieldtype: 'Select'
|
options: "", fieldtype: 'Select'
|
||||||
},
|
},
|
||||||
|
|
||||||
{ fieldtype: "Section Break", label: "Financial Year" },
|
{ fieldtype: "Section Break", label: __('Financial Year') },
|
||||||
{ fieldname: 'fy_start_date', label: __('Start Date'), fieldtype: 'Date', reqd: 1 },
|
{ fieldname: 'fy_start_date', label: __('Start Date'), fieldtype: 'Date', reqd: 1 },
|
||||||
{ fieldtype: "Column Break" },
|
{ fieldtype: "Column Break" },
|
||||||
{ fieldname: 'fy_end_date', label: __('End Date'), fieldtype: 'Date', reqd: 1 },
|
{ fieldname: 'fy_end_date', label: __('End Date'), fieldtype: 'Date', reqd: 1 },
|
||||||
@@ -189,6 +189,43 @@ var erpnext_slides = [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// Users
|
||||||
|
name: 'users',
|
||||||
|
domains: ["all"],
|
||||||
|
title: __("Add Users"),
|
||||||
|
help: __("Add users to your organization, other than yourself"),
|
||||||
|
add_more: 1,
|
||||||
|
max_count: 3,
|
||||||
|
fields: [
|
||||||
|
{fieldtype:"Section Break"},
|
||||||
|
{fieldtype:"Data", fieldname:"user_fullname",
|
||||||
|
label:__("Full Name"), static: 1},
|
||||||
|
{fieldtype:"Data", fieldname:"user_email", label:__("Email ID"),
|
||||||
|
placeholder:__("user@example.com"), options: "Email", static: 1},
|
||||||
|
{fieldtype:"Column Break"},
|
||||||
|
{fieldtype: "Check", fieldname: "user_sales",
|
||||||
|
label:__("Sales"), "default": 1, static: 1,
|
||||||
|
hidden: frappe.setup.domain==='Education' ? 1 : 0},
|
||||||
|
{fieldtype: "Check", fieldname: "user_purchaser",
|
||||||
|
label:__("Purchaser"), "default": 1, static: 1,
|
||||||
|
hidden: frappe.setup.domain==='Education' ? 1 : 0},
|
||||||
|
{fieldtype: "Check", fieldname: "user_accountant",
|
||||||
|
label:__("Accountant"), "default": 1, static: 1,
|
||||||
|
hidden: frappe.setup.domain==='Education' ? 1 : 0},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// Sales Target
|
||||||
|
name: 'Goals',
|
||||||
|
domains: ['manufacturing', 'services', 'retail', 'distribution'],
|
||||||
|
title: __("Set your Target"),
|
||||||
|
help: __("Set a sales target you'd like to achieve."),
|
||||||
|
fields: [
|
||||||
|
{fieldtype:"Currency", fieldname:"sales_target", label:__("Monthly Sales Target")},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
// Taxes
|
// Taxes
|
||||||
@@ -198,7 +235,8 @@ var erpnext_slides = [
|
|||||||
title: __("Add Taxes"),
|
title: __("Add Taxes"),
|
||||||
help: __("List your tax heads (e.g. VAT, Customs etc; they should have unique names) and their standard rates. This will create a standard template, which you can edit and add more later."),
|
help: __("List your tax heads (e.g. VAT, Customs etc; they should have unique names) and their standard rates. This will create a standard template, which you can edit and add more later."),
|
||||||
add_more: 1,
|
add_more: 1,
|
||||||
max_count: 4,
|
max_count: 3,
|
||||||
|
mandatory_entry: 0,
|
||||||
fields: [
|
fields: [
|
||||||
{fieldtype:"Section Break"},
|
{fieldtype:"Section Break"},
|
||||||
{fieldtype:"Data", fieldname:"tax", label:__("Tax"),
|
{fieldtype:"Data", fieldname:"tax", label:__("Tax"),
|
||||||
@@ -216,7 +254,8 @@ var erpnext_slides = [
|
|||||||
title: __("Add Customers"),
|
title: __("Add Customers"),
|
||||||
help: __("List a few of your customers. They could be organizations or individuals."),
|
help: __("List a few of your customers. They could be organizations or individuals."),
|
||||||
add_more: 1,
|
add_more: 1,
|
||||||
max_count: 6,
|
max_count: 5,
|
||||||
|
mandatory_entry: 1,
|
||||||
fields: [
|
fields: [
|
||||||
{fieldtype:"Section Break"},
|
{fieldtype:"Section Break"},
|
||||||
{fieldtype:"Data", fieldname:"customer", label:__("Customer"),
|
{fieldtype:"Data", fieldname:"customer", label:__("Customer"),
|
||||||
@@ -235,7 +274,8 @@ var erpnext_slides = [
|
|||||||
title: __("Your Suppliers"),
|
title: __("Your Suppliers"),
|
||||||
help: __("List a few of your suppliers. They could be organizations or individuals."),
|
help: __("List a few of your suppliers. They could be organizations or individuals."),
|
||||||
add_more: 1,
|
add_more: 1,
|
||||||
max_count: 6,
|
max_count: 5,
|
||||||
|
mandatory_entry: 1,
|
||||||
fields: [
|
fields: [
|
||||||
{fieldtype:"Section Break"},
|
{fieldtype:"Section Break"},
|
||||||
{fieldtype:"Data", fieldname:"supplier", label:__("Supplier"),
|
{fieldtype:"Data", fieldname:"supplier", label:__("Supplier"),
|
||||||
@@ -254,7 +294,8 @@ var erpnext_slides = [
|
|||||||
title: __("Your Products or Services"),
|
title: __("Your Products or Services"),
|
||||||
help: __("List your products or services that you buy or sell. Make sure to check the Item Group, Unit of Measure and other properties when you start."),
|
help: __("List your products or services that you buy or sell. Make sure to check the Item Group, Unit of Measure and other properties when you start."),
|
||||||
add_more: 1,
|
add_more: 1,
|
||||||
max_count: 6,
|
max_count: 5,
|
||||||
|
mandatory_entry: 1,
|
||||||
fields: [
|
fields: [
|
||||||
{fieldtype:"Section Break", show_section_border: true},
|
{fieldtype:"Section Break", show_section_border: true},
|
||||||
{fieldtype:"Data", fieldname:"item", label:__("Item"),
|
{fieldtype:"Data", fieldname:"item", label:__("Item"),
|
||||||
@@ -262,16 +303,18 @@ var erpnext_slides = [
|
|||||||
{fieldtype:"Select", label:__("Group"), fieldname:"item_group",
|
{fieldtype:"Select", label:__("Group"), fieldname:"item_group",
|
||||||
options:[__("Products"), __("Services"),
|
options:[__("Products"), __("Services"),
|
||||||
__("Raw Material"), __("Consumable"), __("Sub Assemblies")],
|
__("Raw Material"), __("Consumable"), __("Sub Assemblies")],
|
||||||
"default": __("Products")},
|
"default": __("Products"), static: 1},
|
||||||
{fieldtype:"Select", fieldname:"item_uom", label:__("UOM"),
|
{fieldtype:"Select", fieldname:"item_uom", label:__("UOM"),
|
||||||
options:[__("Unit"), __("Nos"), __("Box"), __("Pair"), __("Kg"), __("Set"),
|
options:[__("Unit"), __("Nos"), __("Box"), __("Pair"), __("Kg"), __("Set"),
|
||||||
__("Hour"), __("Minute"), __("Litre"), __("Meter"), __("Gram")],
|
__("Hour"), __("Minute"), __("Litre"), __("Meter"), __("Gram")],
|
||||||
"default": __("Unit")},
|
"default": __("Unit"), static: 1},
|
||||||
{fieldtype: "Check", fieldname: "is_sales_item", label:__("We sell this Item"), default: 1},
|
{fieldtype: "Check", fieldname: "is_sales_item",
|
||||||
{fieldtype: "Check", fieldname: "is_purchase_item", label:__("We buy this Item")},
|
label:__("We sell this Item"), default: 1, static: 1},
|
||||||
|
{fieldtype: "Check", fieldname: "is_purchase_item",
|
||||||
|
label:__("We buy this Item"), default: 1, static: 1},
|
||||||
{fieldtype:"Column Break"},
|
{fieldtype:"Column Break"},
|
||||||
{fieldtype:"Currency", fieldname:"item_price", label:__("Rate")},
|
{fieldtype:"Currency", fieldname:"item_price", label:__("Rate"), static: 1},
|
||||||
{fieldtype:"Attach Image", fieldname:"item_img", label:__("Attach Image"), is_private: 0},
|
{fieldtype:"Attach Image", fieldname:"item_img", label:__("Attach Image"), is_private: 0, static: 1},
|
||||||
],
|
],
|
||||||
get_item_count: function() {
|
get_item_count: function() {
|
||||||
return this.item_count;
|
return this.item_count;
|
||||||
@@ -285,7 +328,8 @@ var erpnext_slides = [
|
|||||||
title: __("Program"),
|
title: __("Program"),
|
||||||
help: __("Example: Masters in Computer Science"),
|
help: __("Example: Masters in Computer Science"),
|
||||||
add_more: 1,
|
add_more: 1,
|
||||||
max_count: 6,
|
max_count: 5,
|
||||||
|
mandatory_entry: 1,
|
||||||
fields: [
|
fields: [
|
||||||
{fieldtype:"Section Break", show_section_border: true},
|
{fieldtype:"Section Break", show_section_border: true},
|
||||||
{fieldtype:"Data", fieldname:"program", label:__("Program"), placeholder: __("Program Name")},
|
{fieldtype:"Data", fieldname:"program", label:__("Program"), placeholder: __("Program Name")},
|
||||||
@@ -299,7 +343,8 @@ var erpnext_slides = [
|
|||||||
title: __("Course"),
|
title: __("Course"),
|
||||||
help: __("Example: Basic Mathematics"),
|
help: __("Example: Basic Mathematics"),
|
||||||
add_more: 1,
|
add_more: 1,
|
||||||
max_count: 6,
|
max_count: 5,
|
||||||
|
mandatory_entry: 1,
|
||||||
fields: [
|
fields: [
|
||||||
{fieldtype:"Section Break", show_section_border: true},
|
{fieldtype:"Section Break", show_section_border: true},
|
||||||
{fieldtype:"Data", fieldname:"course", label:__("Course"), placeholder: __("Course Name")},
|
{fieldtype:"Data", fieldname:"course", label:__("Course"), placeholder: __("Course Name")},
|
||||||
@@ -313,7 +358,8 @@ var erpnext_slides = [
|
|||||||
title: __("Instructor"),
|
title: __("Instructor"),
|
||||||
help: __("People who teach at your organisation"),
|
help: __("People who teach at your organisation"),
|
||||||
add_more: 1,
|
add_more: 1,
|
||||||
max_count: 6,
|
max_count: 5,
|
||||||
|
mandatory_entry: 1,
|
||||||
fields: [
|
fields: [
|
||||||
{fieldtype:"Section Break", show_section_border: true},
|
{fieldtype:"Section Break", show_section_border: true},
|
||||||
{fieldtype:"Data", fieldname:"instructor", label:__("Instructor"), placeholder: __("Instructor Name")},
|
{fieldtype:"Data", fieldname:"instructor", label:__("Instructor"), placeholder: __("Instructor Name")},
|
||||||
@@ -327,20 +373,21 @@ var erpnext_slides = [
|
|||||||
title: __("Room"),
|
title: __("Room"),
|
||||||
help: __("Classrooms/ Laboratories etc where lectures can be scheduled."),
|
help: __("Classrooms/ Laboratories etc where lectures can be scheduled."),
|
||||||
add_more: 1,
|
add_more: 1,
|
||||||
max_count: 4,
|
max_count: 3,
|
||||||
|
mandatory_entry: 1,
|
||||||
fields: [
|
fields: [
|
||||||
{fieldtype:"Section Break", show_section_border: true},
|
{fieldtype:"Section Break", show_section_border: true},
|
||||||
{fieldtype:"Data", fieldname:"room", label:__("Room")},
|
{fieldtype:"Data", fieldname:"room", label:__("Room")},
|
||||||
{fieldtype:"Column Break"},
|
{fieldtype:"Column Break"},
|
||||||
{fieldtype:"Int", fieldname:"room_capacity", label:__("Room") + " Capacity"},
|
{fieldtype:"Int", fieldname:"room_capacity", label:__("Room") + " Capacity", static: 1},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
// last slide: Bootstrap
|
// last slide: Sample Data
|
||||||
name: 'bootstrap',
|
name: 'bootstrap',
|
||||||
domains: ["all"],
|
domains: ["all"],
|
||||||
title: __("Bootstrap"),
|
title: __("Sample Data"),
|
||||||
fields: [{fieldtype: "Section Break"},
|
fields: [{fieldtype: "Section Break"},
|
||||||
{fieldtype: "Check", fieldname: "add_sample_data",
|
{fieldtype: "Check", fieldname: "add_sample_data",
|
||||||
label: __("Add a few sample records"), "default": 1},
|
label: __("Add a few sample records"), "default": 1},
|
||||||
|
|||||||
@@ -42,11 +42,15 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) {
|
|||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if(r.message) {
|
if(r.message) {
|
||||||
frm.updating_party_details = true;
|
frm.updating_party_details = true;
|
||||||
frm.set_value(r.message);
|
frappe.run_serially([
|
||||||
frm.updating_party_details = false;
|
() => frm.set_value(r.message),
|
||||||
if(callback) callback();
|
() => {
|
||||||
frm.refresh();
|
frm.updating_party_details = false;
|
||||||
erpnext.utils.add_item(frm);
|
if(callback) callback();
|
||||||
|
frm.refresh();
|
||||||
|
erpnext.utils.add_item(frm);
|
||||||
|
}
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -50,6 +50,14 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
|||||||
batches.grid.refresh();
|
batches.grid.refresh();
|
||||||
batches.grid.add_new_row(null, null, null);
|
batches.grid.add_new_row(null, null, null);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
get_query: function() {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
is_group: 0,
|
||||||
|
company: me.frm.doc.company
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{fieldtype:'Column Break'},
|
{fieldtype:'Column Break'},
|
||||||
@@ -58,7 +66,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
|||||||
fieldtype:'Float',
|
fieldtype:'Float',
|
||||||
read_only: 1,
|
read_only: 1,
|
||||||
label: __(me.has_batch ? 'Total Qty' : 'Qty'),
|
label: __(me.has_batch ? 'Total Qty' : 'Qty'),
|
||||||
default: me.qty
|
default: 0
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -147,14 +155,10 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
bind_qty: function() {
|
bind_qty: function() {
|
||||||
let serial_no_link = this.dialog.fields_dict.serial_no_select;
|
|
||||||
let serial_no_list_field = this.dialog.fields_dict.serial_no;
|
|
||||||
let batches_field = this.dialog.fields_dict.batches;
|
let batches_field = this.dialog.fields_dict.batches;
|
||||||
|
|
||||||
let qty_field = this.dialog.fields_dict.qty;
|
let qty_field = this.dialog.fields_dict.qty;
|
||||||
|
if(batches_field) {
|
||||||
let update_quantity = (batch) => {
|
batches_field.grid.wrapper.on('change', function() {
|
||||||
if(batch) {
|
|
||||||
let total_qty = 0;
|
let total_qty = 0;
|
||||||
batches_field.grid.wrapper.find(
|
batches_field.grid.wrapper.find(
|
||||||
'input[data-fieldname="selected_qty"]').each(function() {
|
'input[data-fieldname="selected_qty"]').each(function() {
|
||||||
@@ -162,48 +166,6 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
|||||||
total_qty += Number($(this).val());
|
total_qty += Number($(this).val());
|
||||||
});
|
});
|
||||||
qty_field.set_input(total_qty);
|
qty_field.set_input(total_qty);
|
||||||
} else {
|
|
||||||
let serial_numbers = serial_no_list_field.get_value()
|
|
||||||
.replace(/\n/g, ' ').match(/\S+/g) || [];
|
|
||||||
qty_field.set_input(serial_numbers.length);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if(serial_no_link) {
|
|
||||||
let serial_list = [];
|
|
||||||
serial_no_link.$input.on('awesomplete-selectcomplete', function() {
|
|
||||||
if(serial_no_link.get_value().length > 0) {
|
|
||||||
let new_no = serial_no_link.get_value();
|
|
||||||
let list_value = serial_no_list_field.get_value();
|
|
||||||
let new_line = '\n';
|
|
||||||
if(!serial_no_list_field.get_value()) {
|
|
||||||
new_line = '';
|
|
||||||
} else {
|
|
||||||
serial_list = list_value.replace(/\s+/g, ' ').split(' ');
|
|
||||||
}
|
|
||||||
if(!serial_list.includes(new_no)) {
|
|
||||||
serial_no_link.set_new_description('');
|
|
||||||
serial_no_list_field.set_value(list_value + new_line + new_no);
|
|
||||||
update_quantity(0);
|
|
||||||
} else {
|
|
||||||
serial_no_link.set_new_description(new_no + ' is already selected.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should, but doesn't work
|
|
||||||
serial_no_link.set_input('');
|
|
||||||
serial_no_link.$input.blur();
|
|
||||||
});
|
|
||||||
|
|
||||||
serial_no_list_field.$input.on('input', function() {
|
|
||||||
serial_list = serial_no_list_field.get_value().replace(/\s+/g, ' ').split(' ');
|
|
||||||
update_quantity(0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if(batches_field) {
|
|
||||||
batches_field.grid.wrapper.on('change', function() {
|
|
||||||
update_quantity(1);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -311,6 +273,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
|||||||
|
|
||||||
get_serial_no_fields: function() {
|
get_serial_no_fields: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
this.serial_list = [];
|
||||||
return [
|
return [
|
||||||
{fieldtype: 'Section Break', label: __('Serial No')},
|
{fieldtype: 'Section Break', label: __('Serial No')},
|
||||||
{
|
{
|
||||||
@@ -318,10 +281,46 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
|||||||
label: __('Select'),
|
label: __('Select'),
|
||||||
get_query: function() {
|
get_query: function() {
|
||||||
return { filters: {item_code: me.item_code}};
|
return { filters: {item_code: me.item_code}};
|
||||||
|
},
|
||||||
|
onchange: function(e) {
|
||||||
|
if(this.in_local_change) return;
|
||||||
|
this.in_local_change = 1;
|
||||||
|
|
||||||
|
let serial_no_list_field = this.layout.fields_dict.serial_no;
|
||||||
|
let qty_field = this.layout.fields_dict.qty;
|
||||||
|
|
||||||
|
let new_number = this.get_value();
|
||||||
|
let list_value = serial_no_list_field.get_value();
|
||||||
|
let new_line = '\n';
|
||||||
|
if(!list_value) {
|
||||||
|
new_line = '';
|
||||||
|
} else {
|
||||||
|
me.serial_list = list_value.replace(/\n/g, ' ').match(/\S+/g) || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!me.serial_list.includes(new_number)) {
|
||||||
|
this.set_new_description('');
|
||||||
|
serial_no_list_field.set_value(me.serial_list.join('\n') + new_line + new_number);
|
||||||
|
me.serial_list = serial_no_list_field.get_value().replace(/\n/g, ' ').match(/\S+/g) || [];
|
||||||
|
} else {
|
||||||
|
this.set_new_description(new_number + ' is already selected.');
|
||||||
|
}
|
||||||
|
|
||||||
|
qty_field.set_input(me.serial_list.length);
|
||||||
|
this.$input.val("");
|
||||||
|
this.in_local_change = 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{fieldtype: 'Column Break'},
|
{fieldtype: 'Column Break'},
|
||||||
{fieldname: 'serial_no', fieldtype: 'Small Text'}
|
{
|
||||||
|
fieldname: 'serial_no',
|
||||||
|
fieldtype: 'Small Text',
|
||||||
|
onchange: function() {
|
||||||
|
me.serial_list = this.get_value()
|
||||||
|
.replace(/\n/g, ' ').match(/\S+/g) || [];
|
||||||
|
this.layout.fields_dict.qty.set_input(me.serial_list.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
states = [
|
states = [
|
||||||
'',
|
'',
|
||||||
|
'Andaman and Nicobar Islands',
|
||||||
'Andhra Pradesh',
|
'Andhra Pradesh',
|
||||||
'Arunachal Pradesh',
|
'Arunachal Pradesh',
|
||||||
'Assam',
|
'Assam',
|
||||||
'Bihar',
|
'Bihar',
|
||||||
'Chandigarh',
|
'Chandigarh',
|
||||||
'Chattisgarh',
|
'Chhattisgarh',
|
||||||
'Dadra and Nagar Haveli',
|
'Dadra and Nagar Haveli',
|
||||||
'Daman and Diu',
|
'Daman and Diu',
|
||||||
'Delhi',
|
'Delhi',
|
||||||
@@ -25,6 +26,7 @@ states = [
|
|||||||
'Mizoram',
|
'Mizoram',
|
||||||
'Nagaland',
|
'Nagaland',
|
||||||
'Odisha',
|
'Odisha',
|
||||||
|
'Other Territory',
|
||||||
'Pondicherry',
|
'Pondicherry',
|
||||||
'Punjab',
|
'Punjab',
|
||||||
'Rajasthan',
|
'Rajasthan',
|
||||||
@@ -38,12 +40,13 @@ states = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
state_numbers = {
|
state_numbers = {
|
||||||
|
"Andaman and Nicobar Islands": "35",
|
||||||
"Andhra Pradesh": "37",
|
"Andhra Pradesh": "37",
|
||||||
"Arunachal Pradesh": "12",
|
"Arunachal Pradesh": "12",
|
||||||
"Assam": "18",
|
"Assam": "18",
|
||||||
"Bihar": "10",
|
"Bihar": "10",
|
||||||
"Chandigarh": "04",
|
"Chandigarh": "04",
|
||||||
"Chattisgarh": "22",
|
"Chhattisgarh": "22",
|
||||||
"Dadra and Nagar Haveli": "26",
|
"Dadra and Nagar Haveli": "26",
|
||||||
"Daman and Diu": "25",
|
"Daman and Diu": "25",
|
||||||
"Delhi": "07",
|
"Delhi": "07",
|
||||||
@@ -63,6 +66,7 @@ state_numbers = {
|
|||||||
"Mizoram": "15",
|
"Mizoram": "15",
|
||||||
"Nagaland": "13",
|
"Nagaland": "13",
|
||||||
"Odisha": "21",
|
"Odisha": "21",
|
||||||
|
"Other Territory": "98",
|
||||||
"Pondicherry": "34",
|
"Pondicherry": "34",
|
||||||
"Punjab": "03",
|
"Punjab": "03",
|
||||||
"Rajasthan": "08",
|
"Rajasthan": "08",
|
||||||
@@ -70,7 +74,7 @@ state_numbers = {
|
|||||||
"Tamil Nadu": "33",
|
"Tamil Nadu": "33",
|
||||||
"Telangana": "36",
|
"Telangana": "36",
|
||||||
"Tripura": "16",
|
"Tripura": "16",
|
||||||
"Uttar Pradesh": "35",
|
"Uttar Pradesh": "09",
|
||||||
"Uttarakhand": "36",
|
"Uttarakhand": "05",
|
||||||
"West Bengal": "19"
|
"West Bengal": "19",
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"state_name": "Uttar Pradesh"
|
"state_name": "Uttar Pradesh"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"state_number": "36",
|
"state_number": "05",
|
||||||
"state_code": "UT",
|
"state_code": "UT",
|
||||||
"state_name": "Uttarakhand"
|
"state_name": "Uttarakhand"
|
||||||
},
|
},
|
||||||
|
|||||||
2398
erpnext/regional/india/sac_code_data.json
Normal file
@@ -12,10 +12,10 @@ def setup(company=None, patch=True):
|
|||||||
make_custom_fields()
|
make_custom_fields()
|
||||||
add_permissions()
|
add_permissions()
|
||||||
add_custom_roles_for_reports()
|
add_custom_roles_for_reports()
|
||||||
add_hsn_codes()
|
add_hsn_sac_codes()
|
||||||
update_address_template()
|
|
||||||
add_print_formats()
|
add_print_formats()
|
||||||
if not patch:
|
if not patch:
|
||||||
|
update_address_template()
|
||||||
make_fixtures()
|
make_fixtures()
|
||||||
|
|
||||||
def update_address_template():
|
def update_address_template():
|
||||||
@@ -33,21 +33,26 @@ def update_address_template():
|
|||||||
template=html
|
template=html
|
||||||
)).insert()
|
)).insert()
|
||||||
|
|
||||||
def add_hsn_codes():
|
def add_hsn_sac_codes():
|
||||||
if frappe.db.count('GST HSN Code') > 100:
|
# HSN codes
|
||||||
return
|
|
||||||
|
|
||||||
with open(os.path.join(os.path.dirname(__file__), 'hsn_code_data.json'), 'r') as f:
|
with open(os.path.join(os.path.dirname(__file__), 'hsn_code_data.json'), 'r') as f:
|
||||||
hsn_codes = json.loads(f.read())
|
hsn_codes = json.loads(f.read())
|
||||||
|
|
||||||
frappe.db.commit()
|
create_hsn_codes(hsn_codes, code_field="hsn_code")
|
||||||
frappe.db.sql('truncate `tabGST HSN Code`')
|
|
||||||
|
|
||||||
for d in hsn_codes:
|
# SAC Codes
|
||||||
hsn_code = frappe.new_doc('GST HSN Code')
|
with open(os.path.join(os.path.dirname(__file__), 'sac_code_data.json'), 'r') as f:
|
||||||
hsn_code.update(d)
|
sac_codes = json.loads(f.read())
|
||||||
hsn_code.name = hsn_code.hsn_code
|
create_hsn_codes(sac_codes, code_field="sac_code")
|
||||||
hsn_code.db_insert()
|
|
||||||
|
def create_hsn_codes(data, code_field):
|
||||||
|
for d in data:
|
||||||
|
if not frappe.db.exists("GST HSN Code", d[code_field]):
|
||||||
|
hsn_code = frappe.new_doc('GST HSN Code')
|
||||||
|
hsn_code.description = d["description"]
|
||||||
|
hsn_code.hsn_code = d[code_field]
|
||||||
|
hsn_code.name = d[code_field]
|
||||||
|
hsn_code.db_insert()
|
||||||
|
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
|
|
||||||
@@ -75,7 +80,7 @@ def add_print_formats():
|
|||||||
|
|
||||||
def make_custom_fields():
|
def make_custom_fields():
|
||||||
hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
|
hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
|
||||||
fieldtype='Data', options='item_code.gst_hsn_code', insert_after='description')
|
fieldtype='Data', options='item_code.gst_hsn_code', insert_after='description', print_hide=1)
|
||||||
|
|
||||||
custom_fields = {
|
custom_fields = {
|
||||||
'Address': [
|
'Address': [
|
||||||
@@ -84,7 +89,7 @@ def make_custom_fields():
|
|||||||
dict(fieldname='gst_state', label='GST State', fieldtype='Select',
|
dict(fieldname='gst_state', label='GST State', fieldtype='Select',
|
||||||
options='\n'.join(states), insert_after='gstin'),
|
options='\n'.join(states), insert_after='gstin'),
|
||||||
dict(fieldname='gst_state_number', label='GST State Number',
|
dict(fieldname='gst_state_number', label='GST State Number',
|
||||||
fieldtype='Int', insert_after='gst_state'),
|
fieldtype='Int', insert_after='gst_state', read_only=1),
|
||||||
],
|
],
|
||||||
'Purchase Invoice': [
|
'Purchase Invoice': [
|
||||||
dict(fieldname='supplier_gstin', label='Supplier GSTIN',
|
dict(fieldname='supplier_gstin', label='Supplier GSTIN',
|
||||||
@@ -102,13 +107,15 @@ def make_custom_fields():
|
|||||||
fieldtype='Data', insert_after='company_address',
|
fieldtype='Data', insert_after='company_address',
|
||||||
options='company_address.gstin', print_hide=1),
|
options='company_address.gstin', print_hide=1),
|
||||||
dict(fieldname='invoice_copy', label='Invoice Copy',
|
dict(fieldname='invoice_copy', label='Invoice Copy',
|
||||||
fieldtype='Select', insert_after='project', print_hide=1, allow_on_submit=1,
|
fieldtype='Select', insert_after='select_print_heading', print_hide=1, allow_on_submit=1,
|
||||||
options='ORIGINAL FOR RECIPIENT\nDUPLICATE FOR TRANSPORTER\nTRIPLICATE FOR SUPPLIER')
|
options='Original for Recipient\nDuplicate for Transporter\nDuplicate for Supplier\nTriplicate for Supplier')
|
||||||
],
|
],
|
||||||
'Item': [
|
'Item': [
|
||||||
dict(fieldname='gst_hsn_code', label='HSN/SAC',
|
dict(fieldname='gst_hsn_code', label='HSN/SAC',
|
||||||
fieldtype='Link', options='GST HSN Code', insert_after='item_group'),
|
fieldtype='Link', options='GST HSN Code', insert_after='item_group'),
|
||||||
],
|
],
|
||||||
|
'Quotation Item': [hsn_sac_field],
|
||||||
|
'Supplier Quotation Item': [hsn_sac_field],
|
||||||
'Sales Order Item': [hsn_sac_field],
|
'Sales Order Item': [hsn_sac_field],
|
||||||
'Delivery Note Item': [hsn_sac_field],
|
'Delivery Note Item': [hsn_sac_field],
|
||||||
'Sales Invoice Item': [hsn_sac_field],
|
'Sales Invoice Item': [hsn_sac_field],
|
||||||
@@ -119,7 +126,13 @@ def make_custom_fields():
|
|||||||
|
|
||||||
for doctype, fields in custom_fields.items():
|
for doctype, fields in custom_fields.items():
|
||||||
for df in fields:
|
for df in fields:
|
||||||
create_custom_field(doctype, df)
|
field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": df["fieldname"]})
|
||||||
|
if not field:
|
||||||
|
create_custom_field(doctype, df)
|
||||||
|
else:
|
||||||
|
custom_field = frappe.get_doc("Custom Field", field)
|
||||||
|
custom_field.update(df)
|
||||||
|
custom_field.save()
|
||||||
|
|
||||||
def make_fixtures():
|
def make_fixtures():
|
||||||
docs = [
|
docs = [
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import frappe, re
|
import frappe, re
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from erpnext.regional.india import states, state_numbers
|
from erpnext.regional.india import states, state_numbers
|
||||||
|
from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount
|
||||||
|
|
||||||
def validate_gstin_for_india(doc, method):
|
def validate_gstin_for_india(doc, method):
|
||||||
if not hasattr(doc, 'gstin'):
|
if not hasattr(doc, 'gstin'):
|
||||||
@@ -19,6 +20,47 @@ def validate_gstin_for_india(doc, method):
|
|||||||
|
|
||||||
if doc.gst_state:
|
if doc.gst_state:
|
||||||
doc.gst_state_number = state_numbers[doc.gst_state]
|
doc.gst_state_number = state_numbers[doc.gst_state]
|
||||||
if doc.gst_state_number != doc.gstin[:2]:
|
if doc.gstin != "NA" and doc.gst_state_number != doc.gstin[:2]:
|
||||||
frappe.throw(_("First 2 digits of GSTIN should match with State number {0}")
|
frappe.throw(_("First 2 digits of GSTIN should match with State number {0}")
|
||||||
.format(doc.gst_state_number))
|
.format(doc.gst_state_number))
|
||||||
|
|
||||||
|
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
|
||||||
|
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
|
||||||
|
return [_("HSN/SAC"), _("Taxable Amount")] + tax_accounts
|
||||||
|
else:
|
||||||
|
return [_("Item"), _("Taxable Amount")] + tax_accounts
|
||||||
|
|
||||||
|
def get_itemised_tax_breakup_data(doc):
|
||||||
|
itemised_tax = get_itemised_tax(doc.taxes)
|
||||||
|
|
||||||
|
itemised_taxable_amount = get_itemised_taxable_amount(doc.items)
|
||||||
|
|
||||||
|
if not frappe.get_meta(doc.doctype + " Item").has_field('gst_hsn_code'):
|
||||||
|
return itemised_tax, itemised_taxable_amount
|
||||||
|
|
||||||
|
item_hsn_map = frappe._dict()
|
||||||
|
for d in doc.items:
|
||||||
|
item_hsn_map.setdefault(d.item_code or d.item_name, d.get("gst_hsn_code"))
|
||||||
|
|
||||||
|
hsn_tax = {}
|
||||||
|
for item, taxes in itemised_tax.items():
|
||||||
|
hsn_code = item_hsn_map.get(item)
|
||||||
|
hsn_tax.setdefault(hsn_code, frappe._dict())
|
||||||
|
for tax_account, tax_detail in taxes.items():
|
||||||
|
hsn_tax[hsn_code].setdefault(tax_account, {"tax_rate": 0, "tax_amount": 0})
|
||||||
|
hsn_tax[hsn_code][tax_account]["tax_rate"] = tax_detail.get("tax_rate")
|
||||||
|
hsn_tax[hsn_code][tax_account]["tax_amount"] += tax_detail.get("tax_amount")
|
||||||
|
|
||||||
|
# set taxable amount
|
||||||
|
hsn_taxable_amount = frappe._dict()
|
||||||
|
for item, taxable_amount in itemised_taxable_amount.items():
|
||||||
|
hsn_code = item_hsn_map.get(item)
|
||||||
|
hsn_taxable_amount.setdefault(hsn_code, 0)
|
||||||
|
hsn_taxable_amount[hsn_code] += itemised_taxable_amount.get(item)
|
||||||
|
|
||||||
|
return hsn_tax, hsn_taxable_amount
|
||||||
|
|
||||||
|
# don't remove this function it is used in tests
|
||||||
|
def test_method():
|
||||||
|
'''test function'''
|
||||||
|
return 'overridden'
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
cur_frm.add_fetch("student_group", "course", "course");
|
cur_frm.add_fetch("student_group", "course", "course");
|
||||||
cur_frm.add_fetch("examiner", "instructor_name", "examiner_name");
|
cur_frm.add_fetch("examiner", "instructor_name", "examiner_name");
|
||||||
cur_frm.add_fetch("supervisor", "instructor_name", "supervisor_name");
|
cur_frm.add_fetch("supervisor", "instructor_name", "supervisor_name");
|
||||||
|
cur_frm.add_fetch("course", "default_grading_scale", "grading_scale");
|
||||||
|
|
||||||
frappe.ui.form.on("Assessment Plan", {
|
frappe.ui.form.on("Assessment Plan", {
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
|
|||||||
@@ -143,9 +143,10 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"default": "Today",
|
"default": "0",
|
||||||
"fieldname": "enrollment_date",
|
"description": "Check this if the Student is residing at the Institute's Hostel.",
|
||||||
"fieldtype": "Date",
|
"fieldname": "boarding_student",
|
||||||
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
@@ -153,9 +154,10 @@
|
|||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Enrollment Date",
|
"label": "Boarding Student",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
|
"options": "",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@@ -163,7 +165,7 @@
|
|||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"remember_last_selected_value": 0,
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 1,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
@@ -321,6 +323,37 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"default": "Today",
|
||||||
|
"fieldname": "enrollment_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Enrollment Date",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 1,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@@ -370,7 +403,7 @@
|
|||||||
"label": "Mode of Transportation",
|
"label": "Mode of Transportation",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "\nSchool Bus\nPublic Transport\nSelf-Driving Vehicle\nPick/Drop by Guardian",
|
"options": "\nWalking\nSchool Bus\nPublic Transport\nSelf-Driving Vehicle\nPick/Drop by Guardian",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@@ -638,7 +671,7 @@
|
|||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
"modified": "2017-06-30 08:21:49.430996",
|
"modified": "2017-07-10 18:16:15.810616",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Schools",
|
"module": "Schools",
|
||||||
"name": "Program Enrollment",
|
"name": "Program Enrollment",
|
||||||
|
|||||||
@@ -589,67 +589,6 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_18",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Guardian Details",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "guardians",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Guardians",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Student Guardian",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@@ -859,6 +798,67 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "section_break_18",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Guardian Details",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "guardians",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Guardians",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"options": "Student Guardian",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@@ -1114,7 +1114,7 @@
|
|||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
"modified": "2017-06-30 08:21:50.423784",
|
"modified": "2017-07-07 16:30:08.930882",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Schools",
|
"module": "Schools",
|
||||||
"name": "Student",
|
"name": "Student",
|
||||||
|
|||||||
@@ -7,10 +7,24 @@ def get_data():
|
|||||||
'fieldname': 'student',
|
'fieldname': 'student',
|
||||||
'transactions': [
|
'transactions': [
|
||||||
{
|
{
|
||||||
'items': ['Student Log', 'Student Group', 'Program Enrollment']
|
'label': _('Admission'),
|
||||||
|
'items': ['Program Enrollment']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'items': ['Fees', 'Assessment Result', 'Student Attendance', 'Student Leave Application']
|
'label': _('Student Activity'),
|
||||||
|
'items': ['Student Log', 'Student Group', ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Assessment'),
|
||||||
|
'items': ['Assessment Result']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Attendance'),
|
||||||
|
'items': ['Student Attendance', 'Student Leave Application']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Fee'),
|
||||||
|
'items': ['Fees']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -135,22 +135,24 @@ schools.StudentsEditor = Class.extend({
|
|||||||
frappe.confirm(__("Do you want to update attendance?<br>Present: {0}\
|
frappe.confirm(__("Do you want to update attendance?<br>Present: {0}\
|
||||||
<br>Absent: {1}", [students_present.length, students_absent.length]),
|
<br>Absent: {1}", [students_present.length, students_absent.length]),
|
||||||
function() { //ifyes
|
function() { //ifyes
|
||||||
frappe.call({
|
if(!frappe.request.ajax_count) {
|
||||||
method: "erpnext.schools.api.mark_attendance",
|
frappe.call({
|
||||||
freeze: true,
|
method: "erpnext.schools.api.mark_attendance",
|
||||||
freeze_message: "Marking attendance",
|
freeze: true,
|
||||||
args: {
|
freeze_message: "Marking attendance",
|
||||||
"students_present": students_present,
|
args: {
|
||||||
"students_absent": students_absent,
|
"students_present": students_present,
|
||||||
"student_group": frm.doc.student_group,
|
"students_absent": students_absent,
|
||||||
"course_schedule": frm.doc.course_schedule,
|
"student_group": frm.doc.student_group,
|
||||||
"date": frm.doc.date
|
"course_schedule": frm.doc.course_schedule,
|
||||||
},
|
"date": frm.doc.date
|
||||||
callback: function(r) {
|
},
|
||||||
$(me.wrapper.find(".btn-mark-att")).attr("disabled", false);
|
callback: function(r) {
|
||||||
frm.trigger("student_group");
|
$(me.wrapper.find(".btn-mark-att")).attr("disabled", false);
|
||||||
}
|
frm.trigger("student_group");
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
function() { //ifno
|
function() { //ifno
|
||||||
$(me.wrapper.find(".btn-mark-att")).attr("disabled", false);
|
$(me.wrapper.find(".btn-mark-att")).attr("disabled", false);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Academic Year",
|
"label": "Academic Year",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
@@ -148,7 +148,7 @@
|
|||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Program",
|
"label": "Program",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
@@ -269,7 +269,7 @@
|
|||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-05-15 12:43:32.317942",
|
"modified": "2017-07-17 21:57:35.602091",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Schools",
|
"module": "Schools",
|
||||||
"name": "Student Group Creation Tool",
|
"name": "Student Group Creation Tool",
|
||||||
@@ -300,6 +300,7 @@
|
|||||||
"quick_entry": 0,
|
"quick_entry": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"read_only_onload": 0,
|
"read_only_onload": 0,
|
||||||
|
"restrict_to_domain": "Education",
|
||||||
"show_name_in_global_search": 0,
|
"show_name_in_global_search": 0,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 0,
|
"allow_import": 0,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"autoname": "SLA.######",
|
"autoname": "SLA.######",
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -43,6 +45,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -73,6 +76,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -102,6 +106,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -131,6 +136,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -160,6 +166,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -190,6 +197,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -218,6 +226,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -247,6 +256,7 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -276,17 +286,17 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"has_web_view": 0,
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"image_view": 0,
|
"image_view": 0,
|
||||||
"in_create": 0,
|
"in_create": 0,
|
||||||
"in_dialog": 0,
|
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-02-20 13:21:08.828872",
|
"modified": "2017-07-17 21:57:57.804413",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Schools",
|
"module": "Schools",
|
||||||
"name": "Student Leave Application",
|
"name": "Student Leave Application",
|
||||||
@@ -337,6 +347,7 @@
|
|||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"read_only_onload": 0,
|
"read_only_onload": 0,
|
||||||
|
"restrict_to_domain": "Education",
|
||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
|||||||