Compare commits
311 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
3f3ac5652f | ||
|
|
7b8d366e3a | ||
|
|
a29442d6bf | ||
|
|
bbe16c80ff | ||
|
|
4e21f11864 | ||
|
|
19d52dc503 | ||
|
|
701f7cccbf | ||
|
|
8b486b0f28 | ||
|
|
6705ab3eaf | ||
|
|
233a19a373 | ||
|
|
fbb5945ff3 | ||
|
|
7773ee8960 | ||
|
|
8ad168ac67 | ||
|
|
3e9520b276 | ||
|
|
29b74b90c8 | ||
|
|
ad6cf4fa88 | ||
|
|
e927b81292 | ||
|
|
88a37c17a6 | ||
|
|
934e69fe0b | ||
|
|
5fe7f6c3fd | ||
|
|
d59819d9bb | ||
|
|
afdd7a626c | ||
|
|
7699b5e92a | ||
|
|
b5d765d19a | ||
|
|
6d03790b44 | ||
|
|
3638250f5d | ||
|
|
7bf192e46a | ||
|
|
fa351f4bdf | ||
|
|
bedb486c55 | ||
|
|
f3f0dfef2a | ||
|
|
5d5a81f375 | ||
|
|
02c8607d04 | ||
|
|
ddd4845420 | ||
|
|
19d9381197 | ||
|
|
63b06420e1 | ||
|
|
bf66d7e041 | ||
|
|
fc85768685 | ||
|
|
37c784eb3a | ||
|
|
a54eb7d022 | ||
|
|
48af4289d3 | ||
|
|
03c30a7f92 | ||
|
|
949a920022 | ||
|
|
852cb64e4f | ||
|
|
b66fb9a4c0 | ||
|
|
9fbdf14e61 | ||
|
|
4b7a30b527 | ||
|
|
5ad4a6e161 | ||
|
|
10a4a13e5e | ||
|
|
3ceab64bfa | ||
|
|
6015f0f2ec | ||
|
|
e5ca48a76a | ||
|
|
3e4bcfe2d8 | ||
|
|
5e4c8ecd62 | ||
|
|
11df066ed0 | ||
|
|
87f2848aeb | ||
|
|
12450fa473 | ||
|
|
67bbcf6932 | ||
|
|
79918c66c2 | ||
|
|
960208bae0 | ||
|
|
1bad1fcc00 | ||
|
|
43ef4e9047 | ||
|
|
65f6f2a05e | ||
|
|
558fcc140f | ||
|
|
ea92682cfd | ||
|
|
a06a600d0a | ||
|
|
af9d3a4db6 | ||
|
|
f39a9f1c5b | ||
|
|
067991ee30 | ||
|
|
1589ada04d | ||
|
|
ee368221cf | ||
|
|
6691856d08 | ||
|
|
53de2f1b57 | ||
|
|
22aaf0cbd0 | ||
|
|
8ebc0df65f | ||
|
|
4095915bff | ||
|
|
abe8e2ecce | ||
|
|
b053674781 | ||
|
|
bb68f8ca01 | ||
|
|
943637e06c | ||
|
|
0407cb0d92 | ||
|
|
d192a420d1 | ||
|
|
3856d14ae6 | ||
|
|
85480b3af7 | ||
|
|
c4125b32ee | ||
|
|
7640858510 | ||
|
|
4e08dfc72f | ||
|
|
53e34f5c1c | ||
|
|
c6e1c3c048 | ||
|
|
0c2de6e07a | ||
|
|
b801357ecf | ||
|
|
1508267fd6 | ||
|
|
8f1f93603d | ||
|
|
f1bd39c937 | ||
|
|
800c69eec3 | ||
|
|
ec252c806f | ||
|
|
2a903a0608 | ||
|
|
71b4e48ea5 | ||
|
|
ae2d92ee76 | ||
|
|
21cf1fd851 | ||
|
|
02c281cc2f | ||
|
|
a938d3956a | ||
|
|
02b0ed4199 | ||
|
|
76f93d05b7 | ||
|
|
24ab20fe11 | ||
|
|
1eb31db71f | ||
|
|
ef95b4d6e3 | ||
|
|
514c0417dd | ||
|
|
67f6ac848c | ||
|
|
5d95ebec4e | ||
|
|
bb7317d398 | ||
|
|
550268eaf3 | ||
|
|
7f9af46da5 | ||
|
|
e38eb83358 | ||
|
|
af00c9f70b | ||
|
|
5c7545da0c | ||
|
|
d6e8bb5452 | ||
|
|
435032f5bc | ||
|
|
1ef50c89db | ||
|
|
2e4b4454b3 | ||
|
|
4b33b7e1c1 | ||
|
|
69279229cc | ||
|
|
5b7028c7bb | ||
|
|
0018db344c | ||
|
|
e9a4f4e70d | ||
|
|
be03de3ad6 | ||
|
|
d235325a95 | ||
|
|
6daa6e422e | ||
|
|
07913c3ff2 | ||
|
|
71ba7ea717 | ||
|
|
3b0e6cecd6 | ||
|
|
544de60d36 | ||
|
|
d652221071 | ||
|
|
4d5d3b7685 | ||
|
|
3bf9071598 | ||
|
|
46af07cc09 | ||
|
|
27692670b1 | ||
|
|
3708df61bf | ||
|
|
3f2dd04b10 | ||
|
|
3959c7c3c1 | ||
|
|
eb7eb43dfc | ||
|
|
0b078fb4cb | ||
|
|
6837e69187 | ||
|
|
5824ae98d9 | ||
|
|
67526f244e | ||
|
|
67cbeb1bb0 | ||
|
|
8859eb23a3 | ||
|
|
82e816054e | ||
|
|
ea7768d3f3 | ||
|
|
cb650f836e | ||
|
|
c1d22adb9f | ||
|
|
bce13cd0e3 | ||
|
|
8623166dca | ||
|
|
94500fd17b | ||
|
|
dcd54209fc | ||
|
|
96e629a635 | ||
|
|
ac3ad0810a | ||
|
|
1e96b7bbe5 | ||
|
|
0ea5d941e6 | ||
|
|
881491cd2b | ||
|
|
2c77165fc6 | ||
|
|
6561b8ade9 | ||
|
|
840c757b12 | ||
|
|
7055446508 | ||
|
|
e0434ad40e | ||
|
|
d53dd7f4c9 | ||
|
|
fed9816213 | ||
|
|
a35839aa47 | ||
|
|
5491275b66 | ||
|
|
70fe968f02 | ||
|
|
a3aa6a4449 | ||
|
|
8fa1e03367 | ||
|
|
0f0b121669 |
@@ -131,6 +131,7 @@
|
||||
"getCookies": true,
|
||||
"get_url_arg": true,
|
||||
"get_server_fields": true,
|
||||
"set_multiple": true
|
||||
"set_multiple": true,
|
||||
"QUnit": true
|
||||
}
|
||||
}
|
||||
|
||||
50
.travis.yml
@@ -1,6 +1,12 @@
|
||||
language: python
|
||||
dist: trusty
|
||||
group: deprecated-2017Q2
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- google-chrome
|
||||
packages:
|
||||
- google-chrome-stable
|
||||
|
||||
python:
|
||||
- "2.7"
|
||||
@@ -8,43 +14,43 @@ python:
|
||||
services:
|
||||
- mysql
|
||||
|
||||
before_install:
|
||||
- "export DISPLAY=:99.0"
|
||||
- "sh -e /etc/init.d/xvfb start"
|
||||
|
||||
install:
|
||||
- sudo rm /etc/apt/sources.list.d/docker.list
|
||||
- sudo apt-get purge -y mysql-common mysql-server mysql-client
|
||||
- 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
|
||||
- sudo python install.py --develop --user travis --without-bench-setup
|
||||
- sudo pip install -e ~/bench
|
||||
|
||||
# - sudo pip install --upgrade pip
|
||||
- rm $TRAVIS_BUILD_DIR/.git/shallow
|
||||
- bash $TRAVIS_BUILD_DIR/travis/bench_init.sh
|
||||
- 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
|
||||
- bench get-app erpnext $TRAVIS_BUILD_DIR
|
||||
- bench use test_site
|
||||
- bench reinstall --yes
|
||||
- bench build
|
||||
- bench scheduler disable
|
||||
- bench start &
|
||||
- sleep 10
|
||||
- bench --verbose run-tests --driver Firefox
|
||||
|
||||
before_script:
|
||||
- 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
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/92b3bea86d8c5397beef
|
||||
on_success: always
|
||||
on_failure: always
|
||||
on_start: never
|
||||
script:
|
||||
- set -e
|
||||
- bench --verbose run-tests
|
||||
- sleep 5
|
||||
- bench --verbose run-ui-tests --app erpnext
|
||||
|
||||
46
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@frappe.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
@@ -1,9 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
import inspect
|
||||
import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
|
||||
__version__ = '8.1.4'
|
||||
|
||||
__version__ = '8.5.0'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
@@ -66,3 +67,34 @@ def is_perpetual_inventory_enabled(company):
|
||||
company, "enable_perpetual_inventory") or 0
|
||||
|
||||
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
|
||||
|
||||
|
||||
cur_frm.cscript.refresh = function (doc, cdt, cdn) {
|
||||
if (doc.__islocal) {
|
||||
frappe.msgprint(__("Please create new account from Chart of Accounts."));
|
||||
throw "cannot create";
|
||||
}
|
||||
|
||||
cur_frm.toggle_display('account_name', doc.__islocal);
|
||||
|
||||
// hide fields if group
|
||||
cur_frm.toggle_display(['account_type', 'tax_rate'], cint(doc.is_group) == 0)
|
||||
|
||||
// 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.ui.form.on('Account', {
|
||||
setup: function(frm) {
|
||||
frm.add_fetch('parent_account', 'report_type', 'report_type');
|
||||
frm.add_fetch('parent_account', 'root_type', 'root_type');
|
||||
},
|
||||
onload: function(frm) {
|
||||
frm.set_query('parent_account', function(doc) {
|
||||
return {
|
||||
filters: {
|
||||
"is_group": 1,
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -62,13 +62,13 @@ class BankReconciliation(Document):
|
||||
|
||||
for d in entries:
|
||||
row = self.append('payment_entries', {})
|
||||
|
||||
d.amount = fmt_money(d.debit if d.debit else d.credit, 2, d.account_currency) + " " + (_("Dr") if d.debit else _("Cr"))
|
||||
amount = d.debit if d.debit else d.credit
|
||||
d.amount = fmt_money(amount, 2, d.account_currency) + " " + (_("Dr") if d.debit else _("Cr"))
|
||||
d.pop("credit")
|
||||
d.pop("debit")
|
||||
d.pop("account_currency")
|
||||
row.update(d)
|
||||
self.total_amount += flt(d.amount)
|
||||
self.total_amount += flt(amount)
|
||||
|
||||
def update_clearance_date(self):
|
||||
clearance_date_updated = False
|
||||
|
||||
@@ -83,7 +83,7 @@ def validate_expense_against_budget(args):
|
||||
|
||||
budget_records = frappe.db.sql("""
|
||||
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_accumulated_monthly_budget_exceeded
|
||||
from
|
||||
@@ -111,15 +111,15 @@ def validate_budget_records(args, budget_records):
|
||||
args["month_end_date"] = get_last_day(args.posting_date)
|
||||
|
||||
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" \
|
||||
and yearly_action != monthly_action:
|
||||
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)
|
||||
if 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(
|
||||
_(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(diff, currency=currency)))
|
||||
|
||||
|
||||
@@ -140,6 +140,33 @@ class TestBudget(unittest.TestCase):
|
||||
budget.load_from_db()
|
||||
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):
|
||||
if budget_against_field == "Project":
|
||||
budget_against = "_Test Project"
|
||||
@@ -167,7 +194,8 @@ def make_budget(budget_against=None, cost_center=None):
|
||||
if budget_against == "Project":
|
||||
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", "_Test Project/_Test Fiscal Year 2013%")})
|
||||
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:
|
||||
frappe.db.sql("delete from `tabBudget` where name = %(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
|
||||
if(jvd.reference_type==="Expense Claim") {
|
||||
return {};
|
||||
return {
|
||||
filters: {
|
||||
'approval_status': 'Approved',
|
||||
'total_sanctioned_amount': ['>', 0],
|
||||
'status': ['!=', 'Paid'],
|
||||
'docstatus': 1
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// journal entry
|
||||
|
||||
@@ -733,11 +733,10 @@ def get_opening_accounts(company):
|
||||
accounts = frappe.db.sql_list("""select
|
||||
name from tabAccount
|
||||
where
|
||||
is_group=0 and
|
||||
report_type='Balance Sheet' and
|
||||
ifnull(warehouse, '') = '' and
|
||||
company=%s
|
||||
order by name asc""", company)
|
||||
is_group=0 and report_type='Balance Sheet' and company=%s and
|
||||
name not in(select distinct account from tabWarehouse where
|
||||
account is not null and account != '')
|
||||
order by name asc""", frappe.db.escape(company))
|
||||
|
||||
return [{"account": a, "balance": get_balance_on(a)} for a in accounts]
|
||||
|
||||
|
||||
@@ -291,37 +291,39 @@ frappe.ui.form.on('Payment Entry', {
|
||||
|
||||
set_account_currency_and_balance: function(frm, account, currency_field,
|
||||
balance_field, callback_function) {
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_details",
|
||||
args: {
|
||||
"account": account,
|
||||
"date": frm.doc.posting_date
|
||||
},
|
||||
callback: function(r, rt) {
|
||||
if(r.message) {
|
||||
frm.set_value(currency_field, r.message['account_currency']);
|
||||
frm.set_value(balance_field, r.message['account_balance']);
|
||||
if (frm.doc.posting_date && account) {
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_details",
|
||||
args: {
|
||||
"account": account,
|
||||
"date": frm.doc.posting_date
|
||||
},
|
||||
callback: function(r, rt) {
|
||||
if(r.message) {
|
||||
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") {
|
||||
frm.toggle_reqd(["reference_no", "reference_date"],
|
||||
(r.message['account_type'] == "Bank" ? 1 : 0));
|
||||
if(!frm.doc.received_amount && frm.doc.paid_amount)
|
||||
frm.events.paid_amount(frm);
|
||||
} else if(frm.doc.payment_type=="Pay" && currency_field=="paid_from_account_currency") {
|
||||
frm.toggle_reqd(["reference_no", "reference_date"],
|
||||
(r.message['account_type'] == "Bank" ? 1 : 0));
|
||||
if(frm.doc.payment_type=="Receive" && currency_field=="paid_to_account_currency") {
|
||||
frm.toggle_reqd(["reference_no", "reference_date"],
|
||||
(r.message['account_type'] == "Bank" ? 1 : 0));
|
||||
if(!frm.doc.received_amount && frm.doc.paid_amount)
|
||||
frm.events.paid_amount(frm);
|
||||
} else if(frm.doc.payment_type=="Pay" && currency_field=="paid_from_account_currency") {
|
||||
frm.toggle_reqd(["reference_no", "reference_date"],
|
||||
(r.message['account_type'] == "Bank" ? 1 : 0));
|
||||
|
||||
if(!frm.doc.paid_amount && frm.doc.received_amount)
|
||||
frm.events.received_amount(frm);
|
||||
if(!frm.doc.paid_amount && frm.doc.received_amount)
|
||||
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) {
|
||||
|
||||
@@ -492,9 +492,13 @@ def get_outstanding_reference_documents(args):
|
||||
|
||||
for d in outstanding_invoices:
|
||||
d["exchange_rate"] = 1
|
||||
if party_account_currency != company_currency \
|
||||
and d.voucher_type in ("Sales Invoice", "Purchase Invoice"):
|
||||
if party_account_currency != company_currency:
|
||||
if d.voucher_type in ("Sales Invoice", "Purchase Invoice"):
|
||||
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
|
||||
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
|
||||
})
|
||||
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'):
|
||||
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 frappe
|
||||
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 frappe import MandatoryError
|
||||
|
||||
@@ -248,4 +249,51 @@ class TestPricingRule(unittest.TestCase):
|
||||
so.submit()
|
||||
so = frappe.get_doc('Sales Order', so.name)
|
||||
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))
|
||||
@@ -224,9 +224,9 @@ cur_frm.fields_dict.cash_bank_account.get_query = function(doc) {
|
||||
return {
|
||||
filters: [
|
||||
["Account", "account_type", "in", ["Cash", "Bank"]],
|
||||
["Account", "root_type", "=", "Asset"],
|
||||
["Account", "is_group", "=",0],
|
||||
["Account", "company", "=", doc.company]
|
||||
["Account", "company", "=", doc.company],
|
||||
["Account", "report_type", "=", "Balance Sheet"]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3238,7 +3238,7 @@
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@@ -3767,10 +3767,11 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2017-06-13 14:28:57.930167",
|
||||
"modified": "2017-06-29 10:48:09.707735",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
"name_case": "Title Case",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
|
||||
@@ -71,17 +71,19 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
});
|
||||
|
||||
if(!from_delivery_note && !is_delivered_by_supplier) {
|
||||
cur_frm.add_custom_button(__('Delivery'), cur_frm.cscript['Make Delivery Note'],
|
||||
__("Make"));
|
||||
cur_frm.add_custom_button(__('Delivery'),
|
||||
cur_frm.cscript['Make Delivery Note'], __("Make"));
|
||||
}
|
||||
}
|
||||
|
||||
if(doc.outstanding_amount!=0 && !cint(doc.is_return)) {
|
||||
cur_frm.add_custom_button(__('Payment'), this.make_payment_entry, __("Make"));
|
||||
cur_frm.add_custom_button(__('Payment'),
|
||||
this.make_payment_entry, __("Make"));
|
||||
}
|
||||
|
||||
if(doc.outstanding_amount>0 && !cint(doc.is_return)) {
|
||||
cur_frm.add_custom_button(__('Payment Request'), this.make_payment_request, __("Make"));
|
||||
cur_frm.add_custom_button(__('Payment Request'),
|
||||
this.make_payment_request, __("Make"));
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +98,26 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
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 to POS type
|
||||
if(cur_frm.doc.is_pos) {
|
||||
@@ -303,6 +325,23 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
}
|
||||
|
||||
this.frm.refresh_fields();
|
||||
},
|
||||
|
||||
company_address: function() {
|
||||
var me = this;
|
||||
if(this.frm.doc.company_address) {
|
||||
frappe.call({
|
||||
method: "frappe.contacts.doctype.address.address.get_address_display",
|
||||
args: {"address_dict": this.frm.doc.company_address },
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
me.frm.set_value("company_address_display", r.message)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.frm.set_value("company_address_display", "");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -324,11 +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
|
||||
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
|
||||
else hide_field(['c_form_applicable', 'c_form_no']);
|
||||
@@ -424,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");
|
||||
}
|
||||
|
||||
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) {
|
||||
// filter on Account
|
||||
if (doc.customer) {
|
||||
@@ -481,7 +497,7 @@ frappe.ui.form.on('Sales Invoice', {
|
||||
'Delivery Note': 'Delivery',
|
||||
'Sales Invoice': 'Sales Return',
|
||||
'Payment Request': 'Payment Request',
|
||||
'Payment': 'Payment Entry'
|
||||
'Payment Entry': 'Payment'
|
||||
},
|
||||
frm.fields_dict["timesheets"].grid.get_field("time_sheet").get_query = function(doc, cdt, cdn){
|
||||
return{
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 0,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
@@ -190,7 +191,7 @@
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
@@ -200,37 +201,6 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "due_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": "Payment Due Date",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "due_date",
|
||||
"oldfieldtype": "Date",
|
||||
"permlevel": 0,
|
||||
"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,
|
||||
@@ -253,7 +223,7 @@
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Project",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
@@ -314,7 +284,7 @@
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
@@ -345,7 +315,7 @@
|
||||
"options": "POS Profile",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
@@ -510,6 +480,37 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "due_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": "Payment Due Date",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "due_date",
|
||||
"oldfieldtype": "Date",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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,
|
||||
@@ -844,6 +845,37 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "territory",
|
||||
"fieldtype": "Link",
|
||||
"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": "Territory",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Territory",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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,
|
||||
@@ -949,13 +981,13 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Company Address",
|
||||
"label": "Company Address Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Address",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
@@ -971,24 +1003,23 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "territory",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"fieldname": "company_address_display",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Territory",
|
||||
"label": "Company Address",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Territory",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
@@ -1479,7 +1510,7 @@
|
||||
"options": "Sales Invoice Timesheet",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
@@ -1882,6 +1913,36 @@
|
||||
"set_only_once": 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_on_submit": 0,
|
||||
@@ -1889,7 +1950,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "HTML",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -1899,12 +1960,12 @@
|
||||
"in_standard_filter": 0,
|
||||
"label": "Taxes and Charges Calculation",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "HTML",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
@@ -2511,7 +2572,7 @@
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Outstanding Amount",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
@@ -2984,7 +3045,7 @@
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
@@ -3597,7 +3658,7 @@
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
@@ -4450,7 +4511,7 @@
|
||||
"options": "Print Format",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
@@ -4511,7 +4572,7 @@
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
@@ -4542,7 +4603,7 @@
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
@@ -4627,10 +4688,11 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2017-06-22 14:45:35.257640",
|
||||
"modified": "2017-07-07 13:05:37.469682",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
"name_case": "Title Case",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@ from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timeshe
|
||||
from erpnext.accounts.doctype.asset.depreciation \
|
||||
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.serial_no.serial_no import get_serial_nos, get_delivery_note_serial_no
|
||||
|
||||
form_grid_templates = {
|
||||
"items": "templates/form_grid/item_grid.html"
|
||||
@@ -83,10 +84,10 @@ class SalesInvoice(SellingController):
|
||||
|
||||
if not self.is_opening:
|
||||
self.is_opening = 'No'
|
||||
|
||||
|
||||
if self._action != 'submit' and self.update_stock and not self.is_return:
|
||||
set_batch_nos(self, 'warehouse', True)
|
||||
|
||||
|
||||
|
||||
self.set_against_income_account()
|
||||
self.validate_c_form()
|
||||
@@ -98,7 +99,7 @@ class SalesInvoice(SellingController):
|
||||
self.set_billing_hours_and_amount()
|
||||
self.update_timesheet_billing_for_project()
|
||||
self.set_status()
|
||||
|
||||
|
||||
def before_save(self):
|
||||
set_account_for_mode_of_payment(self)
|
||||
|
||||
@@ -131,13 +132,16 @@ class SalesInvoice(SellingController):
|
||||
if not self.is_return:
|
||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||
self.check_credit_limit()
|
||||
self.update_serial_no()
|
||||
|
||||
self.update_serial_no()
|
||||
|
||||
if not cint(self.is_pos) == 1 and not self.is_return:
|
||||
self.update_against_document_in_jv()
|
||||
|
||||
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):
|
||||
if len(self.payments) == 0 and self.is_pos:
|
||||
frappe.throw(_("At least one mode of payment is required for POS invoice."))
|
||||
@@ -793,29 +797,36 @@ class SalesInvoice(SellingController):
|
||||
|
||||
def update_serial_no(self, in_cancel=False):
|
||||
""" update Sales Invoice refrence in Serial No """
|
||||
invoice = None if (in_cancel or self.is_return) else self.name
|
||||
if in_cancel and self.is_return:
|
||||
invoice = self.return_against
|
||||
|
||||
for item in self.items:
|
||||
if not item.serial_no:
|
||||
continue
|
||||
|
||||
serial_nos = ["'%s'"%serial_no for serial_no in item.serial_no.split("\n")]
|
||||
|
||||
frappe.db.sql(""" update `tabSerial No` set sales_invoice='{invoice}'
|
||||
where name in ({serial_nos})""".format(
|
||||
invoice='' if in_cancel else self.name,
|
||||
serial_nos=",".join(serial_nos)
|
||||
)
|
||||
)
|
||||
for serial_no in item.serial_no.split("\n"):
|
||||
if serial_no and frappe.db.exists('Serial No', serial_no):
|
||||
sno = frappe.get_doc('Serial No', serial_no)
|
||||
sno.sales_invoice = invoice
|
||||
sno.db_update()
|
||||
|
||||
def validate_serial_numbers(self):
|
||||
"""
|
||||
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_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):
|
||||
"""
|
||||
"""
|
||||
validate if the serial numbers in Sales Invoice Items are same as in
|
||||
Delivery Note Item
|
||||
"""
|
||||
@@ -825,14 +836,18 @@ class SalesInvoice(SellingController):
|
||||
continue
|
||||
|
||||
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 ""
|
||||
si_serial_nos = set(serial_nos.split("\n"))
|
||||
si_serial_nos = set(get_serial_nos(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)))
|
||||
|
||||
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):
|
||||
""" check if serial number is already used in other sales invoice """
|
||||
for item in self.items:
|
||||
@@ -917,7 +932,6 @@ def make_delivery_note(source_name, target_doc=None):
|
||||
|
||||
return doclist
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_sales_return(source_name, target_doc=None):
|
||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||
|
||||
@@ -13,6 +13,7 @@ from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
|
||||
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
|
||||
from frappe.model.naming import make_autoname
|
||||
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):
|
||||
def make(self):
|
||||
@@ -1105,6 +1106,93 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
for i, k in enumerate(expected_values["keys"]):
|
||||
self.assertEquals(d.get(k), expected_values[d.item_code][i])
|
||||
|
||||
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.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", {
|
||||
"charge_type": "On Net Total",
|
||||
"account_head": "_Test Account Service Tax - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"description": "Service Tax",
|
||||
"rate": 10
|
||||
})
|
||||
si.insert()
|
||||
return si
|
||||
|
||||
def create_sales_invoice(**args):
|
||||
si = frappe.new_doc("Sales Invoice")
|
||||
args = frappe._dict(args)
|
||||
@@ -1124,6 +1212,7 @@ def create_sales_invoice(**args):
|
||||
|
||||
si.append("items", {
|
||||
"item_code": args.item or args.item_code or "_Test Item",
|
||||
"gst_hsn_code": "999800",
|
||||
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||
"qty": args.qty or 1,
|
||||
"rate": args.rate or 100,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"doctype": "DocType",
|
||||
"document_type": "Document",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
@@ -1423,7 +1424,7 @@
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "eval:doc.serial_no || doc.batch_no",
|
||||
"columns": 0,
|
||||
"depends_on": "eval: parent.update_stock",
|
||||
"depends_on": "",
|
||||
"fieldname": "warehouse_and_reference",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -2165,7 +2166,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-05-10 17:14:42.681757",
|
||||
"modified": "2017-07-17 17:54:48.246507",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"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()) {
|
||||
search_status = false;
|
||||
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())) {
|
||||
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.stock_uom = this.items[0].stock_uom;
|
||||
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.qty = 1;
|
||||
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);
|
||||
},
|
||||
|
||||
show_item_wise_taxes: function () {
|
||||
return null;
|
||||
},
|
||||
|
||||
show_items_in_item_cart: function () {
|
||||
var me = this;
|
||||
var $items = this.wrapper.find(".items").empty();
|
||||
|
||||
@@ -8,9 +8,10 @@ import datetime
|
||||
from frappe import _, msgprint, scrub
|
||||
from frappe.defaults import get_user_permissions
|
||||
from frappe.model.utils import get_fetch_values
|
||||
from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff, \
|
||||
add_years, get_timestamp, nowdate, flt
|
||||
from frappe.contacts.doctype.address.address import get_address_display, get_default_address
|
||||
from frappe.utils import (add_days, getdate, formatdate, get_first_day, date_diff,
|
||||
add_years, get_timestamp, nowdate, flt)
|
||||
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 erpnext.exceptions import PartyFrozen, PartyDisabled, InvalidAccountCurrency
|
||||
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))
|
||||
|
||||
if doctype and doctype in ['Sales Invoice']:
|
||||
out.company_address = get_default_address('Company', company)
|
||||
out.update(get_fetch_values(doctype, 'company_address', out.company_address))
|
||||
out.update(get_company_address(company))
|
||||
if out.company_address:
|
||||
out.update(get_fetch_values(doctype, 'company_address', out.company_address))
|
||||
|
||||
def set_contact_details(out, party, party_type):
|
||||
out.contact_person = get_default_contact(party_type, party.name)
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
{% var letterhead= filters.letter_head || (frappe.get_doc(":Company", filters.company) && frappe.get_doc(":Company", filters.company).default_letter_head) || frappe.defaults.get_default("letter_head"); %}
|
||||
{% if(letterhead) { %}
|
||||
<div style="margin-bottom: 7px;" class="text-center">
|
||||
{%= frappe.boot.letter_heads[letterhead].header %}
|
||||
</div>
|
||||
{% } %}
|
||||
<h2 class="text-center">{%= __(report.report_name) %}</h2>
|
||||
<h4 class="text-center">{%= filters.customer || filters.supplier %} </h4>
|
||||
<h5 class="text-center">
|
||||
|
||||
@@ -10,7 +10,7 @@ from frappe.utils import (flt, getdate, get_first_day, get_last_day, date_diff,
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
|
||||
|
||||
def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_values=False,
|
||||
def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_values=False,
|
||||
company=None, reset_period_on_fy_change=True):
|
||||
"""Get a list of dict {"from_date": from_date, "to_date": to_date, "key": key, "label": label}
|
||||
Periodicity can be (Yearly, Quarterly, Monthly)"""
|
||||
@@ -85,8 +85,8 @@ def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_v
|
||||
return period_list
|
||||
|
||||
def get_fiscal_year_data(from_fiscal_year, to_fiscal_year):
|
||||
fiscal_year = frappe.db.sql("""select min(year_start_date) as year_start_date,
|
||||
max(year_end_date) as year_end_date from `tabFiscal Year` where
|
||||
fiscal_year = frappe.db.sql("""select min(year_start_date) as year_start_date,
|
||||
max(year_end_date) as year_end_date from `tabFiscal Year` where
|
||||
name between %(from_fiscal_year)s and %(to_fiscal_year)s""",
|
||||
{'from_fiscal_year': from_fiscal_year, 'to_fiscal_year': to_fiscal_year}, as_dict=1)
|
||||
|
||||
@@ -110,7 +110,7 @@ def get_label(periodicity, from_date, to_date):
|
||||
label = formatdate(from_date, "MMM YY") + "-" + formatdate(to_date, "MMM YY")
|
||||
|
||||
return label
|
||||
|
||||
|
||||
def get_data(company, root_type, balance_must_be, period_list, filters=None,
|
||||
accumulated_values=1, only_current_fiscal_year=True, ignore_closing_entries=False,
|
||||
ignore_accumulated_values_for_fy=False):
|
||||
@@ -119,16 +119,16 @@ def get_data(company, root_type, balance_must_be, period_list, filters=None,
|
||||
return None
|
||||
|
||||
accounts, accounts_by_name, parent_children_map = filter_accounts(accounts)
|
||||
|
||||
|
||||
company_currency = frappe.db.get_value("Company", company, "default_currency")
|
||||
|
||||
gl_entries_by_account = {}
|
||||
for root in frappe.db.sql("""select lft, rgt from tabAccount
|
||||
where root_type=%s and ifnull(parent_account, '') = ''""", root_type, as_dict=1):
|
||||
|
||||
set_gl_entries_by_account(company,
|
||||
|
||||
set_gl_entries_by_account(company,
|
||||
period_list[0]["year_start_date"] if only_current_fiscal_year else None,
|
||||
period_list[-1]["to_date"],
|
||||
period_list[-1]["to_date"],
|
||||
root.lft, root.rgt, filters,
|
||||
gl_entries_by_account, ignore_closing_entries=ignore_closing_entries)
|
||||
|
||||
@@ -136,7 +136,7 @@ def get_data(company, root_type, balance_must_be, period_list, filters=None,
|
||||
accumulate_values_into_parents(accounts, accounts_by_name, period_list, accumulated_values)
|
||||
out = prepare_data(accounts, balance_must_be, period_list, company_currency)
|
||||
out = filter_out_zero_value_rows(out, parent_children_map)
|
||||
|
||||
|
||||
if out:
|
||||
add_total_row(out, root_type, balance_must_be, period_list, company_currency)
|
||||
|
||||
@@ -151,13 +151,13 @@ def calculate_values(accounts_by_name, gl_entries_by_account, period_list, accum
|
||||
|
||||
if entry.posting_date <= period.to_date:
|
||||
if (accumulated_values or entry.posting_date >= period.from_date) and \
|
||||
(not ignore_accumulated_values_for_fy or
|
||||
(not ignore_accumulated_values_for_fy or
|
||||
entry.fiscal_year == period.to_date_fiscal_year):
|
||||
d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit)
|
||||
|
||||
if entry.posting_date < period_list[0].year_start_date:
|
||||
d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit)
|
||||
|
||||
|
||||
def accumulate_values_into_parents(accounts, accounts_by_name, period_list, accumulated_values):
|
||||
"""accumulate children's values in parent accounts"""
|
||||
for d in reversed(accounts):
|
||||
@@ -165,7 +165,7 @@ def accumulate_values_into_parents(accounts, accounts_by_name, period_list, accu
|
||||
for period in period_list:
|
||||
accounts_by_name[d.parent_account][period.key] = \
|
||||
accounts_by_name[d.parent_account].get(period.key, 0.0) + d.get(period.key, 0.0)
|
||||
|
||||
|
||||
accounts_by_name[d.parent_account]["opening_balance"] = \
|
||||
accounts_by_name[d.parent_account].get("opening_balance", 0.0) + d.get("opening_balance", 0.0)
|
||||
|
||||
@@ -173,15 +173,15 @@ def prepare_data(accounts, balance_must_be, period_list, company_currency):
|
||||
data = []
|
||||
year_start_date = period_list[0]["year_start_date"].strftime("%Y-%m-%d")
|
||||
year_end_date = period_list[-1]["year_end_date"].strftime("%Y-%m-%d")
|
||||
|
||||
|
||||
for d in accounts:
|
||||
# add to output
|
||||
has_value = False
|
||||
total = 0
|
||||
row = frappe._dict({
|
||||
"account_name": d.account_name,
|
||||
"account": d.name,
|
||||
"parent_account": d.parent_account,
|
||||
"account_name": _(d.account_name),
|
||||
"account": _(d.name),
|
||||
"parent_account": _(d.parent_account),
|
||||
"indent": flt(d.indent),
|
||||
"year_start_date": year_start_date,
|
||||
"year_end_date": year_end_date,
|
||||
@@ -192,7 +192,7 @@ def prepare_data(accounts, balance_must_be, period_list, company_currency):
|
||||
if d.get(period.key) and balance_must_be=="Credit":
|
||||
# change sign based on Debit or Credit, since calculation is done using (debit - credit)
|
||||
d[period.key] *= -1
|
||||
|
||||
|
||||
row[period.key] = flt(d.get(period.key, 0.0), 3)
|
||||
|
||||
if abs(row[period.key]) >= 0.005:
|
||||
@@ -203,9 +203,9 @@ def prepare_data(accounts, balance_must_be, period_list, company_currency):
|
||||
row["has_value"] = has_value
|
||||
row["total"] = total
|
||||
data.append(row)
|
||||
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def filter_out_zero_value_rows(data, parent_children_map, show_zero_values=False):
|
||||
data_with_value = []
|
||||
for d in data:
|
||||
@@ -224,8 +224,8 @@ def filter_out_zero_value_rows(data, parent_children_map, show_zero_values=False
|
||||
|
||||
def add_total_row(out, root_type, balance_must_be, period_list, company_currency):
|
||||
total_row = {
|
||||
"account_name": "'" + _("Total {0} ({1})").format(root_type, balance_must_be) + "'",
|
||||
"account": "'" + _("Total {0} ({1})").format(root_type, balance_must_be) + "'",
|
||||
"account_name": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'",
|
||||
"account": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'",
|
||||
"currency": company_currency
|
||||
}
|
||||
|
||||
@@ -235,11 +235,11 @@ def add_total_row(out, root_type, balance_must_be, period_list, company_currency
|
||||
total_row.setdefault(period.key, 0.0)
|
||||
total_row[period.key] += row.get(period.key, 0.0)
|
||||
row[period.key] = ""
|
||||
|
||||
|
||||
total_row.setdefault("total", 0.0)
|
||||
total_row["total"] += flt(row["total"])
|
||||
row["total"] = ""
|
||||
|
||||
|
||||
if total_row.has_key("total"):
|
||||
out.append(total_row)
|
||||
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
{% var letterhead= filters.letter_head || (frappe.get_doc(":Company", filters.company) && frappe.get_doc(":Company", filters.company).default_letter_head) || frappe.defaults.get_default("letter_head"); %}
|
||||
{% if(letterhead) { %}
|
||||
<div style="margin-bottom: 7px;" class="text-center">
|
||||
{%= frappe.boot.letter_heads[letterhead].header %}
|
||||
</div>
|
||||
{% } %}
|
||||
<h2 class="text-center">{%= __("Statement of Account") %}</h2>
|
||||
<h4 class="text-center">
|
||||
{% if (filters.party_name) { %}
|
||||
|
||||
@@ -278,7 +278,7 @@ class GrossProfitGenerator(object):
|
||||
inner join `tabSales Invoice Item` on `tabSales Invoice Item`.parent = `tabSales Invoice`.name
|
||||
{sales_team_table}
|
||||
where
|
||||
`tabSales Invoice`.docstatus = 1 and `tabSales Invoice`.is_return != 1 {conditions} {match_cond}
|
||||
`tabSales Invoice`.docstatus = 1 {conditions} {match_cond}
|
||||
order by
|
||||
`tabSales Invoice`.posting_date desc, `tabSales Invoice`.posting_time desc"""
|
||||
.format(conditions=conditions, sales_person_cols=sales_person_cols,
|
||||
|
||||
@@ -24,7 +24,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
||||
"fieldtype": "Data",
|
||||
"width": 80
|
||||
})
|
||||
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
|
||||
company_currency = frappe.db.get_value("Company", filters.get("company"), "default_currency")
|
||||
mode_of_payments = get_mode_of_payments(set([d.parent for d in item_list]))
|
||||
|
||||
data = []
|
||||
|
||||
@@ -26,7 +26,7 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
|
||||
invoice_so_dn_map = get_invoice_so_dn_map(invoice_list)
|
||||
customers = list(set([inv.customer for inv in invoice_list]))
|
||||
customer_map = get_customer_details(customers)
|
||||
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
|
||||
company_currency = frappe.db.get_value("Company", filters.get("company"), "default_currency")
|
||||
mode_of_payments = get_mode_of_payments([inv.name for inv in invoice_list])
|
||||
|
||||
data = []
|
||||
|
||||
@@ -270,6 +270,9 @@ def make_purchase_receipt(source_name, target_doc=None):
|
||||
doc = get_mapped_doc("Purchase Order", source_name, {
|
||||
"Purchase Order": {
|
||||
"doctype": "Purchase Receipt",
|
||||
"field_map": {
|
||||
"per_billed": "per_billed"
|
||||
},
|
||||
"validation": {
|
||||
"docstatus": ["=", 1],
|
||||
}
|
||||
|
||||
@@ -11,3 +11,6 @@ from erpnext.controllers.print_settings import print_settings_for_item_table
|
||||
class PurchaseOrderItem(Document):
|
||||
def __setup__(self):
|
||||
print_settings_for_item_table(self)
|
||||
|
||||
def on_doctype_update():
|
||||
frappe.db.add_index("Purchase Order Item", ["item_code", "warehouse"])
|
||||
@@ -3,8 +3,10 @@
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
import frappe
|
||||
from erpnext.templates.pages.rfq import check_supplier_has_docname_access
|
||||
from frappe.utils import nowdate
|
||||
|
||||
class TestRequestforQuotation(unittest.TestCase):
|
||||
@@ -28,6 +30,31 @@ class TestRequestforQuotation(unittest.TestCase):
|
||||
self.assertEquals(sq1.get('items')[0].item_code, "_Test Item")
|
||||
self.assertEquals(sq1.get('items')[0].qty, 5)
|
||||
|
||||
def test_make_supplier_quotation_with_special_characters(self):
|
||||
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import make_supplier_quotation
|
||||
|
||||
frappe.delete_doc_if_exists("Supplier", "_Test Supplier '1", force=1)
|
||||
supplier = frappe.new_doc("Supplier")
|
||||
supplier.supplier_name = "_Test Supplier '1"
|
||||
supplier.supplier_type = "_Test Supplier Type"
|
||||
supplier.insert()
|
||||
|
||||
rfq = make_request_for_quotation(supplier_wt_appos)
|
||||
|
||||
sq = make_supplier_quotation(rfq.name, supplier_wt_appos[0].get("supplier"))
|
||||
sq.submit()
|
||||
|
||||
frappe.form_dict = frappe.local("form_dict")
|
||||
frappe.form_dict.name = rfq.name
|
||||
|
||||
self.assertEqual(
|
||||
check_supplier_has_docname_access(supplier_wt_appos[0].get('supplier')),
|
||||
True
|
||||
)
|
||||
|
||||
# reset form_dict
|
||||
frappe.form_dict.name = None
|
||||
|
||||
def test_make_supplier_quotation_from_portal(self):
|
||||
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import create_supplier_quotation
|
||||
rfq = make_request_for_quotation()
|
||||
@@ -44,8 +71,11 @@ class TestRequestforQuotation(unittest.TestCase):
|
||||
self.assertEquals(supplier_quotation_doc.get('items')[0].amount, 500)
|
||||
|
||||
|
||||
def make_request_for_quotation():
|
||||
supplier_data = get_supplier_data()
|
||||
def make_request_for_quotation(supplier_data=None):
|
||||
"""
|
||||
:param supplier_data: List containing supplier data
|
||||
"""
|
||||
supplier_data = supplier_data if supplier_data else get_supplier_data()
|
||||
rfq = frappe.new_doc('Request for Quotation')
|
||||
rfq.transaction_date = nowdate()
|
||||
rfq.status = 'Draft'
|
||||
@@ -77,3 +107,8 @@ def get_supplier_data():
|
||||
"supplier": "_Test Supplier 1",
|
||||
"supplier_name": "_Test Supplier 1"
|
||||
}]
|
||||
|
||||
supplier_wt_appos = [{
|
||||
"supplier": "_Test Supplier '1",
|
||||
"supplier_name": "_Test Supplier '1",
|
||||
}]
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
frappe.listview_settings['Supplier'] = {
|
||||
add_fields: ["supplier_name", "supplier_type"],
|
||||
add_fields: ["supplier_name", "supplier_type", "image"],
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "hash",
|
||||
@@ -13,6 +14,7 @@
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
@@ -44,6 +46,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -73,34 +76,7 @@
|
||||
"unique": 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,
|
||||
@@ -131,6 +107,66 @@
|
||||
"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,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
@@ -160,6 +196,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -192,6 +229,7 @@
|
||||
"width": "300px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -219,6 +257,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -248,6 +287,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -278,6 +318,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -306,6 +347,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
@@ -338,6 +380,7 @@
|
||||
"width": "60px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -368,6 +411,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -397,6 +441,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -426,6 +471,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -453,6 +499,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -486,6 +533,7 @@
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -515,6 +563,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -544,6 +593,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -571,6 +621,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
@@ -602,6 +653,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -633,6 +685,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -660,6 +713,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -694,6 +748,7 @@
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -725,6 +780,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -754,6 +810,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -782,6 +839,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -811,6 +869,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -841,6 +900,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -869,6 +929,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -899,6 +960,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -929,6 +991,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -957,6 +1020,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -988,6 +1052,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1017,6 +1082,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1047,6 +1113,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1080,6 +1147,7 @@
|
||||
"width": "120px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1110,6 +1178,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1137,6 +1206,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1167,6 +1237,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1196,6 +1267,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1227,6 +1299,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1259,6 +1332,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1290,6 +1364,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1318,6 +1393,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1347,6 +1423,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1377,17 +1454,17 @@
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-02-17 16:43:59.582188",
|
||||
"modified": "2017-07-10 09:08:52.015387",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Quotation Item",
|
||||
|
||||
8
erpnext/change_log/v8/v8_3_0.md
Normal file
@@ -0,0 +1,8 @@
|
||||
### Production Order Enahancement
|
||||
- Show required items child table.
|
||||
- Source warehouse for each Raw Materials, in Production Order Item and BOM Item table.
|
||||
- Group warehouse allowed for Source and WIP warehouse.
|
||||
### GST Tax Invoice Print Format
|
||||
- Added print format to show tax(GST) breakup.
|
||||
- Total Stock Summary report.
|
||||
- Include Search Fields in Customer Query.
|
||||
@@ -137,7 +137,14 @@ def get_data():
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Assessment Result Tool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
"name": "Course wise Assessment Report",
|
||||
"doctype": "Assessment Result"
|
||||
},
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -49,6 +49,12 @@ def get_data():
|
||||
"doctype": "Issue",
|
||||
"is_query_report": True
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"name": "Support Hours",
|
||||
"doctype": "Issue",
|
||||
"is_query_report": True
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
@@ -160,6 +160,7 @@ class AccountsController(TransactionBase):
|
||||
def set_missing_item_details(self, for_validate=False):
|
||||
"""set missing item values"""
|
||||
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"):
|
||||
parent_dict = {}
|
||||
@@ -196,7 +197,7 @@ class AccountsController(TransactionBase):
|
||||
|
||||
elif fieldname == "serial_no":
|
||||
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)
|
||||
|
||||
elif fieldname == "conversion_factor" and not item.get("conversion_factor"):
|
||||
|
||||
@@ -255,7 +255,7 @@ class BuyingController(StockController):
|
||||
|
||||
def get_items_from_bom(self, item_code, bom):
|
||||
bom_items = frappe.db.sql("""select t2.item_code,
|
||||
t2.qty / ifnull(t1.quantity, 1) as qty_consumed_per_unit,
|
||||
t2.stock_qty / ifnull(t1.quantity, 1) as qty_consumed_per_unit,
|
||||
t2.rate, t2.stock_uom, t2.name, t2.description
|
||||
from `tabBOM` t1, `tabBOM Item` t2, tabItem t3
|
||||
where t2.parent = t1.name and t1.item = %s
|
||||
|
||||
@@ -169,6 +169,7 @@ def create_variant(item, args):
|
||||
|
||||
return variant
|
||||
|
||||
|
||||
def copy_attributes_to_variant(item, variant):
|
||||
from frappe.model import no_value_fields
|
||||
|
||||
@@ -181,8 +182,9 @@ def copy_attributes_to_variant(item, variant):
|
||||
exclude_fields += ['manufacturer', 'manufacturer_part_no']
|
||||
|
||||
for field in item.meta.fields:
|
||||
if field.fieldtype not in no_value_fields and (not field.no_copy)\
|
||||
and field.fieldname not in exclude_fields:
|
||||
# "Table" is part of `no_value_field` but we shouldn't ignore tables
|
||||
if (field.fieldtype == 'Table' or field.fieldtype not in no_value_fields) \
|
||||
and (not field.no_copy) and field.fieldname not in exclude_fields:
|
||||
if variant.get(field.fieldname) != item.get(field.fieldname):
|
||||
variant.set(field.fieldname, item.get(field.fieldname))
|
||||
variant.variant_of = item.name
|
||||
|
||||
@@ -68,14 +68,17 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
fields = ["name", "customer_name", "customer_group", "territory"]
|
||||
|
||||
meta = frappe.get_meta("Customer")
|
||||
fields = fields + [f for f in meta.get_search_fields() if not f in fields]
|
||||
searchfields = meta.get_search_fields()
|
||||
searchfields = searchfields + [f for f in [searchfield or "name", "customer_name"] \
|
||||
if not f in searchfields]
|
||||
fields = fields + [f for f in searchfields if not f in fields]
|
||||
|
||||
fields = ", ".join(fields)
|
||||
searchfields = " or ".join([field + " like %(txt)s" for field in searchfields])
|
||||
|
||||
return frappe.db.sql("""select {fields} from `tabCustomer`
|
||||
where docstatus < 2
|
||||
and ({key} like %(txt)s
|
||||
or customer_name like %(txt)s) and disabled=0
|
||||
and ({scond}) and disabled=0
|
||||
{mcond}
|
||||
order by
|
||||
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
|
||||
@@ -84,7 +87,7 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
name, customer_name
|
||||
limit %(start)s, %(page_len)s""".format(**{
|
||||
"fields": fields,
|
||||
"key": searchfield,
|
||||
"scond": searchfields,
|
||||
"mcond": get_match_cond(doctype)
|
||||
}), {
|
||||
'txt': "%%%s%%" % txt,
|
||||
|
||||
@@ -24,6 +24,9 @@ class calculate_taxes_and_totals(object):
|
||||
|
||||
if self.doc.doctype in ["Sales Invoice", "Purchase Invoice"]:
|
||||
self.calculate_total_advance()
|
||||
|
||||
if self.doc.meta.get_field("other_charges_calculation"):
|
||||
self.set_item_wise_tax_breakup()
|
||||
|
||||
def _calculate(self):
|
||||
self.calculate_item_values()
|
||||
@@ -504,3 +507,74 @@ class calculate_taxes_and_totals(object):
|
||||
rate_with_margin = flt(item.price_list_rate) + flt(margin_value)
|
||||
|
||||
return rate_with_margin
|
||||
|
||||
def set_item_wise_tax_breakup(self):
|
||||
if not self.doc.taxes:
|
||||
return
|
||||
frappe.flags.company = self.doc.company
|
||||
|
||||
# get headers
|
||||
tax_accounts = list(set([d.description for d in self.doc.taxes]))
|
||||
headers = get_itemised_tax_breakup_header(self.doc.doctype + " Item", tax_accounts)
|
||||
|
||||
# get tax breakup data
|
||||
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(self.doc)
|
||||
|
||||
frappe.flags.company = None
|
||||
|
||||
self.doc.other_charges_calculation = frappe.render_template(
|
||||
"templates/includes/itemised_tax_breakup.html", dict(
|
||||
headers=headers,
|
||||
itemised_tax=itemised_tax,
|
||||
itemised_taxable_amount=itemised_taxable_amount,
|
||||
tax_accounts=tax_accounts,
|
||||
company_currency=erpnext.get_company_currency(self.doc.company)
|
||||
)
|
||||
)
|
||||
|
||||
@erpnext.allow_regional
|
||||
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
|
||||
return [_("Item"), _("Taxable Amount")] + tax_accounts
|
||||
|
||||
@erpnext.allow_regional
|
||||
def get_itemised_tax_breakup_data(doc):
|
||||
itemised_tax = get_itemised_tax(doc.taxes)
|
||||
|
||||
itemised_taxable_amount = get_itemised_taxable_amount(doc.items)
|
||||
|
||||
return itemised_tax, itemised_taxable_amount
|
||||
|
||||
def get_itemised_tax(taxes):
|
||||
itemised_tax = {}
|
||||
for tax in taxes:
|
||||
tax_amount_precision = tax.precision("tax_amount")
|
||||
tax_rate_precision = tax.precision("rate")
|
||||
|
||||
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())
|
||||
|
||||
if isinstance(tax_data, list) and tax_data[0]:
|
||||
precision = tax_amount_precision if tax.charge_type == "Actual" else tax_rate_precision
|
||||
|
||||
itemised_tax[item_code][tax.description] = frappe._dict(dict(
|
||||
tax_rate=flt(tax_data[0], precision),
|
||||
tax_amount=flt(tax_data[1], tax_amount_precision)
|
||||
))
|
||||
else:
|
||||
itemised_tax[item_code][tax.description] = frappe._dict(dict(
|
||||
tax_rate=flt(tax_data, tax_rate_precision),
|
||||
tax_amount=0.0
|
||||
))
|
||||
|
||||
return itemised_tax
|
||||
|
||||
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
|
||||
58
erpnext/controllers/tests/test_item_variant.py
Normal file
@@ -0,0 +1,58 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import json
|
||||
import unittest
|
||||
|
||||
from erpnext.controllers.item_variant import copy_attributes_to_variant, make_variant_item_code
|
||||
|
||||
# python 3 compatibility stuff
|
||||
try:
|
||||
unicode = unicode
|
||||
except NameError:
|
||||
# Python 3
|
||||
basestring = (str, bytes)
|
||||
else:
|
||||
# Python 2
|
||||
basestring = basestring
|
||||
|
||||
|
||||
def create_variant_with_tables(item, args):
|
||||
if isinstance(args, basestring):
|
||||
args = json.loads(args)
|
||||
|
||||
template = frappe.get_doc("Item", item)
|
||||
template.quality_parameters.append({
|
||||
"specification": "Moisture",
|
||||
"value": "< 5%",
|
||||
})
|
||||
variant = frappe.new_doc("Item")
|
||||
variant.variant_based_on = 'Item Attribute'
|
||||
variant_attributes = []
|
||||
|
||||
for d in template.attributes:
|
||||
variant_attributes.append({
|
||||
"attribute": d.attribute,
|
||||
"attribute_value": args.get(d.attribute)
|
||||
})
|
||||
|
||||
variant.set("attributes", variant_attributes)
|
||||
copy_attributes_to_variant(template, variant)
|
||||
make_variant_item_code(template.item_code, template.item_name, variant)
|
||||
|
||||
return variant
|
||||
|
||||
|
||||
def make_item_variant():
|
||||
frappe.delete_doc_if_exists("Item", "_Test Variant Item-S", force=1)
|
||||
variant = create_variant_with_tables("_Test Variant Item", '{"Test Size": "Small"}')
|
||||
variant.item_code = "_Test Variant Item-S"
|
||||
variant.item_name = "_Test Variant Item-S"
|
||||
variant.save()
|
||||
return variant
|
||||
|
||||
|
||||
class TestItemVariant(unittest.TestCase):
|
||||
def test_tables_in_template_copied_to_variant(self):
|
||||
variant = make_item_variant()
|
||||
self.assertNotEqual(variant.get("quality_parameters"), [])
|
||||
@@ -56,7 +56,7 @@
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Series",
|
||||
"length": 0,
|
||||
@@ -88,7 +88,7 @@
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Opportunity From",
|
||||
"length": 0,
|
||||
@@ -277,8 +277,8 @@
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Opportunity Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@@ -310,7 +310,7 @@
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
@@ -1189,7 +1189,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-06-13 14:29:07.077697",
|
||||
"modified": "2017-07-10 15:29:23.921967",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Opportunity",
|
||||
|
||||
@@ -272,4 +272,6 @@ def auto_close_opportunity():
|
||||
for opportunity in opportunities:
|
||||
doc = frappe.get_doc("Opportunity", opportunity.get("name"))
|
||||
doc.status = "Closed"
|
||||
doc.save(ignore_permissions=True)
|
||||
doc.flags.ignore_permissions = True
|
||||
doc.flags.ignore_mandatory = True
|
||||
doc.save()
|
||||
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 261 KiB |
0
erpnext/docs/assets/img/regional/__init__.py
Normal file
0
erpnext/docs/assets/img/regional/india/__init__.py
Normal file
|
After Width: | Height: | Size: 215 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 109 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 |
BIN
erpnext/docs/assets/img/setup/email/email-alert-set-property.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
BIN
erpnext/docs/assets/img/setup/stock-reco-data.png
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
erpnext/docs/assets/img/setup/stock-reco-ledger.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
erpnext/docs/assets/img/setup/stock-reco-upload.gif
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 291 KiB After Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 211 KiB After Width: | Height: | Size: 199 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 78 KiB |
BIN
erpnext/docs/assets/img/support/support_hours.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 28 KiB |
@@ -640,8 +640,8 @@ attach them to the start of each source file to most effectively state
|
||||
the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.</p>
|
||||
|
||||
<pre><code> <one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
<pre><code> <one line="" to="" give="" the="" program's="" name="" and="" a="" brief="" idea="" of="" what="" it="" does.="">
|
||||
Copyright (C) <year> <name of="" author="">
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -38,15 +38,13 @@ Hinweis: Stellen Sie sicher, dass im Abschnitt "Weitere Informationen" "Ist Erö
|
||||
|
||||
Vervollständigen Sie die Buchungssätze auf der Soll- und Haben-Seite.
|
||||
|
||||

|
||||
<img class="screenshot" alt="Opening Account" src="{{docs_base_url}}/assets/img/accounts/opening-6.png">
|
||||
|
||||
Um einen Eröffnungsstand einzupflegen, erstellen Sie einen Buchungssatz für ein Konto oder eine Gruppe von Konten.
|
||||
|
||||
Beispiel: Wenn Sie die Kontenstände von drei Bankkonten einpflegen möchten, dann erstellen Sie Buchungssätze der folgenden Art und Weise:
|
||||
|
||||

|
||||
|
||||

|
||||
<img class="screenshot" alt="Opening Account" src="{{docs_base_url}}/assets/img/accounts/opening-3.png">
|
||||
|
||||
Um einen Ausgleich herzustellen, wird ein temporäres Konto für Vermögen und Verbindlichkeiten verwendet. Wenn Sie einen Anfangsbestand in einem Verbindlichkeitenkonto einpflegen, können Sie zum Ausgleich ein temporäres Vermögenskonto verwenden.
|
||||
|
||||
@@ -61,7 +59,8 @@ Sie können zwei Eröffnungsbuchungssätze erstellen:
|
||||
|
||||
Wenn Sie die Buchungen erstellt haben, schaut der Bericht zur Probebilanz in etwa wie folgt aus:
|
||||
|
||||

|
||||
<img class="screenshot" alt="Probebilanz" src="{{docs_base_url}}/assets/img/accounts/opening-4.png">
|
||||
|
||||
|
||||
### Offene Rechnungen
|
||||
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
|
||||
Dieses Diagramm stellt dar, wie ERPNext die Informationen und Vorgänge in Ihrem Unternehmen über Schlüsselfunktionen nachverfolgt. Dieses Diagramm gibt nicht alle Funktionalitäten von ERPNext wieder.
|
||||
|
||||

|
||||
|
||||
<img class="screenshot" alt="Hohe Auflösung" src="{{docs_base_url}}/assets/img/setup/overview.png">
|
||||
|
||||
[Hohe Auflösung]({{docs_base_url}}/assets/old_images/erpnext/overview.png)
|
||||
|
||||
_Anmerkung: Nicht alle Schritte sind zwingend erforderlich. ERPNext erlaubt es Ihnen nach eigenem Gutdünken Schritte auszulassen, wenn Sie den Prozess vereinfachen wollen._
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ Wenn Sie bei Ihrer Tätigkeit bestimmte Prozesse an eine Drittpartei, bei der Si
|
||||
2. Erstellen Sie ein Lager für den Lieferanten, damit Sie die übergebenen Artikel nachverfolgen können (möglicherweise geben Sie ja Artikel im Wert einer Monatslieferung außer Haus).
|
||||
3. Stellen Sie für den bearbeiteten Artikel und der Artikelvorlage den Punkt "Ist Fremdvergabe" auf JA ein.
|
||||
|
||||

|
||||
<img class="screenshot" alt="Fremdvergabe" src="{{docs_base_url}}/assets/img/manufacturing/subcontract.png">
|
||||
|
||||
|
||||
**Schritt 1:** Erstellen Sie für den bearbeiteten Artikel eine Stückliste, die den unbearbeiteten Artikel als Unterartikel enthält. Beispiel: Wenn Sie einen Stift herstellen, wird der bearbeitete Stift mit der Stückliste benannt, wbei der Tintentank, der Knopf und andere Artikel, die in die Fertigung eingehen als Unterartikel verwaltet werden.
|
||||
|
||||
|
||||
@@ -15,5 +15,6 @@ third-party-backups
|
||||
workflows
|
||||
bar-code
|
||||
company-setup
|
||||
setting-company-sales-goal
|
||||
calculate-incentive-for-sales-team
|
||||
articles
|
||||
|
||||
@@ -27,7 +27,7 @@ Sie sollten sich an eine spezielle Vorlage eines Tabellenblattes halten um den B
|
||||
|
||||
#### Schritt 2: Geben Sie Daten in die CSV-Datei ein.
|
||||
|
||||

|
||||
<img class="screenshot" alt="Bestandsabgleich" src="{{docs_base_url}}/assets/img/setup/stock-reco-data.png">
|
||||
|
||||
Das CSV-Format beachtet Groß- und Kleinschreibung. Verändern Sie nicht die Kopfbezeichnungen, die in der Vorlage vordefiniert wurden. In den Spalten "Artikelnummer" und "Lager" geben Sie bitte die richtige Artikelnummer und das Lager ein, so wie es in ERPNext bezeichnet wird. Für die Menge geben Sie den Lagerbestand, den Sie für diesen Artikel erfassen wollen, in einem bestimmten Lager ein. Wenn Sie die Menge oder den wertmäßigen Betrag eines Artikels nicht ändern wollen, dann lassen Sie den Eintrag leer.
|
||||
Anmerkung: Geben Sie keine "0" ein, wenn sie die Menge oder den wertmäßigen Betrag nicht ändern wollen. Sonst kalkuliert das System eine Menge von "0". Lassen Sie also das Feld leer!
|
||||
@@ -52,11 +52,12 @@ Notiz: Wenn Sie die bewerteten Beträge eines Artikels eingeben, können Sie zum
|
||||
|
||||
#### Schritt 4: Überprüfen Sie die Daten zum Bestandsabgleich
|
||||
|
||||

|
||||
<img class="screenshot" alt="Bestandsabgleich Überprüfung" src="{{docs_base_url}}/assets/img/setup/stock-reco-upload.gif">
|
||||
|
||||
### Bericht zum Lagerbuch
|
||||
|
||||

|
||||
<img class="screenshot" alt="Bestandsabgleich" src="{{docs_base_url}}/assets/img/setup/stock-reco-ledger.png">
|
||||
|
||||
|
||||
##### So arbeitet der Bestandsabgleich
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ Unten Sehen Sie ein Beispiel eines Worklflows.
|
||||
|
||||
Wenn ein Benutzer einen Urlaub beantragt, dann wird seine Anfrage an die Personalabteilung weiter geleitet. Die Personalabteilung, repräsentiert durch einen Mitarbeiter der Personalabteilung, wird diese Anfrage dann entweder genehmigen oder ablehnen. Wenn dieser Prozess abgeschlossen ist, dann bekommt der Vorgesetzte des Benutzers (der Urlaubsgenehmiger) eine Mitteilung, dass die Personalabteilung den Antrag genehmigt oder abgelehnt hat. Der Vorgesetzte, der die genehmigende Instanz ist, wird dann den Antrag entweder genehmigen oder ablehnen. Dementsprechend bekommt der Benutzer dann eine Genehmigung oder eine Ablehnung.
|
||||
|
||||

|
||||
<img class="screenshot" alt="Workflow" src="{{docs_base_url}}/assets/img/setup/workflow-leave-fl.jpg">
|
||||
|
||||
Um einen Workflow und Übergangsregeln zu erstellen, gehen Sie zu:
|
||||
|
||||
@@ -37,14 +37,14 @@ Gehen Sie in das Modul Personalwesen und klicken Sie auf Urlaubsantrag. Beantrag
|
||||
|
||||
Wenn ein Urlaubsantrag übertragen wird, steht der Status in der Ecke der rechten Seite auf "Beantragt".
|
||||
|
||||

|
||||
<img class="screenshot" alt="Workflow" src="{{docs_base_url}}/assets/img/setup/workflow-3.png">
|
||||
|
||||
Wenn sich ein Mitarbeiter der Personalabteilung anmeldet, dann kann er den Antrag genehmigen oder ablehnen. Wenn eine Genehmigung erfolgt, wechselt der Status in der rechten Ecke zu "Genehmigt". Es wird jedoch ein blaues Informationssymbol angezeigt, welches aussagt, dass der Urlaubsantrag noch anhängig ist.
|
||||
|
||||

|
||||
<img class="screenshot" alt="Workflow" src="{{docs_base_url}}/assets/img/setup/workflow-4.png">
|
||||
|
||||
Wenn der Urlaubsgenehmiger die Seite mit den Urlaubsanträgen öffnet, kann er den Status von "Genehmigt" auf "Abgelehnt" ändern.
|
||||
|
||||

|
||||
<img class="screenshot" alt="Workflow" src="{{docs_base_url}}/assets/img/setup/workflow-5.png">
|
||||
|
||||
{next}
|
||||
|
||||
@@ -6,7 +6,7 @@ functions. This diagram does not cover all the features of ERPNext.
|
||||

|
||||
|
||||
|
||||
[Full Resolution]({{docs_base_url}}/assets/old_images/erpnext/overview.png)
|
||||
<img class="screenshot" alt="Workflow" src="{{docs_base_url}}/assets/img/setup/overview.png">
|
||||
|
||||
_Note: Not all of the steps are mandatory. ERPNext allows you to freely skip
|
||||
steps if you want to simplify the process._
|
||||
|
||||
@@ -17,9 +17,15 @@ by:
|
||||
|
||||
* Select the Item to be produced.
|
||||
* The default BOM for that item will be fetched by the system. You can also change BOM.
|
||||
* Enter the Qty to manufacture.
|
||||
* If the selected BOM has operartion mentioned in it, the system shall fetch all operations from BOM.
|
||||
* Mention the Planned Start Date (an Estimated Date at which you want the Production to begin.)
|
||||
* Select Warehouses. Work-in-Progress Warehouse is where your Items will be transferred when you begin production and Target Warehouse is where you store finished Items before they are shipped.
|
||||
* Select Warehouses:
|
||||
* Source Warehouses: The warehouse where you store your raw materials. Each required item can have separate source warehouse. Group warehouse also can be selected as source warehouse. On submission of Production Order, the raw mateirals will be reserved in these warehouses for production usage.
|
||||
* Work-in-Progress Warehouse: The warehouse where your Items will be transferred when you begin production. Group Warehouse can also be selected as Work-in-Progress warehouse.
|
||||
* Target Warehouse: The warehouse where you store finished Items before they are shipped.
|
||||
* Scrap Warehouse: Scrap Items will be stored in this warehouse.
|
||||
* Required Items: All the required items (raw materials) will be fetched from BOM and populated in this table. Here you can also change the default source warehouse for any item. And during the production, you can track transferred raw materials from this table.
|
||||
|
||||
> Note : You can save a Production Order without selecting the warehouses, but warehouses are mandatory for submitting a Production Order
|
||||
|
||||
|
||||
0
erpnext/docs/user/manual/en/regional/__init__.py
Normal file
@@ -4,7 +4,7 @@ You can send email reminders to your Customers and Suppliers so that they can di
|
||||
|
||||
To send GSTIN Reminders, you can either open the Customer / Supplier record or **GST Settings**
|
||||
|
||||
<img class="screenshot" alt="GST Settings" src="{{docs_base_url}}/assets/img/regional/india/gstin-settings.png">
|
||||
<img class="screenshot" alt="GST Settings" src="{{docs_base_url}}/assets/img/regional/india/gst-settings.png">
|
||||
|
||||
Here you can click on the "Send GSTIN Update Reminders" button to send email reminders to all your customers
|
||||
|
||||
|
||||
@@ -14,6 +14,13 @@ Go to the Company master and add the GSTIN to your default address.
|
||||
|
||||
<img class="screenshot" alt="GST in Company" src="{{docs_base_url}}/assets/img/regional/india/gstin-company.gif">
|
||||
|
||||
**Include GSTIN number in the Address Template**
|
||||
|
||||
Open Address Template record for India, add GSTIN number and State Code there if not exists.
|
||||
|
||||
<img class="screenshot" alt="GST in Company" src="{{docs_base_url}}/assets/img/regional/india/address-template-gstin.png">
|
||||
|
||||
|
||||
### 2. Setting up HSN Codes
|
||||
|
||||
According to the GST Law, your itemised invoices must contain the HSN Code related to that Item. ERPNext comes pre-installed with all 12,000+ HSN Codes so that you can easily select the relevant HSN Code in your Item
|
||||
@@ -54,6 +61,12 @@ For **Sales Invoice**,
|
||||
|
||||
<img class="screenshot" alt="GST Invoice" src="{{docs_base_url}}/assets/img/regional/india/gst-invoice.gif">
|
||||
|
||||
### 6. Print GST Tax Invoice
|
||||
|
||||
To print Tax Invoice as per GSTN guidelines, please select **GST Tax Invoice** print format. This print format includes company address, GSTIN numbers, HSN/SAC Code and item-wise tax breakup. And while printing select correct value of Invoice Copy field, to mention whether it is for the Customer, Supplier or Transporter.
|
||||
|
||||
<img class="screenshot" alt="Sample GST Tax Invoice" src="{{docs_base_url}}/assets/img/regional/india/sample-gst-tax-invoice.png">
|
||||
|
||||
### Reports
|
||||
|
||||
ERPNext comes with most of your reports you need to prepare your GST Returns. Go to Accounts > GST India head for the list.
|
||||
|
||||
@@ -91,5 +91,5 @@ To setup Email Digests, go to:
|
||||
|
||||
#### Figure 4: Set up Email Digest
|
||||
|
||||

|
||||
<img class="screenshot" alt="Email Digest" src="{{docs_base_url}}/assets/img/setup/email/email-digest.png">
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ Email alerts allow you to set conditions according to the field data in your doc
|
||||
|
||||
The above example will send an Email Alert when a Task is saved with the status "Open" and the Expected End Date for the Task is the date on or before the date on which it was saved on.
|
||||
|
||||
|
||||
### Setting a Message
|
||||
|
||||
You can use both Jinja Tags (`{% raw %}{{ doc.[field_name] }}{% endraw %}`) and HTML tags in the message textbox.
|
||||
@@ -64,6 +65,17 @@ You can use both Jinja Tags (`{% raw %}{{ doc.[field_name] }}{% endraw %}`) and
|
||||
|
||||
---
|
||||
|
||||
### Setting a Value after the Alert is Set
|
||||
|
||||
Sometimes to make sure that the email alert is not sent multiple times, you can
|
||||
define a custom property (via Customize Form) like "Email Alert Sent" and then
|
||||
set this property after the alert is sent by setting the **Set Property After Alert**
|
||||
field.
|
||||
|
||||
Then you can use that as a condition in the **Condition** rules to ensure emails are not sent multiple times
|
||||
|
||||
<img class="screenshot" alt="Setting Property in Email Alert" src="{{docs_base_url}}/assets/img/setup/email/email-alert-subject.png">
|
||||
|
||||
### Example
|
||||
|
||||
1. Defining the Criteria
|
||||
|
||||
@@ -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}
|
||||
@@ -31,7 +31,7 @@ A predefined template of an spreadsheet file should be followed for importing it
|
||||
|
||||
#### Step 2: Enter Data in csv file.
|
||||
|
||||

|
||||
<img class="screenshot" alt="Stock Reconciliation" src="{{docs_base_url}}/assets/img/setup/stock-reco-data.png">
|
||||
|
||||
The csv format is case-sensitive. Do not edit the headers which are preset in the template. In the Item Code and Warehouse column, enter exact Item Code and Warehouse as created in your ERPNext account. For quatity, enter stock level you wish to set for that item, in a specific warehouse.
|
||||
|
||||
@@ -59,11 +59,12 @@ report. The report will show you all types of rates.
|
||||
|
||||
#### Step 4: Review the reconciliation data
|
||||
|
||||

|
||||
<img class="screenshot" alt="Stock Reconciliation" src="{{docs_base_url}}/assets/img/setup/stock-reco-upload.gif">
|
||||
|
||||
### Stock Ledger Report
|
||||
|
||||

|
||||
<img class="screenshot" alt="Stock Reconciliation" src="{{docs_base_url}}/assets/img/setup//stock-reco-ledger.png">
|
||||
|
||||
|
||||
**How Stock Reconciliation Works**
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ will get an indication that the HR department has Accepted or Rejected. The
|
||||
Manager, who is the approving authority, will either Approve or Reject this
|
||||
request. Accordingly,the user will get his Approved or Rejected status.
|
||||
|
||||

|
||||
<img class="screenshot" alt="Workflow" src="{{docs_base_url}}/assets/img/setup/workflow-leave-fl.jpg">
|
||||
|
||||
To make this Workflow and transition rules go to :
|
||||
|
||||
@@ -46,15 +46,15 @@ workflow transition step that says from submitted you can cancel.
|
||||
|
||||
When a Leave Application is saved by Employee, the status of the document changes to "Applied"
|
||||
|
||||

|
||||
<img class="screenshot" alt="Workflow" src="{{docs_base_url}}/assets/img/setup/workflow-3.png">
|
||||
|
||||
When the HR User logs in, he can either Approve or Reject. If approved the
|
||||
status of the document changes to "Approved by HR". However, it is yet to be approved by Leave Approver.
|
||||
|
||||

|
||||
<img class="screenshot" alt="Workflow" src="{{docs_base_url}}/assets/img/setup/workflow-4.png">
|
||||
|
||||
When the Leave Approver opens the Leave Application page, he can finally "Approve" or "Reject" the Leave Application.
|
||||
|
||||

|
||||
<img class="screenshot" alt="Workflow" src="{{docs_base_url}}/assets/img/setup/workflow-5.png">
|
||||
|
||||
{next}
|
||||
|
||||
@@ -37,9 +37,9 @@ These numbers help to track individual units or batches of Items which you sell.
|
||||
|
||||
### Re Ordering
|
||||
|
||||
* **Re-order level** suggests the amount of stock balance in the Warehouse.
|
||||
* **Re-order Qty** suggests the amount of stock to be ordered to maintain minimum stock levels.
|
||||
* **Minimum Order Qty** is the minimum quantity for which a Material Request / Purchase Order must be made.
|
||||
***Re-order level** suggests the amount of stock balance in the Warehouse.
|
||||
***Re-order Qty** suggests the amount of stock to be ordered to maintain minimum stock levels.
|
||||
***Minimum Order Qty** is the minimum quantity for which a Material Request / Purchase Order must be made.
|
||||
|
||||
### Item Tax
|
||||
|
||||
@@ -55,6 +55,8 @@ Inspection Criteria: If a Quality Inspection is prepared for this Item, then thi
|
||||
|
||||
### Purchase Details
|
||||
|
||||
<img alt="Item Purchase Details" class="screenshot" src="{{docs_base_url}}/assets/img/stock/item-purchase.png">
|
||||
|
||||
<img class="screenshot" alt="Purchase details" src="{{docs_base_url}}/assets/img/stock/item-purchase.png">
|
||||
|
||||
* **Lead time days:** Lead time days are the number of days required for the Item to reach the warehouse.
|
||||
@@ -79,9 +81,13 @@ Inspection Criteria: If a Quality Inspection is prepared for this Item, then thi
|
||||
|
||||
* **Default Income Account:** Income account selected here will be fetched automatically in sales invoice for this item.
|
||||
|
||||
* **Cost Centre:** Cost center selected here will be fetched automatically in sales invoice for this item.
|
||||
<img class="screenshot" alt="Sales details" src="{{docs_base_url}}/assets/img/stock/item-sales.png)">
|
||||
|
||||
* **Customer Codes:** Track Item Code assigned by the Customers for this Item. This will help you in searching item while creating Sales Order based on the Item Code in the Customer's Purchase Order.
|
||||
<img class="screenshot" alt="Sales details" src="{{docs_base_url}}/assets/img/stock/item-sales.png">
|
||||
|
||||
***Cost Centre:** Cost center selected here will be fetched automatically in sales invoice for this item.
|
||||
|
||||
***Customer Codes:** Track Item Code assigned by the Customers for this Item. This will help you in searching item while creating Sales Order based on the Item Code in the Customer's Purchase Order.
|
||||
|
||||
<img class="screenshot" alt="Sales details" src="{{docs_base_url}}/assets/img/stock/item-sales.png)">
|
||||
|
||||
|
||||
8
erpnext/docs/user/manual/en/support/support_reports.md
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
### Support Hours
|
||||
This report provide the information about the time slot along with the count of issues has been reported during the slot daywise.
|
||||
|
||||
> Support > Reports > Support Hours
|
||||
|
||||
<img class="screenshot" alt="Maintenance Visit" src="{{docs_base_url}}/assets/img/support/support_hours.png">
|
||||
@@ -0,0 +1,16 @@
|
||||
Global-search.md
|
||||
|
||||
|
||||
Global search is a word-processing operation in which a complete computer file or set of files is searched for every occurrence of a particular word or other sequence of characters.
|
||||
|
||||
We have made the Awesome Bar of ERPNext lot more powerful by adding Global Search feature.
|
||||
Global Search helps users find information quickly. It’s located in the upper right-hand corner in ERPNext. Simply entering a few characters in the Search will show results from several different record types (Contact, Customer, Issues etc.) related to that keyword. You can also customise the fields based on which search will be shown.
|
||||
|
||||
### Using Awesome bar for Global Search.
|
||||
|
||||
<img alt="Global Search" class="screenshot" src="{{docs_base_url}}/assets/img/articles/Global Search .gif">
|
||||
|
||||
### Enable Global Search for fields in a Doctype.
|
||||
|
||||
<img alt="Global Search" class="screenshot" src="{{docs_base_url}}/assets/img/articles/Enable Global Search .gif">
|
||||
|
||||
@@ -3,10 +3,10 @@ WORK IN PROGRESS
|
||||
-->
|
||||
# Manual de Usuario (Español)
|
||||
|
||||
### Contenido:
|
||||
### Contenido:
|
||||
|
||||
{index}
|
||||
|
||||
**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
|
||||
|
||||