Compare commits
358 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39ec7dc658 | ||
|
|
e77102ea47 | ||
|
|
b985ad2a8e | ||
|
|
1065679720 | ||
|
|
35167be0d9 | ||
|
|
1846d0fa2f | ||
|
|
9ef1d0f5a5 | ||
|
|
738d8c2e0f | ||
|
|
632f7673d5 | ||
|
|
51b4167cdd | ||
|
|
4ef1e2046b | ||
|
|
320fb13b37 | ||
|
|
4796e8e317 | ||
|
|
87b6498e02 | ||
|
|
499144fd86 | ||
|
|
b96e239cc0 | ||
|
|
cce79255fe | ||
|
|
139db5ffe7 | ||
|
|
8cf951b574 | ||
|
|
0c1d441aa3 | ||
|
|
5906ddf804 | ||
|
|
1696294847 | ||
|
|
046e1a6e28 | ||
|
|
ee5ff805e9 | ||
|
|
329aae2458 | ||
|
|
33aaebac2b | ||
|
|
af01f5154b | ||
|
|
b554f9077c | ||
|
|
f7c1c2c812 | ||
|
|
bfb3de771b | ||
|
|
21045c456e | ||
|
|
5ebb9a0fc7 | ||
|
|
1fd17a9a67 | ||
|
|
7663bbadb9 | ||
|
|
4a263c714d | ||
|
|
7587b19d1b | ||
|
|
919c9db1b0 | ||
|
|
f5dee777dd | ||
|
|
3b8b3fe766 | ||
|
|
85adbd7eae | ||
|
|
c697526382 | ||
|
|
2dd57acdef | ||
|
|
99350db5e1 | ||
|
|
478ffb9ae3 | ||
|
|
73dc35ddbf | ||
|
|
250e964205 | ||
|
|
ee090a9a3c | ||
|
|
22a5e79b9a | ||
|
|
4d49a7f6d1 | ||
|
|
ce436b7698 | ||
|
|
ec9430dae7 | ||
|
|
578624db1f | ||
|
|
ed0b107a9f | ||
|
|
f9e4893d9d | ||
|
|
f1f1b60a62 | ||
|
|
78c6e34106 | ||
|
|
9641d5b1f4 | ||
|
|
edba79e8f0 | ||
|
|
38d4be8325 | ||
|
|
118ceda46f | ||
|
|
316477b422 | ||
|
|
564e8b74dc | ||
|
|
4ada637b17 | ||
|
|
3a512af0e2 | ||
|
|
1012bcdde5 | ||
|
|
d0c5b3eb07 | ||
|
|
9b2b42dfc1 | ||
|
|
317888211a | ||
|
|
cd95134267 | ||
|
|
1fb4abc322 | ||
|
|
95dfe27bf7 | ||
|
|
4920d73adb | ||
|
|
95349fe360 | ||
|
|
40d3ad2bb4 | ||
|
|
98b52a7245 | ||
|
|
8b6f7914b0 | ||
|
|
4d185f3541 | ||
|
|
892cd615f8 | ||
|
|
495ef67caa | ||
|
|
35d3190822 | ||
|
|
4e91f28ce5 | ||
|
|
3beb1ba667 | ||
|
|
33977827c4 | ||
|
|
e09b507b6c | ||
|
|
1fcd2b0676 | ||
|
|
41c954b8b3 | ||
|
|
482331b987 | ||
|
|
e2176b852e | ||
|
|
8990af458b | ||
|
|
569011fb21 | ||
|
|
4c7709efbd | ||
|
|
11a3d51774 | ||
|
|
9d5b1b0e8f | ||
|
|
3b27382013 | ||
|
|
2b420f7038 | ||
|
|
353af64197 | ||
|
|
be4fd1100d | ||
|
|
8bccaed35a | ||
|
|
8af33a513b | ||
|
|
4d2e782e42 | ||
|
|
e16ec0c891 | ||
|
|
20f4d7f559 | ||
|
|
0fcf44e1a2 | ||
|
|
bab0c5a8a5 | ||
|
|
bead70b43a | ||
|
|
1c8d8a9720 | ||
|
|
d50da78f28 | ||
|
|
2653825d25 | ||
|
|
120b6c0b3c | ||
|
|
5296e3c321 | ||
|
|
c07741d36f | ||
|
|
734e635ef6 | ||
|
|
8907f1d2c3 | ||
|
|
6f9ef5b890 | ||
|
|
c54510660e | ||
|
|
145393b12f | ||
|
|
9c6e2c3637 | ||
|
|
cfc2693b2e | ||
|
|
7b764d03c2 | ||
|
|
448d919cc1 | ||
|
|
b528411ed1 | ||
|
|
b8b01928d3 | ||
|
|
296603a861 | ||
|
|
84227a6c54 | ||
|
|
9281013d51 | ||
|
|
87ec6a12ef | ||
|
|
059f99e621 | ||
|
|
8579dd1d78 | ||
|
|
6848708377 | ||
|
|
c67bf5026e | ||
|
|
fbec103ae7 | ||
|
|
1d9fd9aa52 | ||
|
|
58c9934452 | ||
|
|
83535811ad | ||
|
|
930dd5e54e | ||
|
|
7800bd89dc | ||
|
|
53b877bd8f | ||
|
|
40937083bf | ||
|
|
d0109a6fc0 | ||
|
|
b8a4a584e6 | ||
|
|
cda6206c1f | ||
|
|
4c28fa77bd | ||
|
|
7bdc45eceb | ||
|
|
394dbca0e4 | ||
|
|
33ebd9f88e | ||
|
|
4c1caa7e98 | ||
|
|
dc6e369172 | ||
|
|
08c3b3c925 | ||
|
|
bb5812cf0f | ||
|
|
36645e4e2f | ||
|
|
fb4f320df4 | ||
|
|
b296bb1551 | ||
|
|
e7c14fcc3d | ||
|
|
31bb34bbae | ||
|
|
6436b9d089 | ||
|
|
d62fa84ed9 | ||
|
|
baa937aa52 | ||
|
|
08450878f1 | ||
|
|
2ffe878999 | ||
|
|
49a6b4a4fa | ||
|
|
05e51d6c83 | ||
|
|
4cccdbdbf9 | ||
|
|
4b888b95d0 | ||
|
|
b5ec8381a6 | ||
|
|
3b128cabb2 | ||
|
|
1c6828e5d6 | ||
|
|
d65b4b4238 | ||
|
|
13abada526 | ||
|
|
de54f3019f | ||
|
|
d023d9a0bd | ||
|
|
edb2749dfd | ||
|
|
fcaf313c0f | ||
|
|
dfc5a454b3 | ||
|
|
1c32f5ace9 | ||
|
|
96381da547 | ||
|
|
91b2833708 | ||
|
|
20a862a6b9 | ||
|
|
65656ec2df | ||
|
|
9306aff1bb | ||
|
|
73f969fd7f | ||
|
|
283d5550e6 | ||
|
|
dda608dd00 | ||
|
|
e355f99786 | ||
|
|
27334c28a9 | ||
|
|
6c8d4678db | ||
|
|
ea50c9d1be | ||
|
|
35da7d1fb4 | ||
|
|
ced14cc789 | ||
|
|
9d27cf3c62 | ||
|
|
0e6933a1e8 | ||
|
|
51a76885b8 | ||
|
|
a919be111a | ||
|
|
9c42161061 | ||
|
|
79d6266c7b | ||
|
|
11d23f84d7 | ||
|
|
8e0f23efc7 | ||
|
|
ac9b1332d2 | ||
|
|
7b021e0fac | ||
|
|
d6dd25a666 | ||
|
|
f86100a734 | ||
|
|
96bb6099d6 | ||
|
|
e6c2ae3682 | ||
|
|
8d56f2959b | ||
|
|
d2d24554b3 | ||
|
|
c7d2bc67e8 | ||
|
|
1283f6308d | ||
|
|
d36c136fc6 | ||
|
|
3951f6971e | ||
|
|
75e65e7079 | ||
|
|
7f95d587b2 | ||
|
|
75b145fe2c | ||
|
|
bc3acdd0ba | ||
|
|
8f42f60dc9 | ||
|
|
823b3ca540 | ||
|
|
5e75e3ba03 | ||
|
|
113df55e64 | ||
|
|
3e4b2743c6 | ||
|
|
338c28e78e | ||
|
|
7e14996995 | ||
|
|
6e30f04181 | ||
|
|
4a10f18ee3 | ||
|
|
f37d43d0c1 | ||
|
|
aea60f349f | ||
|
|
90bd5681d1 | ||
|
|
30e03cc4c8 | ||
|
|
4c40a416e6 | ||
|
|
3020c8086c | ||
|
|
8b3ef1e70a | ||
|
|
c446bf6117 | ||
|
|
660de515b5 | ||
|
|
e012e24423 | ||
|
|
e2d0d0a0c1 | ||
|
|
22e82dff20 | ||
|
|
78d2f542d0 | ||
|
|
b962fc1573 | ||
|
|
1ee534889f | ||
|
|
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 | ||
|
|
934e69fe0b | ||
|
|
19d9381197 | ||
|
|
7640858510 | ||
|
|
690de64734 | ||
|
|
c7e3a09cfb |
52
.travis.yml
52
.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,45 @@ python:
|
||||
services:
|
||||
- mysql
|
||||
|
||||
before_install:
|
||||
- "export DISPLAY=:99.0"
|
||||
- "sh -e /etc/init.d/xvfb start"
|
||||
|
||||
install:
|
||||
- pip install flake8==3.3.0
|
||||
- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
|
||||
- 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
|
||||
|
||||
19
README.md
19
README.md
@@ -6,10 +6,9 @@
|
||||
|
||||
Includes: Accounting, Inventory, Manufacturing, CRM, Sales, Purchase, Project Management, HRMS. Requires MariaDB.
|
||||
|
||||
ERPNext is built on the [Frappe](https://github.com/frappe/frappe) Framework, a full-stack web app framework in Python & JavaScript.
|
||||
ERPNext is built on the [Frappé](https://github.com/frappe/frappe) Framework, a full-stack web app framework in Python & JavaScript.
|
||||
|
||||
- [User Guide](https://frappe.github.io/erpnext/)
|
||||
- [Getting Help](http://erpnext.org/getting-help.html)
|
||||
- [User Guide](https://erpnext.org/docs/user)
|
||||
- [Discussion Forum](https://discuss.erpnext.com/)
|
||||
|
||||
---
|
||||
@@ -34,7 +33,7 @@ System and user credentials are listed on the download page.
|
||||
|
||||
GNU/General Public License (see LICENSE.txt)
|
||||
|
||||
The ERPNext code is licensed as GNU General Public License (v3) and the Documentation is licensed as Creative Commons (CC-BY-SA-3.0) and the copyright is owned by Frappe Technologies Pvt Ltd (Frappe) and Contributors.
|
||||
The ERPNext code is licensed as GNU General Public License (v3) and the Documentation is licensed as Creative Commons (CC-BY-SA-3.0) and the copyright is owned by Frappé Technologies Pvt Ltd (Frappé) and Contributors.
|
||||
|
||||
---
|
||||
|
||||
@@ -49,19 +48,19 @@ The ERPNext code is licensed as GNU General Public License (v3) and the Document
|
||||
|
||||
## Logo and Trademark
|
||||
|
||||
The brand name ERPNext and the logo are trademarks of Frappe Technologies Pvt. Ltd.
|
||||
The brand name ERPNext and the logo are trademarks of Frappé Technologies Pvt. Ltd.
|
||||
|
||||
### Introduction
|
||||
|
||||
Frappe Technologies Pvt. Ltd. (Frappe) owns and oversees the trademarks for the ERPNext name and logos. We have developed this trademark usage policy with the following goals in mind:
|
||||
Frappé Technologies Pvt. Ltd. (Frappé) owns and oversees the trademarks for the ERPNext name and logos. We have developed this trademark usage policy with the following goals in mind:
|
||||
|
||||
- We’d like to make it easy for anyone to use the ERPNext name or logo for community-oriented efforts that help spread and improve ERPNext.
|
||||
- We’d like to make it clear how ERPNext-related businesses and projects can (and cannot) use the ERPNext name and logo.
|
||||
- We’d like to make it hard for anyone to use the ERPNext name and logo to unfairly profit from, trick or confuse people who are looking for official ERPNext resources.
|
||||
|
||||
### Frappe Trademark Usage Policy
|
||||
### Frappé Trademark Usage Policy
|
||||
|
||||
Permission from Frappe is required to use the ERPNext name or logo as part of any project, product, service, domain or company name.
|
||||
Permission from Frappé is required to use the ERPNext name or logo as part of any project, product, service, domain or company name.
|
||||
|
||||
We will grant permission to use the ERPNext name and logo for projects that meet the following criteria:
|
||||
|
||||
@@ -72,7 +71,7 @@ Your project neither promotes nor is associated with entities that currently fai
|
||||
|
||||
Use of the ERPNext name and logo is additionally allowed in the following situations:
|
||||
|
||||
All other ERPNext-related businesses or projects can use the ERPNext name and logo to refer to and explain their services, but they cannot use them as part of a product, project, service, domain, or company name and they cannot use them in any way that suggests an affiliation with or endorsement by ERPNext or Frappe Technologies or the ERPNext open source project. For example, a consulting company can describe its business as “123 Web Services, offering ERPNext consulting for small businesses,” but cannot call its business “The ERPNext Consulting Company.”
|
||||
All other ERPNext-related businesses or projects can use the ERPNext name and logo to refer to and explain their services, but they cannot use them as part of a product, project, service, domain, or company name and they cannot use them in any way that suggests an affiliation with or endorsement by ERPNext or Frappé Technologies or the ERPNext open source project. For example, a consulting company can describe its business as “123 Web Services, offering ERPNext consulting for small businesses,” but cannot call its business “The ERPNext Consulting Company.”
|
||||
|
||||
Similarly, it’s OK to use the ERPNext logo as part of a page that describes your products or services, but it is not OK to use it as part of your company or product logo or branding itself. Under no circumstances is it permitted to use ERPNext as part of a top-level domain name.
|
||||
|
||||
@@ -80,6 +79,6 @@ We do not allow the use of the trademark in advertising, including AdSense/AdWor
|
||||
|
||||
Please note that it is not the goal of this policy to limit commercial activity around ERPNext. We encourage ERPNext-based businesses, and we would love to see hundreds of them.
|
||||
|
||||
When in doubt about your use of the ERPNext name or logo, please contact Frappe Technologies for clarification.
|
||||
When in doubt about your use of the ERPNext name or logo, please contact Frappé Technologies for clarification.
|
||||
|
||||
(inspired by WordPress)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## ERPNext includes these public works
|
||||
|
||||
For Frappe Framework, please see attributions.md at https://github.com/frappe/frappe/
|
||||
For Frappé Framework, please see attributions.md at https://github.com/frappe/frappe/
|
||||
|
||||
#### Images
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
import inspect
|
||||
import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
|
||||
__version__ = '8.3.3'
|
||||
__version__ = '8.8.0'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
@@ -65,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,95 @@
|
||||
// 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
|
||||
&& frappe.boot.user.can_read.indexOf("GL Entry") !== -1) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -84,7 +84,7 @@ def get_csv_contents(files_path):
|
||||
try:
|
||||
csv_content.setdefault(file_type, [])\
|
||||
.append(read_csv_content(csvfile.read()))
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
continue
|
||||
return csv_content
|
||||
|
||||
|
||||
27
erpnext/accounts/doctype/account/test_account.js
Normal file
27
erpnext/accounts/doctype/account/test_account.js
Normal file
@@ -0,0 +1,27 @@
|
||||
QUnit.module('accounts');
|
||||
|
||||
QUnit.test("test account", function(assert) {
|
||||
assert.expect(4);
|
||||
let done = assert.async();
|
||||
frappe.run_serially([
|
||||
() => frappe.set_route('Tree', 'Account'),
|
||||
() => frappe.click_button('Expand All'),
|
||||
() => frappe.click_link('Debtors'),
|
||||
() => frappe.click_button('Edit'),
|
||||
() => frappe.timeout(1),
|
||||
() => {
|
||||
assert.ok(cur_frm.doc.root_type=='Asset');
|
||||
assert.ok(cur_frm.doc.report_type=='Balance Sheet');
|
||||
assert.ok(cur_frm.doc.account_type=='Receivable');
|
||||
},
|
||||
() => frappe.click_button('Ledger'),
|
||||
() => frappe.timeout(1),
|
||||
() => {
|
||||
// check if general ledger report shown
|
||||
assert.deepEqual(frappe.get_route(), ['query-report', 'General Ledger']);
|
||||
window.history.back();
|
||||
return frappe.timeout(1);
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
46
erpnext/accounts/doctype/account/test_make_tax_account.js
Normal file
46
erpnext/accounts/doctype/account/test_make_tax_account.js
Normal file
@@ -0,0 +1,46 @@
|
||||
QUnit.module('accounts');
|
||||
QUnit.test("test account", assert => {
|
||||
assert.expect(3);
|
||||
let done = assert.async();
|
||||
frappe.run_serially([
|
||||
() => frappe.set_route('Tree', 'Account'),
|
||||
() => frappe.click_button('Expand All'),
|
||||
() => frappe.click_link('Duties and Taxes - '+ frappe.get_abbr(frappe.defaults.get_default("Company"))),
|
||||
() => {
|
||||
if($('a:contains("CGST"):visible').length == 0){
|
||||
return frappe.map_tax.make('CGST', 9);
|
||||
}
|
||||
},
|
||||
() => {
|
||||
if($('a:contains("SGST"):visible').length == 0){
|
||||
return frappe.map_tax.make('SGST', 9);
|
||||
}
|
||||
},
|
||||
() => {
|
||||
if($('a:contains("IGST"):visible').length == 0){
|
||||
return frappe.map_tax.make('IGST', 18);
|
||||
}
|
||||
},
|
||||
() => {
|
||||
assert.ok($('a:contains("CGST"):visible').length!=0, "CGST Checked");
|
||||
assert.ok($('a:contains("SGST"):visible').length!=0, "SGST Checked");
|
||||
assert.ok($('a:contains("IGST"):visible').length!=0, "IGST Checked");
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
frappe.map_tax = {
|
||||
make:function(text,rate){
|
||||
return frappe.run_serially([
|
||||
() => frappe.click_button('Add Child'),
|
||||
() => frappe.timeout(0.2),
|
||||
() => cur_dialog.set_value('account_name',text),
|
||||
() => cur_dialog.set_value('account_type','Tax'),
|
||||
() => cur_dialog.set_value('tax_rate',rate),
|
||||
() => cur_dialog.set_value('account_currency','INR'),
|
||||
() => frappe.click_button('Create New'),
|
||||
]);
|
||||
}
|
||||
};
|
||||
@@ -147,8 +147,9 @@ class Asset(Document):
|
||||
accumulated_depreciation_after_full_schedule = \
|
||||
max([d.accumulated_depreciation_amount for d in self.get("schedules")])
|
||||
|
||||
asset_value_after_full_schedule = (flt(self.gross_purchase_amount) -
|
||||
flt(accumulated_depreciation_after_full_schedule))
|
||||
asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) -
|
||||
flt(accumulated_depreciation_after_full_schedule),
|
||||
self.precision('expected_value_after_useful_life'))
|
||||
|
||||
if self.expected_value_after_useful_life < asset_value_after_full_schedule:
|
||||
frappe.throw(_("Expected value after useful life must be greater than or equal to {0}")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -718,7 +718,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-04-27 13:18:06.617940",
|
||||
"modified": "2017-08-03 12:40:09.611951",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "GL Entry",
|
||||
@@ -786,7 +786,7 @@
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"search_fields": "voucher_no,account,posting_date,against_voucher",
|
||||
"show_name_in_global_search": 0,
|
||||
|
||||
23
erpnext/accounts/doctype/gl_entry/test_gl_entry.js
Normal file
23
erpnext/accounts/doctype/gl_entry/test_gl_entry.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: GL Entry", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially('GL Entry', [
|
||||
// insert a new GL Entry
|
||||
() => frappe.tests.make([
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
||||
@@ -43,8 +43,26 @@ frappe.ui.form.on("Journal Entry", {
|
||||
$.each(frm.doc.accounts || [], function(i, row) {
|
||||
erpnext.journal_entry.set_exchange_rate(frm, row.doctype, row.name);
|
||||
})
|
||||
},
|
||||
|
||||
company: function(frm) {
|
||||
frappe.call({
|
||||
method: "frappe.client.get_value",
|
||||
args: {
|
||||
doctype: "Company",
|
||||
filters: {"name": frm.doc.company},
|
||||
fieldname: "cost_center"
|
||||
},
|
||||
callback: function(r){
|
||||
if(r.message){
|
||||
$.each(frm.doc.accounts || [], function(i, jvd) {
|
||||
frappe.model.set_value(jvd.doctype, jvd.name, "cost_center", r.message.cost_center);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
||||
onload: function() {
|
||||
@@ -96,7 +114,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
|
||||
@@ -122,10 +147,11 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
||||
|
||||
// account filter
|
||||
frappe.model.validate_missing(jvd, "account");
|
||||
|
||||
var party_account_field = jvd.reference_type==="Sales Invoice" ? "debit_to": "credit_to";
|
||||
out.filters.push([jvd.reference_type, party_account_field, "=", jvd.account]);
|
||||
} else {
|
||||
}
|
||||
|
||||
if(in_list(["Sales Order", "Purchase Order"], jvd.reference_type)) {
|
||||
// party_type and party mandatory
|
||||
frappe.model.validate_missing(jvd, "party_type");
|
||||
frappe.model.validate_missing(jvd, "party");
|
||||
|
||||
@@ -28,7 +28,7 @@ frappe.ui.form.on('Payment Entry', {
|
||||
frm.set_query("party_type", function() {
|
||||
return{
|
||||
"filters": {
|
||||
"name": ["in",["Customer","Supplier"]],
|
||||
"name": ["in",["Customer","Supplier", "Employee"]],
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -70,6 +70,8 @@ frappe.ui.form.on('Payment Entry', {
|
||||
var doctypes = ["Sales Order", "Sales Invoice", "Journal Entry"];
|
||||
} else if (frm.doc.party_type=="Supplier") {
|
||||
var doctypes = ["Purchase Order", "Purchase Invoice", "Journal Entry"];
|
||||
} else if (frm.doc.party_type=="Employee") {
|
||||
var doctypes = ["Expense Claim", "Journal Entry"];
|
||||
} else {
|
||||
var doctypes = ["Journal Entry"];
|
||||
}
|
||||
@@ -82,12 +84,18 @@ frappe.ui.form.on('Payment Entry', {
|
||||
frm.set_query("reference_name", "references", function(doc, cdt, cdn) {
|
||||
child = locals[cdt][cdn];
|
||||
filters = {"docstatus": 1, "company": doc.company};
|
||||
party_type_doctypes = ['Sales Invoice', 'Sales Order', 'Purchase Invoice', 'Purchase Order'];
|
||||
party_type_doctypes = ['Sales Invoice', 'Sales Order', 'Purchase Invoice',
|
||||
'Purchase Order', 'Expense Claim'];
|
||||
|
||||
if (in_list(party_type_doctypes, child.reference_doctype)) {
|
||||
filters[doc.party_type.toLowerCase()] = doc.party;
|
||||
}
|
||||
|
||||
if(child.reference_doctype == "Expense Claim") {
|
||||
filters["status"] = "Approved";
|
||||
filters["is_paid"] = 0;
|
||||
}
|
||||
|
||||
return {
|
||||
filters: filters
|
||||
};
|
||||
@@ -200,9 +208,15 @@ frappe.ui.form.on('Payment Entry', {
|
||||
});
|
||||
} else {
|
||||
if(!frm.doc.party)
|
||||
frm.set_value("party_type", frm.doc.payment_type=="Receive" ? "Customer" : "Supplier");
|
||||
{
|
||||
if (frm.doc.payment_type=="Receive"){
|
||||
frm.set_value("party_type", "Customer");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
frm.events.party(frm);
|
||||
}
|
||||
|
||||
if(frm.doc.mode_of_payment)
|
||||
frm.events.mode_of_payment(frm);
|
||||
@@ -291,37 +305,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) {
|
||||
@@ -337,7 +353,8 @@ frappe.ui.form.on('Payment Entry', {
|
||||
method: "erpnext.setup.utils.get_exchange_rate",
|
||||
args: {
|
||||
from_currency: frm.doc.paid_from_account_currency,
|
||||
to_currency: company_currency
|
||||
to_currency: company_currency,
|
||||
transaction_date: frm.doc.posting_date
|
||||
},
|
||||
callback: function(r, rt) {
|
||||
frm.set_value("source_exchange_rate", r.message);
|
||||
@@ -484,7 +501,7 @@ frappe.ui.form.on('Payment Entry', {
|
||||
c.reference_name = d.voucher_no;
|
||||
c.total_amount = d.invoice_amount;
|
||||
c.outstanding_amount = d.outstanding_amount;
|
||||
if(!in_list(["Sales Order", "Purchase Order"], d.voucher_type)) {
|
||||
if(!in_list(["Sales Order", "Purchase Order", "Expense Claim"], d.voucher_type)) {
|
||||
if(flt(d.outstanding_amount) > 0)
|
||||
total_positive_outstanding += flt(d.outstanding_amount);
|
||||
else
|
||||
@@ -499,14 +516,15 @@ frappe.ui.form.on('Payment Entry', {
|
||||
} else {
|
||||
c.exchange_rate = 1;
|
||||
}
|
||||
if (in_list(['Sales Invoice', 'Purchase Invoice'], d.reference_doctype)){
|
||||
if (in_list(['Sales Invoice', 'Purchase Invoice', "Expense Claim"], d.reference_doctype)){
|
||||
c.due_date = d.due_date;
|
||||
}
|
||||
});
|
||||
|
||||
if(
|
||||
(frm.doc.payment_type=="Receive" && frm.doc.party_type=="Customer") ||
|
||||
(frm.doc.payment_type=="Pay" && frm.doc.party_type=="Supplier")
|
||||
(frm.doc.payment_type=="Pay" && frm.doc.party_type=="Supplier") ||
|
||||
(frm.doc.payment_type=="Pay" && frm.doc.party_type=="Employee")
|
||||
) {
|
||||
if(total_positive_outstanding > total_negative_outstanding)
|
||||
frm.set_value("paid_amount",
|
||||
@@ -551,7 +569,8 @@ frappe.ui.form.on('Payment Entry', {
|
||||
|
||||
var allocated_negative_outstanding = 0;
|
||||
if((frm.doc.payment_type=="Receive" && frm.doc.party_type=="Customer") ||
|
||||
(frm.doc.payment_type=="Pay" && frm.doc.party_type=="Supplier")) {
|
||||
(frm.doc.payment_type=="Pay" && frm.doc.party_type=="Supplier") ||
|
||||
(frm.doc.payment_type=="Pay" && frm.doc.party_type=="Employee")) {
|
||||
if(total_positive_outstanding_including_order > paid_amount) {
|
||||
var remaining_outstanding = total_positive_outstanding_including_order - paid_amount;
|
||||
allocated_negative_outstanding = total_negative_outstanding < remaining_outstanding ?
|
||||
@@ -692,6 +711,14 @@ frappe.ui.form.on('Payment Entry', {
|
||||
frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Purchase Order, Purchase Invoice or Journal Entry", [row.idx]));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(frm.doc.party_type=="Employee" &&
|
||||
!in_list(["Expense Claim", "Journal Entry"], row.reference_doctype)
|
||||
) {
|
||||
frappe.model.set_value(row.doctype, row.name, "against_voucher_type", null);
|
||||
frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Expense Claim or Journal Entry", [row.idx]));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (row) {
|
||||
|
||||
@@ -12,27 +12,27 @@ from erpnext.accounts.doctype.journal_entry.journal_entry \
|
||||
import get_average_exchange_rate, get_default_bank_cash_account
|
||||
from erpnext.setup.utils import get_exchange_rate
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
|
||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
||||
from erpnext.controllers.accounts_controller import AccountsController
|
||||
|
||||
class InvalidPaymentEntry(ValidationError): pass
|
||||
|
||||
class PaymentEntry(AccountsController):
|
||||
def setup_party_account_field(self):
|
||||
def setup_party_account_field(self):
|
||||
self.party_account_field = None
|
||||
self.party_account = None
|
||||
self.party_account_currency = None
|
||||
|
||||
|
||||
if self.payment_type == "Receive":
|
||||
self.party_account_field = "paid_from"
|
||||
self.party_account = self.paid_from
|
||||
self.party_account_currency = self.paid_from_account_currency
|
||||
|
||||
|
||||
elif self.payment_type == "Pay":
|
||||
self.party_account_field = "paid_to"
|
||||
self.party_account = self.paid_to
|
||||
self.party_account_currency = self.paid_to_account_currency
|
||||
|
||||
|
||||
def validate(self):
|
||||
self.setup_party_account_field()
|
||||
self.set_missing_values()
|
||||
@@ -50,18 +50,20 @@ class PaymentEntry(AccountsController):
|
||||
self.set_remarks()
|
||||
self.validate_duplicate_entry()
|
||||
self.validate_allocated_amount()
|
||||
|
||||
|
||||
def on_submit(self):
|
||||
self.setup_party_account_field()
|
||||
if self.difference_amount:
|
||||
frappe.throw(_("Difference Amount must be zero"))
|
||||
self.make_gl_entries()
|
||||
self.update_advance_paid()
|
||||
|
||||
self.update_expense_claim()
|
||||
|
||||
def on_cancel(self):
|
||||
self.setup_party_account_field()
|
||||
self.make_gl_entries(cancel=1)
|
||||
self.update_advance_paid()
|
||||
self.update_expense_claim()
|
||||
self.delink_advance_entry_references()
|
||||
|
||||
def validate_duplicate_entry(self):
|
||||
@@ -70,8 +72,8 @@ class PaymentEntry(AccountsController):
|
||||
if (d.reference_doctype, d.reference_name) in reference_names:
|
||||
frappe.throw(_("Row #{0}: Duplicate entry in References {1} {2}").format(d.idx, d.reference_doctype, d.reference_name))
|
||||
reference_names.append((d.reference_doctype, d.reference_name))
|
||||
|
||||
|
||||
|
||||
|
||||
def validate_allocated_amount(self):
|
||||
for d in self.get("references"):
|
||||
if (flt(d.allocated_amount))> 0:
|
||||
@@ -87,111 +89,113 @@ class PaymentEntry(AccountsController):
|
||||
|
||||
def set_missing_values(self):
|
||||
if self.payment_type == "Internal Transfer":
|
||||
for field in ("party", "party_balance", "total_allocated_amount",
|
||||
for field in ("party", "party_balance", "total_allocated_amount",
|
||||
"base_total_allocated_amount", "unallocated_amount"):
|
||||
self.set(field, None)
|
||||
self.references = []
|
||||
else:
|
||||
if not self.party_type:
|
||||
frappe.throw(_("Party Type is mandatory"))
|
||||
|
||||
|
||||
if not self.party:
|
||||
frappe.throw(_("Party is mandatory"))
|
||||
|
||||
self.party_name = frappe.db.get_value(self.party_type, self.party,
|
||||
|
||||
self.party_name = frappe.db.get_value(self.party_type, self.party,
|
||||
self.party_type.lower() + "_name")
|
||||
|
||||
|
||||
if self.party:
|
||||
if not self.party_balance:
|
||||
self.party_balance = get_balance_on(party_type=self.party_type,
|
||||
party=self.party, date=self.posting_date, company=self.company)
|
||||
|
||||
|
||||
if not self.party_account:
|
||||
party_account = get_party_account(self.party_type, self.party, self.company)
|
||||
self.set(self.party_account_field, party_account)
|
||||
self.party_account = party_account
|
||||
|
||||
|
||||
if self.paid_from and not (self.paid_from_account_currency or self.paid_from_account_balance):
|
||||
acc = get_account_details(self.paid_from, self.posting_date)
|
||||
self.paid_from_account_currency = acc.account_currency
|
||||
self.paid_from_account_balance = acc.account_balance
|
||||
|
||||
|
||||
if self.paid_to and not (self.paid_to_account_currency or self.paid_to_account_balance):
|
||||
acc = get_account_details(self.paid_to, self.posting_date)
|
||||
self.paid_to_account_currency = acc.account_currency
|
||||
self.paid_to_account_balance = acc.account_balance
|
||||
|
||||
|
||||
self.party_account_currency = self.paid_from_account_currency \
|
||||
if self.payment_type=="Receive" else self.paid_to_account_currency
|
||||
|
||||
|
||||
self.set_missing_ref_details()
|
||||
|
||||
|
||||
|
||||
|
||||
def set_missing_ref_details(self):
|
||||
for d in self.get("references"):
|
||||
if d.allocated_amount:
|
||||
ref_details = get_reference_details(d.reference_doctype,
|
||||
ref_details = get_reference_details(d.reference_doctype,
|
||||
d.reference_name, self.party_account_currency)
|
||||
|
||||
|
||||
for field, value in ref_details.items():
|
||||
if not d.get(field):
|
||||
d.set(field, value)
|
||||
|
||||
|
||||
def validate_payment_type(self):
|
||||
if self.payment_type not in ("Receive", "Pay", "Internal Transfer"):
|
||||
frappe.throw(_("Payment Type must be one of Receive, Pay and Internal Transfer"))
|
||||
|
||||
|
||||
def validate_party_details(self):
|
||||
if self.party:
|
||||
if not frappe.db.exists(self.party_type, self.party):
|
||||
frappe.throw(_("Invalid {0}: {1}").format(self.party_type, self.party))
|
||||
|
||||
|
||||
if self.party_account:
|
||||
party_account_type = "Receivable" if self.party_type=="Customer" else "Payable"
|
||||
self.validate_account_type(self.party_account, [party_account_type])
|
||||
|
||||
|
||||
def validate_bank_accounts(self):
|
||||
if self.payment_type in ("Pay", "Internal Transfer"):
|
||||
self.validate_account_type(self.paid_from, ["Bank", "Cash"])
|
||||
|
||||
|
||||
if self.payment_type in ("Receive", "Internal Transfer"):
|
||||
self.validate_account_type(self.paid_to, ["Bank", "Cash"])
|
||||
|
||||
|
||||
def validate_account_type(self, account, account_types):
|
||||
account_type = frappe.db.get_value("Account", account, "account_type")
|
||||
if account_type not in account_types:
|
||||
frappe.throw(_("Account Type for {0} must be {1}").format(account, comma_or(account_types)))
|
||||
|
||||
|
||||
def set_exchange_rate(self):
|
||||
if self.paid_from and not self.source_exchange_rate:
|
||||
if self.paid_from_account_currency == self.company_currency:
|
||||
self.source_exchange_rate = 1
|
||||
else:
|
||||
self.source_exchange_rate = get_exchange_rate(self.paid_from_account_currency,
|
||||
self.source_exchange_rate = get_exchange_rate(self.paid_from_account_currency,
|
||||
self.company_currency, self.posting_date)
|
||||
|
||||
|
||||
if self.paid_to and not self.target_exchange_rate:
|
||||
self.target_exchange_rate = get_exchange_rate(self.paid_to_account_currency,
|
||||
self.target_exchange_rate = get_exchange_rate(self.paid_to_account_currency,
|
||||
self.company_currency, self.posting_date)
|
||||
|
||||
|
||||
def validate_mandatory(self):
|
||||
for field in ("paid_amount", "received_amount", "source_exchange_rate", "target_exchange_rate"):
|
||||
if not self.get(field):
|
||||
frappe.throw(_("{0} is mandatory").format(self.meta.get_label(field)))
|
||||
|
||||
|
||||
def validate_reference_documents(self):
|
||||
if self.party_type == "Customer":
|
||||
valid_reference_doctypes = ("Sales Order", "Sales Invoice", "Journal Entry")
|
||||
else:
|
||||
elif self.party_type == "Supplier":
|
||||
valid_reference_doctypes = ("Purchase Order", "Purchase Invoice", "Journal Entry")
|
||||
|
||||
elif self.party_type == "Employee":
|
||||
valid_reference_doctypes = ("Expense Claim", "Journal Entry")
|
||||
|
||||
for d in self.get("references"):
|
||||
if not d.allocated_amount:
|
||||
continue
|
||||
if d.reference_doctype not in valid_reference_doctypes:
|
||||
frappe.throw(_("Reference Doctype must be one of {0}")
|
||||
.format(comma_or(valid_reference_doctypes)))
|
||||
|
||||
|
||||
elif d.reference_name:
|
||||
if not frappe.db.exists(d.reference_doctype, d.reference_name):
|
||||
frappe.throw(_("{0} {1} does not exist").format(d.reference_doctype, d.reference_name))
|
||||
@@ -204,21 +208,26 @@ class PaymentEntry(AccountsController):
|
||||
.format(d.reference_doctype, d.reference_name, self.party_type, self.party))
|
||||
else:
|
||||
self.validate_journal_entry()
|
||||
|
||||
if d.reference_doctype in ("Sales Invoice", "Purchase Invoice"):
|
||||
ref_party_account = ref_doc.debit_to \
|
||||
if self.party_type=="Customer" else ref_doc.credit_to
|
||||
|
||||
if d.reference_doctype in ("Sales Invoice", "Purchase Invoice", "Expense Claim"):
|
||||
if self.party_type=="Customer":
|
||||
ref_party_account = ref_doc.debit_to
|
||||
elif self.party_type=="Supplier":
|
||||
ref_party_account = ref_doc.credit_to
|
||||
elif self.party_type=="Employee":
|
||||
ref_party_account = ref_doc.payable_account
|
||||
|
||||
if ref_party_account != self.party_account:
|
||||
frappe.throw(_("{0} {1} does not associated with Party Account {2}")
|
||||
.format(d.reference_doctype, d.reference_name, self.party_account))
|
||||
|
||||
frappe.throw(_("{0} {1} is associated with {2}, but Party Account is {3}")
|
||||
.format(d.reference_doctype, d.reference_name, ref_party_account, self.party_account))
|
||||
|
||||
if ref_doc.docstatus != 1:
|
||||
frappe.throw(_("{0} {1} must be submitted")
|
||||
.format(d.reference_doctype, d.reference_name))
|
||||
|
||||
|
||||
def validate_journal_entry(self):
|
||||
for d in self.get("references"):
|
||||
if d.allocated_amount and d.reference_doctype == "Journal Entry":
|
||||
if d.allocated_amount and d.reference_doctype == "Journal Entry":
|
||||
je_accounts = frappe.db.sql("""select debit, credit from `tabJournal Entry Account`
|
||||
where account = %s and party=%s and docstatus = 1 and parent = %s
|
||||
and (reference_type is null or reference_type in ("", "Sales Order", "Purchase Order"))
|
||||
@@ -236,7 +245,7 @@ class PaymentEntry(AccountsController):
|
||||
if not valid:
|
||||
frappe.throw(_("Against Journal Entry {0} does not have any unmatched {1} entry")
|
||||
.format(d.reference_name, dr_or_cr))
|
||||
|
||||
|
||||
def set_amounts(self):
|
||||
self.set_amounts_in_company_currency()
|
||||
self.set_total_allocated_amount()
|
||||
@@ -246,111 +255,111 @@ class PaymentEntry(AccountsController):
|
||||
def set_amounts_in_company_currency(self):
|
||||
self.base_paid_amount, self.base_received_amount, self.difference_amount = 0, 0, 0
|
||||
if self.paid_amount:
|
||||
self.base_paid_amount = flt(flt(self.paid_amount) * flt(self.source_exchange_rate),
|
||||
self.base_paid_amount = flt(flt(self.paid_amount) * flt(self.source_exchange_rate),
|
||||
self.precision("base_paid_amount"))
|
||||
|
||||
|
||||
if self.received_amount:
|
||||
self.base_received_amount = flt(flt(self.received_amount) * flt(self.target_exchange_rate),
|
||||
self.base_received_amount = flt(flt(self.received_amount) * flt(self.target_exchange_rate),
|
||||
self.precision("base_received_amount"))
|
||||
|
||||
|
||||
def set_total_allocated_amount(self):
|
||||
if self.payment_type == "Internal Transfer":
|
||||
return
|
||||
|
||||
|
||||
total_allocated_amount, base_total_allocated_amount = 0, 0
|
||||
for d in self.get("references"):
|
||||
if d.allocated_amount:
|
||||
if d.allocated_amount:
|
||||
total_allocated_amount += flt(d.allocated_amount)
|
||||
base_total_allocated_amount += flt(flt(d.allocated_amount) * flt(d.exchange_rate),
|
||||
base_total_allocated_amount += flt(flt(d.allocated_amount) * flt(d.exchange_rate),
|
||||
self.precision("base_paid_amount"))
|
||||
|
||||
|
||||
self.total_allocated_amount = abs(total_allocated_amount)
|
||||
self.base_total_allocated_amount = abs(base_total_allocated_amount)
|
||||
|
||||
|
||||
def set_unallocated_amount(self):
|
||||
self.unallocated_amount = 0;
|
||||
if self.party:
|
||||
party_amount = self.paid_amount if self.payment_type=="Receive" else self.received_amount
|
||||
|
||||
|
||||
total_deductions = sum([flt(d.amount) for d in self.get("deductions")])
|
||||
|
||||
|
||||
if self.total_allocated_amount < party_amount:
|
||||
if self.payment_type == "Receive":
|
||||
self.unallocated_amount = party_amount - (self.total_allocated_amount - total_deductions)
|
||||
else:
|
||||
self.unallocated_amount = party_amount - (self.total_allocated_amount + total_deductions)
|
||||
|
||||
|
||||
def set_difference_amount(self):
|
||||
base_unallocated_amount = flt(self.unallocated_amount) * (flt(self.source_exchange_rate)
|
||||
base_unallocated_amount = flt(self.unallocated_amount) * (flt(self.source_exchange_rate)
|
||||
if self.payment_type=="Receive" else flt(self.target_exchange_rate))
|
||||
|
||||
|
||||
base_party_amount = flt(self.base_total_allocated_amount) + flt(base_unallocated_amount)
|
||||
|
||||
|
||||
if self.payment_type == "Receive":
|
||||
self.difference_amount = base_party_amount - self.base_received_amount
|
||||
elif self.payment_type == "Pay":
|
||||
self.difference_amount = self.base_paid_amount - base_party_amount
|
||||
else:
|
||||
self.difference_amount = self.base_paid_amount - flt(self.base_received_amount)
|
||||
|
||||
|
||||
for d in self.get("deductions"):
|
||||
if d.amount:
|
||||
self.difference_amount -= flt(d.amount)
|
||||
|
||||
|
||||
self.difference_amount = flt(self.difference_amount, self.precision("difference_amount"))
|
||||
|
||||
|
||||
def clear_unallocated_reference_document_rows(self):
|
||||
self.set("references", self.get("references", {"allocated_amount": ["not in", [0, None, ""]]}))
|
||||
|
||||
frappe.db.sql("""delete from `tabPayment Entry Reference`
|
||||
frappe.db.sql("""delete from `tabPayment Entry Reference`
|
||||
where parent = %s and allocated_amount = 0""", self.name)
|
||||
|
||||
|
||||
def validate_payment_against_negative_invoice(self):
|
||||
if ((self.payment_type=="Pay" and self.party_type=="Customer")
|
||||
if ((self.payment_type=="Pay" and self.party_type=="Customer")
|
||||
or (self.payment_type=="Receive" and self.party_type=="Supplier")):
|
||||
|
||||
total_negative_outstanding = sum([abs(flt(d.outstanding_amount))
|
||||
|
||||
total_negative_outstanding = sum([abs(flt(d.outstanding_amount))
|
||||
for d in self.get("references") if flt(d.outstanding_amount) < 0])
|
||||
|
||||
|
||||
party_amount = self.paid_amount if self.payment_type=="Receive" else self.received_amount
|
||||
|
||||
if not total_negative_outstanding:
|
||||
frappe.throw(_("Cannot {0} {1} {2} without any negative outstanding invoice")
|
||||
.format(self.payment_type, ("to" if self.party_type=="Customer" else "from"),
|
||||
.format(self.payment_type, ("to" if self.party_type=="Customer" else "from"),
|
||||
self.party_type), InvalidPaymentEntry)
|
||||
|
||||
|
||||
elif party_amount > total_negative_outstanding:
|
||||
frappe.throw(_("Paid Amount cannot be greater than total negative outstanding amount {0}")
|
||||
.format(total_negative_outstanding), InvalidPaymentEntry)
|
||||
|
||||
|
||||
def set_title(self):
|
||||
if self.payment_type in ("Receive", "Pay"):
|
||||
self.title = self.party
|
||||
else:
|
||||
self.title = self.paid_from + " - " + self.paid_to
|
||||
|
||||
|
||||
def validate_transaction_reference(self):
|
||||
bank_account = self.paid_to if self.payment_type == "Receive" else self.paid_from
|
||||
bank_account_type = frappe.db.get_value("Account", bank_account, "account_type")
|
||||
|
||||
|
||||
if bank_account_type == "Bank":
|
||||
if not self.reference_no or not self.reference_date:
|
||||
frappe.throw(_("Reference No and Reference Date is mandatory for Bank transaction"))
|
||||
|
||||
|
||||
def set_remarks(self):
|
||||
if self.remarks: return
|
||||
|
||||
|
||||
if self.payment_type=="Internal Transfer":
|
||||
remarks = [_("Amount {0} {1} transferred from {2} to {3}")
|
||||
.format(self.paid_from_account_currency, self.paid_amount, self.paid_from, self.paid_to)]
|
||||
else:
|
||||
|
||||
|
||||
remarks = [_("Amount {0} {1} {2} {3}").format(
|
||||
self.party_account_currency,
|
||||
self.paid_amount if self.payment_type=="Receive" else self.received_amount,
|
||||
_("received from") if self.payment_type=="Receive" else _("to"), self.party
|
||||
)]
|
||||
|
||||
|
||||
if self.reference_no:
|
||||
remarks.append(_("Transaction reference no {0} dated {1}")
|
||||
.format(self.reference_no, self.reference_date))
|
||||
@@ -358,35 +367,35 @@ class PaymentEntry(AccountsController):
|
||||
if self.payment_type in ["Receive", "Pay"]:
|
||||
for d in self.get("references"):
|
||||
if d.allocated_amount:
|
||||
remarks.append(_("Amount {0} {1} against {2} {3}").format(self.party_account_currency,
|
||||
remarks.append(_("Amount {0} {1} against {2} {3}").format(self.party_account_currency,
|
||||
d.allocated_amount, d.reference_doctype, d.reference_name))
|
||||
|
||||
|
||||
for d in self.get("deductions"):
|
||||
if d.amount:
|
||||
remarks.append(_("Amount {0} {1} deducted against {2}")
|
||||
.format(self.company_currency, d.amount, d.account))
|
||||
|
||||
self.set("remarks", "\n".join(remarks))
|
||||
|
||||
|
||||
def make_gl_entries(self, cancel=0, adv_adj=0):
|
||||
if self.payment_type in ("Receive", "Pay") and not self.get("party_account_field"):
|
||||
self.setup_party_account_field()
|
||||
|
||||
|
||||
gl_entries = []
|
||||
self.add_party_gl_entries(gl_entries)
|
||||
self.add_bank_gl_entries(gl_entries)
|
||||
self.add_deductions_gl_entries(gl_entries)
|
||||
|
||||
make_gl_entries(gl_entries, cancel=cancel, adv_adj=adv_adj)
|
||||
|
||||
|
||||
def add_party_gl_entries(self, gl_entries):
|
||||
if self.party_account:
|
||||
if self.payment_type=="Receive":
|
||||
against_account = self.paid_to
|
||||
else:
|
||||
against_account = self.paid_from
|
||||
|
||||
|
||||
|
||||
|
||||
party_gl_dict = self.get_gl_dict({
|
||||
"account": self.party_account,
|
||||
"party_type": self.party_type,
|
||||
@@ -394,39 +403,39 @@ class PaymentEntry(AccountsController):
|
||||
"against": against_account,
|
||||
"account_currency": self.party_account_currency
|
||||
})
|
||||
|
||||
|
||||
dr_or_cr = "credit" if self.party_type == "Customer" else "debit"
|
||||
|
||||
|
||||
for d in self.get("references"):
|
||||
gle = party_gl_dict.copy()
|
||||
gle.update({
|
||||
"against_voucher_type": d.reference_doctype,
|
||||
"against_voucher": d.reference_name
|
||||
})
|
||||
|
||||
allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate),
|
||||
self.precision("paid_amount"))
|
||||
|
||||
|
||||
allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate),
|
||||
self.precision("paid_amount"))
|
||||
|
||||
gle.update({
|
||||
dr_or_cr + "_in_account_currency": d.allocated_amount,
|
||||
dr_or_cr: allocated_amount_in_company_currency
|
||||
})
|
||||
|
||||
|
||||
gl_entries.append(gle)
|
||||
|
||||
|
||||
if self.unallocated_amount:
|
||||
base_unallocated_amount = base_unallocated_amount = self.unallocated_amount * \
|
||||
(self.source_exchange_rate if self.payment_type=="Receive" else self.target_exchange_rate)
|
||||
|
||||
|
||||
gle = party_gl_dict.copy()
|
||||
|
||||
|
||||
gle.update({
|
||||
dr_or_cr + "_in_account_currency": self.unallocated_amount,
|
||||
dr_or_cr: base_unallocated_amount
|
||||
})
|
||||
|
||||
gl_entries.append(gle)
|
||||
|
||||
|
||||
def add_bank_gl_entries(self, gl_entries):
|
||||
if self.payment_type in ("Pay", "Internal Transfer"):
|
||||
gl_entries.append(
|
||||
@@ -448,14 +457,14 @@ class PaymentEntry(AccountsController):
|
||||
"debit": self.base_received_amount
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
def add_deductions_gl_entries(self, gl_entries):
|
||||
for d in self.get("deductions"):
|
||||
if d.amount:
|
||||
account_currency = get_account_currency(d.account)
|
||||
if account_currency != self.company_currency:
|
||||
frappe.throw(_("Currency for {0} must be {1}").format(d.account, self.company_currency))
|
||||
|
||||
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": d.account,
|
||||
@@ -466,110 +475,131 @@ class PaymentEntry(AccountsController):
|
||||
"cost_center": d.cost_center
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
def update_advance_paid(self):
|
||||
if self.payment_type in ("Receive", "Pay") and self.party:
|
||||
for d in self.get("references"):
|
||||
if d.allocated_amount and d.reference_doctype in ("Sales Order", "Purchase Order"):
|
||||
frappe.get_doc(d.reference_doctype, d.reference_name).set_total_advance_paid()
|
||||
|
||||
def update_expense_claim(self):
|
||||
if self.payment_type in ("Pay") and self.party:
|
||||
for d in self.get("references"):
|
||||
if d.reference_doctype=="Expense Claim" and d.reference_name:
|
||||
doc = frappe.get_doc("Expense Claim", d.reference_name)
|
||||
update_reimbursed_amount(doc)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_outstanding_reference_documents(args):
|
||||
args = json.loads(args)
|
||||
|
||||
party_account_currency = get_account_currency(args.get("party_account"))
|
||||
company_currency = frappe.db.get_value("Company", args.get("company"), "default_currency")
|
||||
|
||||
|
||||
# Get negative outstanding sales /purchase invoices
|
||||
total_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
|
||||
|
||||
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"),
|
||||
|
||||
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"),
|
||||
args.get("party"), args.get("party_account"), total_field)
|
||||
|
||||
# Get positive outstanding sales /purchase invoices
|
||||
outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"),
|
||||
outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"),
|
||||
args.get("party_account"))
|
||||
|
||||
|
||||
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", "Expense Claim"):
|
||||
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"),
|
||||
orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"), args.get("party"),
|
||||
party_account_currency, company_currency)
|
||||
|
||||
|
||||
return negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
|
||||
|
||||
|
||||
def get_orders_to_be_billed(posting_date, party_type, party, party_account_currency, company_currency):
|
||||
voucher_type = 'Sales Order' if party_type == "Customer" else 'Purchase Order'
|
||||
if party_type == "Customer":
|
||||
voucher_type = 'Sales Order'
|
||||
elif party_type == "Supplier":
|
||||
voucher_type = 'Purchase Order'
|
||||
elif party_type == "Employee":
|
||||
voucher_type = None
|
||||
|
||||
ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
|
||||
orders = []
|
||||
if voucher_type:
|
||||
ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
|
||||
|
||||
orders = frappe.db.sql("""
|
||||
select
|
||||
name as voucher_no,
|
||||
{ref_field} as invoice_amount,
|
||||
({ref_field} - advance_paid) as outstanding_amount,
|
||||
transaction_date as posting_date
|
||||
from
|
||||
`tab{voucher_type}`
|
||||
where
|
||||
{party_type} = %s
|
||||
and docstatus = 1
|
||||
and ifnull(status, "") != "Closed"
|
||||
and {ref_field} > advance_paid
|
||||
and abs(100 - per_billed) > 0.01
|
||||
order by
|
||||
transaction_date, name
|
||||
""".format(**{
|
||||
"ref_field": ref_field,
|
||||
"voucher_type": voucher_type,
|
||||
"party_type": scrub(party_type)
|
||||
}), party, as_dict = True)
|
||||
orders = frappe.db.sql("""
|
||||
select
|
||||
name as voucher_no,
|
||||
{ref_field} as invoice_amount,
|
||||
({ref_field} - advance_paid) as outstanding_amount,
|
||||
transaction_date as posting_date
|
||||
from
|
||||
`tab{voucher_type}`
|
||||
where
|
||||
{party_type} = %s
|
||||
and docstatus = 1
|
||||
and ifnull(status, "") != "Closed"
|
||||
and {ref_field} > advance_paid
|
||||
and abs(100 - per_billed) > 0.01
|
||||
order by
|
||||
transaction_date, name
|
||||
""".format(**{
|
||||
"ref_field": ref_field,
|
||||
"voucher_type": voucher_type,
|
||||
"party_type": scrub(party_type)
|
||||
}), party, as_dict = True)
|
||||
|
||||
order_list = []
|
||||
for d in orders:
|
||||
d["voucher_type"] = voucher_type
|
||||
# This assumes that the exchange rate required is the one in the SO
|
||||
d["exchange_rate"] = get_exchange_rate(party_account_currency,
|
||||
d["exchange_rate"] = get_exchange_rate(party_account_currency,
|
||||
company_currency, posting_date)
|
||||
order_list.append(d)
|
||||
|
||||
return order_list
|
||||
|
||||
|
||||
def get_negative_outstanding_invoices(party_type, party, party_account, total_field):
|
||||
voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
|
||||
return frappe.db.sql("""
|
||||
select
|
||||
"{voucher_type}" as voucher_type, name as voucher_no,
|
||||
{total_field} as invoice_amount, outstanding_amount, posting_date,
|
||||
due_date, conversion_rate as exchange_rate
|
||||
from
|
||||
`tab{voucher_type}`
|
||||
where
|
||||
{party_type} = %s and {party_account} = %s and docstatus = 1 and outstanding_amount < 0
|
||||
order by
|
||||
posting_date, name
|
||||
""".format(**{
|
||||
"total_field": total_field,
|
||||
"voucher_type": voucher_type,
|
||||
"party_type": scrub(party_type),
|
||||
"party_account": "debit_to" if party_type=="Customer" else "credit_to"
|
||||
}), (party, party_account), as_dict = True)
|
||||
|
||||
if party_type != "Employee":
|
||||
voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
|
||||
return frappe.db.sql("""
|
||||
select
|
||||
"{voucher_type}" as voucher_type, name as voucher_no,
|
||||
{total_field} as invoice_amount, outstanding_amount, posting_date,
|
||||
due_date, conversion_rate as exchange_rate
|
||||
from
|
||||
`tab{voucher_type}`
|
||||
where
|
||||
{party_type} = %s and {party_account} = %s and docstatus = 1 and outstanding_amount < 0
|
||||
order by
|
||||
posting_date, name
|
||||
""".format(**{
|
||||
"total_field": total_field,
|
||||
"voucher_type": voucher_type,
|
||||
"party_type": scrub(party_type),
|
||||
"party_account": "debit_to" if party_type=="Customer" else "credit_to"
|
||||
}), (party, party_account), as_dict = True)
|
||||
else:
|
||||
return []
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_party_details(company, party_type, party, date):
|
||||
if not frappe.db.exists(party_type, party):
|
||||
frappe.throw(_("Invalid {0}: {1}").format(party_type, party))
|
||||
|
||||
|
||||
party_account = get_party_account(party_type, party, company)
|
||||
|
||||
|
||||
account_currency = get_account_currency(party_account)
|
||||
account_balance = get_balance_on(party_account, date)
|
||||
party_balance = get_balance_on(party_type=party_type, party=party)
|
||||
|
||||
|
||||
return {
|
||||
"party_account": party_account,
|
||||
"party_account_currency": account_currency,
|
||||
@@ -577,7 +607,7 @@ def get_party_details(company, party_type, party, date):
|
||||
"account_balance": account_balance
|
||||
}
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist()
|
||||
def get_account_details(account, date):
|
||||
frappe.has_permission('Payment Entry', throw=True)
|
||||
return frappe._dict({
|
||||
@@ -585,59 +615,67 @@ def get_account_details(account, date):
|
||||
"account_balance": get_balance_on(account, date),
|
||||
"account_type": frappe.db.get_value("Account", account, "account_type")
|
||||
})
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_company_defaults(company):
|
||||
fields = ["write_off_account", "exchange_gain_loss_account", "cost_center"]
|
||||
ret = frappe.db.get_value("Company", company, fields, as_dict=1)
|
||||
|
||||
|
||||
for fieldname in fields:
|
||||
if not ret[fieldname]:
|
||||
frappe.throw(_("Please set default {0} in Company {1}")
|
||||
.format(frappe.get_meta("Company").get_label(fieldname), company))
|
||||
|
||||
|
||||
return ret
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_reference_details(reference_doctype, reference_name, party_account_currency):
|
||||
total_amount = outstanding_amount = exchange_rate = None
|
||||
ref_doc = frappe.get_doc(reference_doctype, reference_name)
|
||||
|
||||
|
||||
if reference_doctype != "Journal Entry":
|
||||
if party_account_currency == ref_doc.company_currency:
|
||||
total_amount = ref_doc.base_grand_total
|
||||
if ref_doc.doctype == "Expense Claim":
|
||||
total_amount = ref_doc.total_sanctioned_amount
|
||||
else:
|
||||
total_amount = ref_doc.base_grand_total
|
||||
exchange_rate = 1
|
||||
else:
|
||||
total_amount = ref_doc.grand_total
|
||||
|
||||
# Get the exchange rate from the original ref doc
|
||||
|
||||
# Get the exchange rate from the original ref doc
|
||||
# or get it based on the posting date of the ref doc
|
||||
exchange_rate = ref_doc.get("conversion_rate") or \
|
||||
get_exchange_rate(party_account_currency, ref_doc.company_currency, ref_doc.posting_date)
|
||||
|
||||
|
||||
outstanding_amount = ref_doc.get("outstanding_amount") \
|
||||
if reference_doctype in ("Sales Invoice", "Purchase Invoice") \
|
||||
else flt(total_amount) - flt(ref_doc.advance_paid)
|
||||
if reference_doctype in ("Sales Invoice", "Purchase Invoice", "Expense Claim") \
|
||||
else flt(total_amount) - flt(ref_doc.advance_paid)
|
||||
else:
|
||||
# Get the exchange rate based on the posting date of the ref doc
|
||||
exchange_rate = get_exchange_rate(party_account_currency,
|
||||
exchange_rate = get_exchange_rate(party_account_currency,
|
||||
ref_doc.company_currency, ref_doc.posting_date)
|
||||
|
||||
|
||||
return frappe._dict({
|
||||
"due_date": ref_doc.get("due_date"),
|
||||
"total_amount": total_amount,
|
||||
"outstanding_amount": outstanding_amount,
|
||||
"exchange_rate": exchange_rate
|
||||
})
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=None):
|
||||
doc = frappe.get_doc(dt, dn)
|
||||
|
||||
|
||||
if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) > 0:
|
||||
frappe.throw(_("Can only make payment against unbilled {0}").format(dt))
|
||||
|
||||
party_type = "Customer" if dt in ("Sales Invoice", "Sales Order") else "Supplier"
|
||||
|
||||
if dt in ("Sales Invoice", "Sales Order"):
|
||||
party_type = "Customer"
|
||||
elif dt in ("Purchase Invoice", "Purchase Order"):
|
||||
party_type = "Supplier"
|
||||
elif dt in ("Expense Claim"):
|
||||
party_type = "Employee"
|
||||
|
||||
# party account
|
||||
if dt == "Sales Invoice":
|
||||
@@ -646,16 +684,16 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
party_account = doc.credit_to
|
||||
else:
|
||||
party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
|
||||
|
||||
|
||||
party_account_currency = doc.get("party_account_currency") or get_account_currency(party_account)
|
||||
|
||||
|
||||
# payment type
|
||||
if (dt == "Sales Order" or (dt=="Sales Invoice" and doc.outstanding_amount > 0)) \
|
||||
or (dt=="Purchase Invoice" and doc.outstanding_amount < 0):
|
||||
payment_type = "Receive"
|
||||
else:
|
||||
payment_type = "Pay"
|
||||
|
||||
|
||||
# amounts
|
||||
grand_total = outstanding_amount = 0
|
||||
if party_amount:
|
||||
@@ -663,15 +701,18 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
elif dt in ("Sales Invoice", "Purchase Invoice"):
|
||||
grand_total = doc.base_grand_total if party_account_currency == doc.company_currency else doc.grand_total
|
||||
outstanding_amount = doc.outstanding_amount
|
||||
elif dt in ("Expense Claim"):
|
||||
grand_total = doc.total_sanctioned_amount
|
||||
outstanding_amount = doc.total_sanctioned_amount - doc.total_amount_reimbursed
|
||||
else:
|
||||
total_field = "base_grand_total" if party_account_currency == doc.company_currency else "grand_total"
|
||||
grand_total = flt(doc.get(total_field))
|
||||
outstanding_amount = grand_total - flt(doc.advance_paid)
|
||||
|
||||
# bank or cash
|
||||
bank = get_default_bank_cash_account(doc.company, "Bank", mode_of_payment=doc.get("mode_of_payment"),
|
||||
bank = get_default_bank_cash_account(doc.company, "Bank", mode_of_payment=doc.get("mode_of_payment"),
|
||||
account=bank_account)
|
||||
|
||||
|
||||
paid_amount = received_amount = 0
|
||||
if party_account_currency == bank.account_currency:
|
||||
paid_amount = received_amount = abs(outstanding_amount)
|
||||
@@ -683,7 +724,7 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
received_amount = abs(outstanding_amount)
|
||||
if bank_amount:
|
||||
paid_amount = bank_amount
|
||||
|
||||
|
||||
pe = frappe.new_doc("Payment Entry")
|
||||
pe.payment_type = payment_type
|
||||
pe.company = doc.company
|
||||
@@ -700,7 +741,7 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
pe.received_amount = received_amount
|
||||
pe.allocate_payment_amount = 1
|
||||
pe.letter_head = doc.get("letter_head")
|
||||
|
||||
|
||||
pe.append("references", {
|
||||
"reference_doctype": dt,
|
||||
"reference_name": dn,
|
||||
|
||||
@@ -10,6 +10,7 @@ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_orde
|
||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry, InvalidPaymentEntry
|
||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||
from erpnext.hr.doctype.expense_claim.test_expense_claim import make_expense_claim
|
||||
|
||||
test_dependencies = ["Item"]
|
||||
|
||||
@@ -20,80 +21,102 @@ class TestPaymentEntry(unittest.TestCase):
|
||||
pe.paid_from = "Debtors - _TC"
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
|
||||
expected_gle = dict((d[0], d) for d in [
|
||||
["Debtors - _TC", 0, 1000, so.name],
|
||||
["_Test Cash - _TC", 1000.0, 0, None]
|
||||
])
|
||||
|
||||
|
||||
self.validate_gl_entries(pe.name, expected_gle)
|
||||
|
||||
|
||||
so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
|
||||
self.assertEqual(so_advance_paid, 1000)
|
||||
|
||||
|
||||
pe.cancel()
|
||||
|
||||
|
||||
self.assertFalse(self.get_gle(pe.name))
|
||||
|
||||
|
||||
so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
|
||||
self.assertEqual(so_advance_paid, 0)
|
||||
|
||||
|
||||
def test_payment_entry_against_si_usd_to_usd(self):
|
||||
si = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
|
||||
currency="USD", conversion_rate=50)
|
||||
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
|
||||
pe.reference_no = "1"
|
||||
pe.reference_date = "2016-01-01"
|
||||
pe.target_exchange_rate = 50
|
||||
pe.target_exchange_rate = 50
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
|
||||
expected_gle = dict((d[0], d) for d in [
|
||||
["_Test Receivable USD - _TC", 0, 5000, si.name],
|
||||
["_Test Bank USD - _TC", 5000.0, 0, None]
|
||||
])
|
||||
|
||||
|
||||
self.validate_gl_entries(pe.name, expected_gle)
|
||||
|
||||
|
||||
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
|
||||
self.assertEqual(outstanding_amount, 0)
|
||||
|
||||
|
||||
pe.cancel()
|
||||
self.assertFalse(self.get_gle(pe.name))
|
||||
|
||||
|
||||
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
|
||||
self.assertEqual(outstanding_amount, 100)
|
||||
|
||||
|
||||
def test_payment_entry_against_pi(self):
|
||||
pi = make_purchase_invoice(supplier="_Test Supplier USD", debit_to="_Test Payable USD - _TC",
|
||||
currency="USD", conversion_rate=50)
|
||||
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank USD - _TC")
|
||||
pe.reference_no = "1"
|
||||
pe.reference_date = "2016-01-01"
|
||||
pe.source_exchange_rate = 50
|
||||
pe.source_exchange_rate = 50
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
|
||||
expected_gle = dict((d[0], d) for d in [
|
||||
["_Test Payable USD - _TC", 12500, 0, pi.name],
|
||||
["_Test Bank USD - _TC", 0, 12500, None]
|
||||
])
|
||||
|
||||
|
||||
self.validate_gl_entries(pe.name, expected_gle)
|
||||
|
||||
|
||||
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", pi.name, "outstanding_amount"))
|
||||
self.assertEqual(outstanding_amount, 0)
|
||||
|
||||
|
||||
def test_payment_entry_against_ec(self):
|
||||
|
||||
payable = frappe.db.get_value('Company', "_Test Company", 'default_payable_account')
|
||||
ec = make_expense_claim(payable, 300, 300, "_Test Company","Travel Expenses - _TC")
|
||||
pe = get_payment_entry("Expense Claim", ec.name, bank_account="_Test Bank USD - _TC", bank_amount=300)
|
||||
pe.reference_no = "1"
|
||||
pe.reference_date = "2016-01-01"
|
||||
pe.source_exchange_rate = 1
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
expected_gle = dict((d[0], d) for d in [
|
||||
[payable, 300, 0, ec.name],
|
||||
["_Test Bank USD - _TC", 0, 300, None]
|
||||
])
|
||||
|
||||
self.validate_gl_entries(pe.name, expected_gle)
|
||||
|
||||
outstanding_amount = flt(frappe.db.get_value("Expense Claim", ec.name, "total_sanctioned_amount")) - \
|
||||
flt(frappe.db.get_value("Expense Claim", ec.name, "total_amount_reimbursed"))
|
||||
self.assertEqual(outstanding_amount, 0)
|
||||
|
||||
def test_payment_entry_against_si_usd_to_inr(self):
|
||||
si = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
|
||||
currency="USD", conversion_rate=50)
|
||||
pe = get_payment_entry("Sales Invoice", si.name, party_amount=20,
|
||||
pe = get_payment_entry("Sales Invoice", si.name, party_amount=20,
|
||||
bank_account="_Test Bank - _TC", bank_amount=900)
|
||||
pe.reference_no = "1"
|
||||
pe.reference_date = "2016-01-01"
|
||||
|
||||
|
||||
self.assertEqual(pe.difference_amount, 100)
|
||||
|
||||
|
||||
pe.append("deductions", {
|
||||
"account": "_Test Exchange Gain/Loss - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
@@ -101,15 +124,15 @@ class TestPaymentEntry(unittest.TestCase):
|
||||
})
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
|
||||
expected_gle = dict((d[0], d) for d in [
|
||||
["_Test Receivable USD - _TC", 0, 1000, si.name],
|
||||
["_Test Bank - _TC", 900, 0, None],
|
||||
["_Test Exchange Gain/Loss - _TC", 100.0, 0, None],
|
||||
])
|
||||
|
||||
|
||||
self.validate_gl_entries(pe.name, expected_gle)
|
||||
|
||||
|
||||
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
|
||||
self.assertEqual(outstanding_amount, 80)
|
||||
|
||||
@@ -140,7 +163,7 @@ class TestPaymentEntry(unittest.TestCase):
|
||||
pe.source_exchange_rate, 65.1,
|
||||
"{0} is not equal to {1}".format(pe.source_exchange_rate, 65.1)
|
||||
)
|
||||
|
||||
|
||||
def test_internal_transfer_usd_to_inr(self):
|
||||
pe = frappe.new_doc("Payment Entry")
|
||||
pe.payment_type = "Internal Transfer"
|
||||
@@ -152,31 +175,31 @@ class TestPaymentEntry(unittest.TestCase):
|
||||
pe.received_amount = 4500
|
||||
pe.reference_no = "2"
|
||||
pe.reference_date = nowdate()
|
||||
|
||||
|
||||
pe.setup_party_account_field()
|
||||
pe.set_missing_values()
|
||||
pe.set_exchange_rate()
|
||||
pe.set_amounts()
|
||||
|
||||
|
||||
self.assertEquals(pe.difference_amount, 500)
|
||||
|
||||
|
||||
pe.append("deductions", {
|
||||
"account": "_Test Exchange Gain/Loss - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"amount": 500
|
||||
})
|
||||
|
||||
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
|
||||
expected_gle = dict((d[0], d) for d in [
|
||||
["_Test Bank USD - _TC", 0, 5000, None],
|
||||
["_Test Bank - _TC", 4500, 0, None],
|
||||
["_Test Exchange Gain/Loss - _TC", 500.0, 0, None],
|
||||
])
|
||||
|
||||
|
||||
self.validate_gl_entries(pe.name, expected_gle)
|
||||
|
||||
|
||||
def test_payment_against_negative_sales_invoice(self):
|
||||
pe1 = frappe.new_doc("Payment Entry")
|
||||
pe1.payment_type = "Pay"
|
||||
@@ -186,33 +209,33 @@ class TestPaymentEntry(unittest.TestCase):
|
||||
pe1.paid_from = "_Test Cash - _TC"
|
||||
pe1.paid_amount = 100
|
||||
pe1.received_amount = 100
|
||||
|
||||
|
||||
self.assertRaises(InvalidPaymentEntry, pe1.validate)
|
||||
|
||||
|
||||
si1 = create_sales_invoice()
|
||||
|
||||
|
||||
# create full payment entry against si1
|
||||
pe2 = get_payment_entry("Sales Invoice", si1.name, bank_account="_Test Cash - _TC")
|
||||
pe2.insert()
|
||||
pe2.submit()
|
||||
|
||||
|
||||
# create return entry against si1
|
||||
create_sales_invoice(is_return=1, return_against=si1.name, qty=-1)
|
||||
si1_outstanding = frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount")
|
||||
self.assertEqual(si1_outstanding, -100)
|
||||
|
||||
|
||||
# pay more than outstanding against si1
|
||||
pe3 = get_payment_entry("Sales Invoice", si1.name, bank_account="_Test Cash - _TC")
|
||||
pe3.paid_amount = pe3.received_amount = 300
|
||||
self.assertRaises(InvalidPaymentEntry, pe3.validate)
|
||||
|
||||
|
||||
# pay negative outstanding against si1
|
||||
pe3.paid_to = "Debtors - _TC"
|
||||
pe3.paid_amount = pe3.received_amount = 100
|
||||
|
||||
|
||||
pe3.insert()
|
||||
pe3.submit()
|
||||
|
||||
|
||||
expected_gle = dict((d[0], d) for d in [
|
||||
["Debtors - _TC", 100, 0, si1.name],
|
||||
["_Test Cash - _TC", 0, 100, None]
|
||||
@@ -228,10 +251,10 @@ class TestPaymentEntry(unittest.TestCase):
|
||||
|
||||
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount"))
|
||||
self.assertEqual(outstanding_amount, -100)
|
||||
|
||||
|
||||
def validate_gl_entries(self, voucher_no, expected_gle):
|
||||
gl_entries = self.get_gle(voucher_no)
|
||||
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
@@ -239,7 +262,7 @@ class TestPaymentEntry(unittest.TestCase):
|
||||
self.assertEquals(expected_gle[gle.account][1], gle.debit)
|
||||
self.assertEquals(expected_gle[gle.account][2], gle.credit)
|
||||
self.assertEquals(expected_gle[gle.account][3], gle.against_voucher)
|
||||
|
||||
|
||||
def get_gle(self, voucher_no):
|
||||
return frappe.db.sql("""select account, debit, credit, against_voucher
|
||||
from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
|
||||
|
||||
@@ -75,8 +75,8 @@ class PaymentRequest(Document):
|
||||
|
||||
return controller.get_payment_url(**{
|
||||
"amount": flt(self.grand_total, self.precision("grand_total")),
|
||||
"title": data.company,
|
||||
"description": self.subject,
|
||||
"title": data.company.encode("utf-8"),
|
||||
"description": self.subject.encode("utf-8"),
|
||||
"reference_doctype": "Payment Request",
|
||||
"reference_docname": self.name,
|
||||
"payer_email": self.email_to or frappe.session.user,
|
||||
|
||||
@@ -721,38 +721,6 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "tc_name",
|
||||
"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": "Terms and Conditions",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "tc_name",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Terms and Conditions",
|
||||
"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,
|
||||
@@ -782,39 +750,6 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "",
|
||||
"fieldname": "territory",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Territory",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "territory",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Territory",
|
||||
"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,
|
||||
@@ -847,6 +782,38 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "tc_name",
|
||||
"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": "Terms and Conditions",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "tc_name",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Terms and Conditions",
|
||||
"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,
|
||||
@@ -910,6 +877,129 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "customer_details",
|
||||
"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": "New Customer Details",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "",
|
||||
"fieldname": "territory",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Territory",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "territory",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Territory",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_31",
|
||||
"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": "customer_group",
|
||||
"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": "Customer Group",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Customer Group",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@@ -1201,7 +1291,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-06-16 17:04:33.165676",
|
||||
"modified": "2017-07-28 03:40:03.253088",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Profile",
|
||||
|
||||
@@ -14,6 +14,8 @@ class POSProfile(Document):
|
||||
self.check_for_duplicate()
|
||||
self.validate_all_link_fields()
|
||||
self.validate_duplicate_groups()
|
||||
self.check_default_payment()
|
||||
self.validate_customer_territory_group()
|
||||
|
||||
def check_for_duplicate(self):
|
||||
res = frappe.db.sql("""select name, user from `tabPOS Profile`
|
||||
@@ -48,6 +50,21 @@ class POSProfile(Document):
|
||||
if len(customer_groups) != len(set(customer_groups)):
|
||||
frappe.throw(_("Duplicate customer group found in the cutomer group table"), title = "Duplicate Customer Group")
|
||||
|
||||
def check_default_payment(self):
|
||||
if self.payments:
|
||||
default_mode_of_payment = [d.default for d in self.payments if d.default]
|
||||
if not default_mode_of_payment:
|
||||
frappe.throw(_("Set default mode of payment"))
|
||||
|
||||
if len(default_mode_of_payment) > 1:
|
||||
frappe.throw(_("Multiple default mode of payment is not allowed"))
|
||||
def validate_customer_territory_group(self):
|
||||
if not self.territory:
|
||||
frappe.throw(_("Territory is Required in POS Profile"), title="Mandatory Field")
|
||||
|
||||
if not self.customer_group:
|
||||
frappe.throw(_("Customer Group is Required in POS Profile"), title="Mandatory Field")
|
||||
|
||||
def before_save(self):
|
||||
set_account_for_mode_of_payment(self)
|
||||
|
||||
|
||||
23
erpnext/accounts/doctype/pos_profile/test_pos_profile.js
Normal file
23
erpnext/accounts/doctype/pos_profile/test_pos_profile.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: POS Profile", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially('POS Profile', [
|
||||
// insert a new POS Profile
|
||||
() => frappe.tests.make([
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
||||
@@ -31,6 +31,8 @@ class TestPOSProfile(unittest.TestCase):
|
||||
frappe.db.sql("delete from `tabPOS Profile`")
|
||||
|
||||
def make_pos_profile():
|
||||
frappe.db.sql("delete from `tabPOS Profile`")
|
||||
|
||||
pos_profile = frappe.get_doc({
|
||||
"company": "_Test Company",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
@@ -42,6 +44,7 @@ def make_pos_profile():
|
||||
"naming_series": "_T-POS Profile-",
|
||||
"selling_price_list": "_Test Price List",
|
||||
"territory": "_Test Territory",
|
||||
"customer_group": frappe.db.get_value('Customer Group', {'is_group': 0}, 'name'),
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"write_off_account": "_Test Write Off - _TC",
|
||||
"write_off_cost_center": "_Test Write Off Cost Center - _TC"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -285,8 +285,9 @@ def get_pricing_rules(args):
|
||||
|
||||
def filter_pricing_rules(args, pricing_rules):
|
||||
# filter for qty
|
||||
stock_qty = args.get('qty') * args.get('conversion_factor', 1)
|
||||
if pricing_rules:
|
||||
stock_qty = flt(args.get('qty')) * args.get('conversion_factor', 1)
|
||||
|
||||
pricing_rules = filter(lambda x: (flt(stock_qty)>=flt(x.min_qty)
|
||||
and (flt(stock_qty)<=x.max_qty if x.max_qty else True)), pricing_rules)
|
||||
|
||||
|
||||
28
erpnext/accounts/doctype/pricing_rule/test_pricing_rule.js
Normal file
28
erpnext/accounts/doctype/pricing_rule/test_pricing_rule.js
Normal file
@@ -0,0 +1,28 @@
|
||||
QUnit.module('Pricing Rule"');
|
||||
|
||||
QUnit.test("test pricing rule", function(assert) {
|
||||
assert.expect(2);
|
||||
let done = assert.async();
|
||||
frappe.run_serially([
|
||||
() => {
|
||||
return frappe.tests.make("Pricing Rule", [
|
||||
{title: 'Test Pricing Rule'},
|
||||
{item_code:'Test Product 2'},
|
||||
{selling:1},
|
||||
{applicable_for:'Customer'},
|
||||
{customer:'Test Customer 3'},
|
||||
{min_qty:1},
|
||||
{max_qty:20},
|
||||
{valid_upto: frappe.datetime.add_days(frappe.defaults.get_default("year_end_date"), 1)},
|
||||
{discount_percentage:10},
|
||||
{for_price_list:'Standard Selling'}
|
||||
]);
|
||||
},
|
||||
() => {
|
||||
assert.ok(cur_frm.doc.item_code=='Test Product 2');
|
||||
assert.ok(cur_frm.doc.customer=='Test Customer 3');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -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))
|
||||
@@ -1516,6 +1516,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,
|
||||
@@ -1523,7 +1553,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "HTML",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -1533,12 +1563,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,
|
||||
@@ -3767,7 +3797,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2017-06-29 10:48:09.707735",
|
||||
"modified": "2017-07-19 13:53:48.673757",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
||||
@@ -510,7 +510,7 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
i += 1
|
||||
|
||||
if self.update_stock and valuation_tax:
|
||||
if self.auto_accounting_for_stock and self.update_stock and valuation_tax:
|
||||
for cost_center, amount in valuation_tax.items():
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe, json
|
||||
from frappe import _
|
||||
from frappe.utils import nowdate
|
||||
from erpnext.setup.utils import get_exchange_rate
|
||||
from frappe.core.doctype.communication.email import make
|
||||
@@ -20,6 +21,7 @@ def get_pos_data():
|
||||
|
||||
if pos_profile.get('name'):
|
||||
pos_profile = frappe.get_doc('POS Profile', pos_profile.get('name'))
|
||||
pos_profile.validate()
|
||||
|
||||
company_data = get_company_data(doc.company)
|
||||
update_pos_profile_data(doc, pos_profile, company_data)
|
||||
@@ -378,13 +380,27 @@ def add_customer(data):
|
||||
customer_doc.customer_name = data.get('full_name') or data.get('customer')
|
||||
customer_doc.customer_pos_id = data.get('customer_pos_id')
|
||||
customer_doc.customer_type = 'Company'
|
||||
customer_doc.customer_group = frappe.db.get_single_value('Selling Settings', 'customer_group')
|
||||
customer_doc.territory = frappe.db.get_single_value('Selling Settings', 'territory')
|
||||
customer_doc.customer_group = get_customer_group(data)
|
||||
customer_doc.territory = get_territory(data)
|
||||
customer_doc.flags.ignore_mandatory = True
|
||||
customer_doc.save(ignore_permissions = True)
|
||||
frappe.db.commit()
|
||||
return customer_doc.name
|
||||
|
||||
def get_territory(data):
|
||||
if data.get('territory'):
|
||||
return data.get('territory')
|
||||
|
||||
return frappe.db.get_single_value('Selling Settings',
|
||||
'territory') or _('All Territories')
|
||||
|
||||
def get_customer_group(data):
|
||||
if data.get('customer_group'):
|
||||
return data.get('customer_group')
|
||||
|
||||
return frappe.db.get_single_value('Selling Settings',
|
||||
'customer_group') or frappe.db.get_value('Customer Group', {'is_group': 0}, 'name')
|
||||
|
||||
def make_contact(args,customer):
|
||||
if args.get('email_id') or args.get('phone'):
|
||||
name = frappe.db.get_value('Dynamic Link',
|
||||
@@ -469,7 +485,7 @@ def submit_invoice(si_doc, name, doc):
|
||||
si_doc.insert()
|
||||
si_doc.submit()
|
||||
frappe.db.commit()
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
if frappe.message_log: frappe.message_log.pop()
|
||||
frappe.db.rollback()
|
||||
save_invoice(e, si_doc, name)
|
||||
|
||||
@@ -98,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) {
|
||||
@@ -306,7 +326,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
|
||||
this.frm.refresh_fields();
|
||||
},
|
||||
|
||||
|
||||
company_address: function() {
|
||||
var me = this;
|
||||
if(this.frm.doc.company_address) {
|
||||
@@ -343,13 +363,6 @@ cur_frm.cscript.hide_fields = function(doc) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var item_fields_stock = ['batch_no', 'actual_batch_qty', 'actual_qty', 'expense_account',
|
||||
'warehouse', 'expense_account', 'quality_inspection']
|
||||
cur_frm.fields_dict['items'].grid.set_column_disp(item_fields_stock,
|
||||
(cint(doc.update_stock)==1 || cint(doc.is_return)==1 ? true : false));
|
||||
|
||||
|
||||
// India related fields
|
||||
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
|
||||
else hide_field(['c_form_applicable', 'c_form_no']);
|
||||
@@ -445,24 +458,6 @@ cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
|
||||
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center");
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -139,6 +140,8 @@ class SalesInvoice(SellingController):
|
||||
|
||||
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."))
|
||||
@@ -803,19 +806,27 @@ class SalesInvoice(SellingController):
|
||||
continue
|
||||
|
||||
for serial_no in item.serial_no.split("\n"):
|
||||
sno = frappe.get_doc('Serial No', serial_no)
|
||||
sno.sales_invoice = invoice
|
||||
sno.db_update()
|
||||
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
|
||||
|
||||
@@ -11,8 +11,7 @@ def get_data():
|
||||
'Sales Invoice': 'return_against'
|
||||
},
|
||||
'internal_links': {
|
||||
'Sales Order': ['items', 'sales_order'],
|
||||
'Delivery Note': ['items', 'delivery_note']
|
||||
'Sales Order': ['items', 'sales_order']
|
||||
},
|
||||
'transactions': [
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
import unittest, copy
|
||||
from frappe.utils import nowdate, add_days, flt
|
||||
from frappe.model.dynamic_links import get_dynamic_link_map
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
|
||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice
|
||||
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
|
||||
@@ -13,6 +14,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):
|
||||
@@ -166,15 +168,15 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"_Test Account S&H Education Cess - _TC": [1.5, 1619.5, 0.03, 32.39],
|
||||
"_Test Account CST - _TC": [32.5, 1652, 0.65, 33.04],
|
||||
"_Test Account VAT - _TC": [156.5, 1808.5, 3.13, 36.17],
|
||||
"_Test Account Discount - _TC": [-180.5, 1628, -3.61, 32.56]
|
||||
"_Test Account Discount - _TC": [-181.0, 1627.5, -3.62, 32.55]
|
||||
}
|
||||
|
||||
for d in si.get("taxes"):
|
||||
for i, k in enumerate(expected_values["keys"]):
|
||||
self.assertEquals(d.get(k), expected_values[d.account_head][i])
|
||||
|
||||
self.assertEquals(si.base_grand_total, 1628)
|
||||
self.assertEquals(si.grand_total, 32.56)
|
||||
self.assertEquals(si.base_grand_total, 1627.5)
|
||||
self.assertEquals(si.grand_total, 32.55)
|
||||
|
||||
def test_sales_invoice_with_discount_and_inclusive_tax(self):
|
||||
si = create_sales_invoice(qty=100, rate=50, do_not_save=True)
|
||||
@@ -234,21 +236,29 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"item_code": "_Test Item Home Desktop 100",
|
||||
"price_list_rate": 62.5,
|
||||
"discount_percentage": 0,
|
||||
"rate": 62.5, "amount": 625,
|
||||
"rate": 62.5,
|
||||
"amount": 625,
|
||||
"base_price_list_rate": 62.5,
|
||||
"base_rate": 62.5, "base_amount": 625,
|
||||
"net_rate": 46.54, "net_amount": 465.37,
|
||||
"base_net_rate": 46.54, "base_net_amount": 465.37
|
||||
"base_rate": 62.5,
|
||||
"base_amount": 625,
|
||||
"net_rate": 46.54,
|
||||
"net_amount": 465.37,
|
||||
"base_net_rate": 46.54,
|
||||
"base_net_amount": 465.37
|
||||
},
|
||||
{
|
||||
"item_code": "_Test Item Home Desktop 200",
|
||||
"price_list_rate": 190.66,
|
||||
"discount_percentage": 0,
|
||||
"rate": 190.66, "amount": 953.3,
|
||||
"rate": 190.66,
|
||||
"amount": 953.3,
|
||||
"base_price_list_rate": 190.66,
|
||||
"base_rate": 190.66, "base_amount": 953.3,
|
||||
"net_rate": 139.62, "net_amount": 698.08,
|
||||
"base_net_rate": 139.62, "base_net_amount": 698.08
|
||||
"base_rate": 190.66,
|
||||
"base_amount": 953.3,
|
||||
"net_rate": 139.62,
|
||||
"net_amount": 698.08,
|
||||
"base_net_rate": 139.62,
|
||||
"base_net_amount": 698.08
|
||||
}
|
||||
]
|
||||
|
||||
@@ -269,13 +279,13 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"keys": ["tax_amount", "tax_amount_after_discount_amount", "total"],
|
||||
"_Test Account Excise Duty - _TC": [140, 130.31, 1293.76],
|
||||
"_Test Account Education Cess - _TC": [2.8, 2.61, 1296.37],
|
||||
"_Test Account S&H Education Cess - _TC": [1.4, 1.31, 1297.68],
|
||||
"_Test Account CST - _TC": [27.88, 25.96, 1323.64],
|
||||
"_Test Account VAT - _TC": [156.25, 145.43, 1469.07],
|
||||
"_Test Account Customs Duty - _TC": [125, 116.35, 1585.42],
|
||||
"_Test Account Shipping Charges - _TC": [100, 100, 1685.42],
|
||||
"_Test Account Discount - _TC": [-180.33, -168.54, 1516.88],
|
||||
"_Test Account Service Tax - _TC": [-18.03, -16.88, 1500]
|
||||
"_Test Account S&H Education Cess - _TC": [1.4, 1.30, 1297.67],
|
||||
"_Test Account CST - _TC": [27.88, 25.95, 1323.62],
|
||||
"_Test Account VAT - _TC": [156.25, 145.43, 1469.05],
|
||||
"_Test Account Customs Duty - _TC": [125, 116.35, 1585.40],
|
||||
"_Test Account Shipping Charges - _TC": [100, 100, 1685.40],
|
||||
"_Test Account Discount - _TC": [-180.33, -168.54, 1516.86],
|
||||
"_Test Account Service Tax - _TC": [-18.03, -16.86, 1500]
|
||||
}
|
||||
|
||||
for d in si.get("taxes"):
|
||||
@@ -311,13 +321,13 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
[test_records[3]["items"][0]["income_account"], 0.0, 1163.45],
|
||||
[test_records[3]["taxes"][0]["account_head"], 0.0, 130.31],
|
||||
[test_records[3]["taxes"][1]["account_head"], 0.0, 2.61],
|
||||
[test_records[3]["taxes"][2]["account_head"], 0.0, 1.31],
|
||||
[test_records[3]["taxes"][3]["account_head"], 0.0, 25.96],
|
||||
[test_records[3]["taxes"][2]["account_head"], 0.0, 1.30],
|
||||
[test_records[3]["taxes"][3]["account_head"], 0.0, 25.95],
|
||||
[test_records[3]["taxes"][4]["account_head"], 0.0, 145.43],
|
||||
[test_records[3]["taxes"][5]["account_head"], 0.0, 116.35],
|
||||
[test_records[3]["taxes"][6]["account_head"], 0.0, 100],
|
||||
[test_records[3]["taxes"][7]["account_head"], 168.54, 0.0],
|
||||
["_Test Account Service Tax - _TC", 16.88, 0.0],
|
||||
["_Test Account Service Tax - _TC", 16.86, 0.0]
|
||||
])
|
||||
|
||||
for gle in gl_entries:
|
||||
@@ -333,6 +343,61 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
|
||||
self.assertFalse(gle)
|
||||
|
||||
def test_tax_calculation_with_multiple_items(self):
|
||||
si = create_sales_invoice(qty=84, rate=4.6, do_not_save=True)
|
||||
item_row = si.get("items")[0]
|
||||
for qty in (54, 288, 144, 430):
|
||||
item_row_copy = copy.deepcopy(item_row)
|
||||
item_row_copy.qty = qty
|
||||
si.append("items", item_row_copy)
|
||||
|
||||
si.append("taxes", {
|
||||
"account_head": "_Test Account VAT - _TC",
|
||||
"charge_type": "On Net Total",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"description": "VAT",
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"rate": 19
|
||||
})
|
||||
si.insert()
|
||||
|
||||
self.assertEquals(si.net_total, 4600)
|
||||
|
||||
self.assertEquals(si.get("taxes")[0].tax_amount, 874.0)
|
||||
self.assertEquals(si.get("taxes")[0].total, 5474.0)
|
||||
|
||||
self.assertEquals(si.grand_total, 5474.0)
|
||||
|
||||
def test_tax_calculation_with_multiple_items_and_discount(self):
|
||||
si = create_sales_invoice(qty=1, rate=75, do_not_save=True)
|
||||
item_row = si.get("items")[0]
|
||||
for rate in (500, 200, 100, 50, 50):
|
||||
item_row_copy = copy.deepcopy(item_row)
|
||||
item_row_copy.price_list_rate = rate
|
||||
item_row_copy.rate = rate
|
||||
si.append("items", item_row_copy)
|
||||
|
||||
si.apply_discount_on = "Net Total"
|
||||
si.discount_amount = 75.0
|
||||
|
||||
si.append("taxes", {
|
||||
"account_head": "_Test Account VAT - _TC",
|
||||
"charge_type": "On Net Total",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"description": "VAT",
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"rate": 24
|
||||
})
|
||||
si.insert()
|
||||
|
||||
self.assertEquals(si.total, 975)
|
||||
self.assertEquals(si.net_total, 900)
|
||||
|
||||
self.assertEquals(si.get("taxes")[0].tax_amount, 216.0)
|
||||
self.assertEquals(si.get("taxes")[0].total, 1116.0)
|
||||
|
||||
self.assertEquals(si.grand_total, 1116.0)
|
||||
|
||||
def test_inclusive_rate_validations(self):
|
||||
si = frappe.copy_doc(test_records[2])
|
||||
for i, tax in enumerate(si.get("taxes")):
|
||||
@@ -415,21 +480,29 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"item_code": "_Test Item Home Desktop 100",
|
||||
"price_list_rate": 55.56,
|
||||
"discount_percentage": 10,
|
||||
"rate": 50, "amount": 500,
|
||||
"rate": 50,
|
||||
"amount": 500,
|
||||
"base_price_list_rate": 2778,
|
||||
"base_rate": 2500, "base_amount": 25000,
|
||||
"net_rate": 40, "net_amount": 399.98,
|
||||
"base_net_rate": 2000, "base_net_amount": 19999
|
||||
"base_rate": 2500,
|
||||
"base_amount": 25000,
|
||||
"net_rate": 40,
|
||||
"net_amount": 399.98,
|
||||
"base_net_rate": 2000,
|
||||
"base_net_amount": 19999
|
||||
},
|
||||
{
|
||||
"item_code": "_Test Item Home Desktop 200",
|
||||
"price_list_rate": 187.5,
|
||||
"discount_percentage": 20,
|
||||
"rate": 150, "amount": 750,
|
||||
"rate": 150,
|
||||
"amount": 750,
|
||||
"base_price_list_rate": 9375,
|
||||
"base_rate": 7500, "base_amount": 37500,
|
||||
"net_rate": 118.01, "net_amount": 590.05,
|
||||
"base_net_rate": 5900.5, "base_net_amount": 29502.5
|
||||
"base_rate": 7500,
|
||||
"base_amount": 37500,
|
||||
"net_rate": 118.01,
|
||||
"net_amount": 590.05,
|
||||
"base_net_rate": 5900.5,
|
||||
"base_net_amount": 29502.5
|
||||
}
|
||||
]
|
||||
|
||||
@@ -449,22 +522,22 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
# check tax calculation
|
||||
expected_values = {
|
||||
"keys": ["base_tax_amount", "base_total", "tax_amount", "total"],
|
||||
"_Test Account Excise Duty - _TC": [5540.5, 55042, 110.81, 1100.84],
|
||||
"_Test Account Education Cess - _TC": [111, 55153, 2.22, 1103.06],
|
||||
"_Test Account S&H Education Cess - _TC": [55.5, 55208.5, 1.11, 1104.17],
|
||||
"_Test Account CST - _TC": [1104, 56312.5, 22.08, 1126.25],
|
||||
"_Test Account VAT - _TC": [6188, 62500.5, 123.76, 1250.01],
|
||||
"_Test Account Customs Duty - _TC": [4950.5, 67451, 99.01, 1349.02],
|
||||
"_Test Account Shipping Charges - _TC": [ 100, 67551, 2, 1351.02],
|
||||
"_Test Account Discount - _TC": [ -6755, 60796, -135.10, 1215.92]
|
||||
"_Test Account Excise Duty - _TC": [5540.0, 55041.5, 110.80, 1100.83],
|
||||
"_Test Account Education Cess - _TC": [111, 55152.5, 2.22, 1103.05],
|
||||
"_Test Account S&H Education Cess - _TC": [55.5, 55208.0, 1.11, 1104.16],
|
||||
"_Test Account CST - _TC": [1104, 56312.0, 22.08, 1126.24],
|
||||
"_Test Account VAT - _TC": [6187.5, 62499.5, 123.75, 1249.99],
|
||||
"_Test Account Customs Duty - _TC": [4950.0, 67449.5, 99.0, 1348.99],
|
||||
"_Test Account Shipping Charges - _TC": [ 100, 67549.5, 2, 1350.99],
|
||||
"_Test Account Discount - _TC": [ -6755, 60794.5, -135.10, 1215.89]
|
||||
}
|
||||
|
||||
for d in si.get("taxes"):
|
||||
for i, k in enumerate(expected_values["keys"]):
|
||||
self.assertEquals(d.get(k), expected_values[d.account_head][i])
|
||||
|
||||
self.assertEquals(si.base_grand_total, 60796)
|
||||
self.assertEquals(si.grand_total, 1215.92)
|
||||
self.assertEquals(si.base_grand_total, 60794.5)
|
||||
self.assertEquals(si.grand_total, 1215.89)
|
||||
|
||||
def test_outstanding(self):
|
||||
w = self.make()
|
||||
@@ -484,6 +557,12 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
|
||||
self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 161.8)
|
||||
|
||||
link_data = get_dynamic_link_map().get('Sales Invoice', [])
|
||||
link_doctypes = [d.parent for d in link_data]
|
||||
|
||||
# test case for dynamic link order
|
||||
self.assertTrue(link_doctypes.index('GL Entry') > link_doctypes.index('Journal Entry Account'))
|
||||
|
||||
jv.cancel()
|
||||
self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 561.8)
|
||||
|
||||
@@ -909,19 +988,20 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"_Test Account Excise Duty - _TC": [70, 70, 70],
|
||||
"_Test Account Education Cess - _TC": [1.4, 1.4, 1.4],
|
||||
"_Test Account S&H Education Cess - _TC": [.7, 0.7, 0.7],
|
||||
"_Test Account CST - _TC": [17.2, 17.2, 17.2],
|
||||
"_Test Account CST - _TC": [17.19, 17.19, 17.19],
|
||||
"_Test Account VAT - _TC": [78.13, 78.13, 78.13],
|
||||
"_Test Account Discount - _TC": [-95.49, -95.49, -95.49]
|
||||
}
|
||||
|
||||
for d in si.get("taxes"):
|
||||
for i, k in enumerate(expected_values["keys"]):
|
||||
self.assertEquals(d.get(k), expected_values[d.account_head][i])
|
||||
if expected_values.get(d.account_head):
|
||||
self.assertEquals(d.get(k), expected_values[d.account_head][i])
|
||||
|
||||
|
||||
self.assertEquals(si.total_taxes_and_charges, 234.44)
|
||||
self.assertEquals(si.base_grand_total, 859.44)
|
||||
self.assertEquals(si.grand_total, 859.44)
|
||||
self.assertEquals(si.total_taxes_and_charges, 234.43)
|
||||
self.assertEquals(si.base_grand_total, 859.43)
|
||||
self.assertEquals(si.grand_total, 859.43)
|
||||
|
||||
def test_multi_currency_gle(self):
|
||||
set_perpetual_inventory(0)
|
||||
@@ -1105,8 +1185,83 @@ 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(self):
|
||||
def test_item_wise_tax_breakup_india(self):
|
||||
frappe.flags.country = "India"
|
||||
|
||||
si = self.create_si_to_test_tax_breakup()
|
||||
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si)
|
||||
|
||||
expected_itemised_tax = {
|
||||
"999800": {
|
||||
"Service Tax": {
|
||||
"tax_rate": 10.0,
|
||||
"tax_amount": 1500.0
|
||||
}
|
||||
}
|
||||
}
|
||||
expected_itemised_taxable_amount = {
|
||||
"999800": 15000.0
|
||||
}
|
||||
|
||||
self.assertEqual(itemised_tax, expected_itemised_tax)
|
||||
self.assertEqual(itemised_taxable_amount, expected_itemised_taxable_amount)
|
||||
|
||||
frappe.flags.country = None
|
||||
|
||||
def test_item_wise_tax_breakup_outside_india(self):
|
||||
frappe.flags.country = "United States"
|
||||
|
||||
si = self.create_si_to_test_tax_breakup()
|
||||
|
||||
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si)
|
||||
|
||||
expected_itemised_tax = {
|
||||
"_Test Item": {
|
||||
"Service Tax": {
|
||||
"tax_rate": 10.0,
|
||||
"tax_amount": 1000.0
|
||||
}
|
||||
},
|
||||
"_Test Item 2": {
|
||||
"Service Tax": {
|
||||
"tax_rate": 10.0,
|
||||
"tax_amount": 500.0
|
||||
}
|
||||
}
|
||||
}
|
||||
expected_itemised_taxable_amount = {
|
||||
"_Test Item": 10000.0,
|
||||
"_Test Item 2": 5000.0
|
||||
}
|
||||
|
||||
self.assertEqual(itemised_tax, expected_itemised_tax)
|
||||
self.assertEqual(itemised_taxable_amount, expected_itemised_taxable_amount)
|
||||
|
||||
frappe.flags.country = None
|
||||
|
||||
def create_si_to_test_tax_breakup(self):
|
||||
si = create_sales_invoice(qty=100, rate=50, do_not_save=True)
|
||||
si.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",
|
||||
@@ -1115,11 +1270,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"rate": 10
|
||||
})
|
||||
si.insert()
|
||||
|
||||
tax_breakup_html = '''\n<div class="tax-break-up" style="overflow-x: auto;">\n\t<table class="table table-bordered table-hover">\n\t\t<thead><tr><th class="text-left" style="min-width: 120px;">Item Name</th><th class="text-right" style="min-width: 80px;">Taxable Amount</th><th class="text-right" style="min-width: 80px;">_Test Account Service Tax - _TC</th></tr></thead>\n\t\t<tbody><tr><td>_Test Item</td><td class="text-right">\u20b9 5,000.00</td><td class="text-right">(10.0%) \u20b9 500.00</td></tr></tbody>\n\t</table>\n</div>'''
|
||||
|
||||
self.assertEqual(si.other_charges_calculation, tax_breakup_html)
|
||||
|
||||
return si
|
||||
|
||||
def create_sales_invoice(**args):
|
||||
si = frappe.new_doc("Sales Invoice")
|
||||
@@ -1140,6 +1291,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,
|
||||
|
||||
@@ -1424,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,
|
||||
@@ -2166,7 +2166,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-06 17:54:03.347700",
|
||||
"modified": "2017-07-17 17:54:48.246507",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Item",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
@@ -11,16 +12,51 @@
|
||||
"editable_grid": 1,
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:parent.doctype == 'POS Profile'",
|
||||
"fieldname": "default",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default",
|
||||
"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": "mode_of_payment",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Mode of Payment",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@@ -30,6 +66,7 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
@@ -37,9 +74,11 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0.0",
|
||||
"depends_on": "eval:parent.doctype == 'Sales Invoice'",
|
||||
"fieldname": "amount",
|
||||
@@ -48,7 +87,9 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@@ -58,6 +99,7 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
@@ -65,16 +107,20 @@
|
||||
"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,
|
||||
@@ -82,6 +128,7 @@
|
||||
"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,
|
||||
@@ -89,16 +136,20 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "account",
|
||||
"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": "Account",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@@ -108,6 +159,7 @@
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
@@ -115,16 +167,20 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "type",
|
||||
"fieldtype": "Read Only",
|
||||
"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": "Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@@ -134,6 +190,7 @@
|
||||
"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,
|
||||
@@ -141,16 +198,20 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "base_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Base Amount (Company Currency)",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
@@ -160,6 +221,7 @@
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
@@ -167,17 +229,17 @@
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-07-11 03:28:07.779228",
|
||||
"modified": "2017-07-24 17:25:03.765856",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Payment",
|
||||
@@ -187,7 +249,9 @@
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
QUnit.module('Sales Taxes and Charges Template');
|
||||
|
||||
QUnit.test("test sales taxes and charges template", function(assert) {
|
||||
assert.expect(1);
|
||||
let done = assert.async();
|
||||
frappe.run_serially([
|
||||
() => {
|
||||
return frappe.tests.make('Sales Taxes and Charges Template', [
|
||||
{title: "TEST In State GST"},
|
||||
{taxes:[
|
||||
[
|
||||
{charge_type:"On Net Total"},
|
||||
{account_head:"CGST - "+frappe.get_abbr(frappe.defaults.get_default("Company")) }
|
||||
],
|
||||
[
|
||||
{charge_type:"On Net Total"},
|
||||
{account_head:"SGST - "+frappe.get_abbr(frappe.defaults.get_default("Company")) }
|
||||
]
|
||||
]}
|
||||
]);
|
||||
},
|
||||
() => {assert.ok(cur_frm.doc.title=='TEST In State GST');},
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
|
||||
35
erpnext/accounts/doctype/shipping_rule/test_shipping_rule.js
Normal file
35
erpnext/accounts/doctype/shipping_rule/test_shipping_rule.js
Normal file
@@ -0,0 +1,35 @@
|
||||
QUnit.module('Shipping Rule');
|
||||
|
||||
QUnit.test("test Shipping Rule", function(assert) {
|
||||
assert.expect(1);
|
||||
let done = assert.async();
|
||||
frappe.run_serially([
|
||||
() => {
|
||||
return frappe.tests.make("Shipping Rule", [
|
||||
{label: "Next Day Shipping"},
|
||||
{conditions:[
|
||||
[
|
||||
{from_value:1},
|
||||
{to_value:200},
|
||||
{shipping_amount:100}
|
||||
],
|
||||
[
|
||||
{from_value:201},
|
||||
{to_value:2000},
|
||||
{shipping_amount:50}
|
||||
],
|
||||
]},
|
||||
{countries:[
|
||||
[
|
||||
{country:'India'}
|
||||
]
|
||||
]},
|
||||
{account:'Accounts Payable - '+frappe.get_abbr(frappe.defaults.get_default("Company"))},
|
||||
{cost_center:'Main - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
|
||||
]);
|
||||
},
|
||||
() => {assert.ok(cur_frm.doc.name=='Next Day Shipping');},
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -20,20 +20,22 @@ frappe.ui.form.on("Tax Rule", "refresh", function(frm) {
|
||||
})
|
||||
|
||||
frappe.ui.form.on("Tax Rule", "customer", function(frm) {
|
||||
frappe.call({
|
||||
method:"erpnext.accounts.doctype.tax_rule.tax_rule.get_party_details",
|
||||
args: {
|
||||
"party": frm.doc.customer,
|
||||
"party_type": "customer"
|
||||
},
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
$.each(r.message, function(k, v) {
|
||||
frm.set_value(k, v);
|
||||
});
|
||||
if(frm.doc.customer) {
|
||||
frappe.call({
|
||||
method:"erpnext.accounts.doctype.tax_rule.tax_rule.get_party_details",
|
||||
args: {
|
||||
"party": frm.doc.customer,
|
||||
"party_type": "customer"
|
||||
},
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
$.each(r.message, function(k, v) {
|
||||
frm.set_value(k, v);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Tax Rule", "supplier", function(frm) {
|
||||
|
||||
@@ -979,6 +979,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
get_prompt_details: function() {
|
||||
this.prompt_details = this.customer_doc.get_values();
|
||||
this.prompt_details['country'] = this.pos_profile_data.country;
|
||||
this.prompt_details['territory'] = this.pos_profile_data["territory"];
|
||||
this.prompt_details['customer_group'] = this.pos_profile_data["customer_group"];
|
||||
this.prompt_details['customer_pos_id'] = this.customer_doc.fields_dict.customer_pos_id.value;
|
||||
return JSON.stringify(this.prompt_details)
|
||||
},
|
||||
@@ -1078,7 +1080,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 +1353,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 +1400,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();
|
||||
|
||||
60
erpnext/accounts/page/pos/test_pos.js
Normal file
60
erpnext/accounts/page/pos/test_pos.js
Normal file
@@ -0,0 +1,60 @@
|
||||
QUnit.test("test:POS Profile", function(assert) {
|
||||
assert.expect(1);
|
||||
let done = assert.async();
|
||||
|
||||
frappe.run_serially([
|
||||
() => {
|
||||
return frappe.tests.make("POS Profile", [
|
||||
{naming_series: "SINV"},
|
||||
{company: "_Test Company"},
|
||||
{country: "India"},
|
||||
{currency: "INR"},
|
||||
{write_off_account: "Write Off - _TC"},
|
||||
{write_off_cost_center: "Main - _TC"},
|
||||
{payments: [
|
||||
[
|
||||
{"default": 1},
|
||||
{"mode_of_payment": "Cash"}
|
||||
]]
|
||||
}
|
||||
]);
|
||||
},
|
||||
() => cur_frm.save(),
|
||||
() => frappe.timeout(2),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.payments[0].default, 1, "Default mode of payment tested");
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
|
||||
QUnit.test("test:Sales Invoice", function(assert) {
|
||||
assert.expect(2);
|
||||
let done = assert.async();
|
||||
|
||||
frappe.run_serially([
|
||||
() => {
|
||||
return frappe.tests.make("Sales Invoice", [
|
||||
{customer: "_Test Customer 2"},
|
||||
{company: "_Test Company"},
|
||||
{is_pos: 1},
|
||||
{posting_date: frappe.datetime.get_today()},
|
||||
{due_date: frappe.datetime.get_today()},
|
||||
{items: [
|
||||
[
|
||||
{"item_code": "_Test Item"},
|
||||
{"qty": 5}
|
||||
]]
|
||||
}
|
||||
]);
|
||||
},
|
||||
() => frappe.timeout(2),
|
||||
() => cur_frm.save(),
|
||||
() => frappe.timeout(2),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.payments[0].default, 1, "Default mode of payment tested");
|
||||
assert.equal(cur_frm.doc.payments[0].mode_of_payment, "Cash", "Default mode of payment tested");
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
@@ -8,13 +8,15 @@ 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
|
||||
from erpnext import get_default_currency
|
||||
from erpnext import get_default_currency, get_company_currency
|
||||
|
||||
|
||||
class DuplicatePartyAccountError(frappe.ValidationError): pass
|
||||
|
||||
@@ -42,6 +44,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
|
||||
frappe.throw(_("Not permitted for {0}").format(party), frappe.PermissionError)
|
||||
|
||||
party = frappe.get_doc(party_type, party)
|
||||
currency = party.default_currency if party.default_currency else get_company_currency(company)
|
||||
|
||||
set_address_details(out, party, party_type, doctype, company)
|
||||
set_contact_details(out, party, party_type)
|
||||
@@ -77,8 +80,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)
|
||||
@@ -271,6 +275,7 @@ def get_due_date(posting_date, party_type, party, company):
|
||||
return due_date
|
||||
|
||||
def get_credit_days(party_type, party, company):
|
||||
credit_days = 0
|
||||
if party_type and party:
|
||||
if party_type == "Customer":
|
||||
credit_days_based_on, credit_days, customer_group = \
|
||||
@@ -280,14 +285,16 @@ def get_credit_days(party_type, party, company):
|
||||
frappe.db.get_value(party_type, party, ["credit_days_based_on", "credit_days", "supplier_type"])
|
||||
|
||||
if not credit_days_based_on:
|
||||
if party_type == "Customer":
|
||||
if party_type == "Customer" and customer_group:
|
||||
credit_days_based_on, credit_days = \
|
||||
frappe.db.get_value("Customer Group", customer_group, ["credit_days_based_on", "credit_days"]) \
|
||||
or frappe.db.get_value("Company", company, ["credit_days_based_on", "credit_days"])
|
||||
else:
|
||||
frappe.db.get_value("Customer Group", customer_group, ["credit_days_based_on", "credit_days"])
|
||||
elif party_type == "Supplier" and supplier_type:
|
||||
credit_days_based_on, credit_days = \
|
||||
frappe.db.get_value("Supplier Type", supplier_type, ["credit_days_based_on", "credit_days"])\
|
||||
or frappe.db.get_value("Company", company, ["credit_days_based_on", "credit_days"] )
|
||||
frappe.db.get_value("Supplier Type", supplier_type, ["credit_days_based_on", "credit_days"])
|
||||
|
||||
if not credit_days_based_on:
|
||||
credit_days_based_on, credit_days = \
|
||||
frappe.db.get_value("Company", company, ["credit_days_based_on", "credit_days"])
|
||||
|
||||
return credit_days_based_on, credit_days
|
||||
|
||||
|
||||
@@ -234,7 +234,7 @@ def add_total_row(out, root_type, balance_must_be, period_list, company_currency
|
||||
for period in period_list:
|
||||
total_row.setdefault(period.key, 0.0)
|
||||
total_row[period.key] += row.get(period.key, 0.0)
|
||||
row[period.key] = ""
|
||||
row[period.key] = 0.0
|
||||
|
||||
total_row.setdefault("total", 0.0)
|
||||
total_row["total"] += flt(row["total"])
|
||||
|
||||
@@ -209,7 +209,10 @@ class GrossProfitGenerator(object):
|
||||
sle.voucher_detail_no == row.item_row:
|
||||
previous_stock_value = len(my_sle) > i+1 and \
|
||||
flt(my_sle[i+1].stock_value) or 0.0
|
||||
return previous_stock_value - flt(sle.stock_value)
|
||||
if previous_stock_value:
|
||||
return previous_stock_value - flt(sle.stock_value)
|
||||
else:
|
||||
return flt(row.qty) * self.get_average_buying_rate(row, item_code)
|
||||
else:
|
||||
return flt(row.qty) * self.get_average_buying_rate(row, item_code)
|
||||
|
||||
|
||||
@@ -20,36 +20,36 @@ def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1, compan
|
||||
|
||||
def get_fiscal_years(transaction_date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False):
|
||||
fiscal_years = frappe.cache().hget("fiscal_years", company) or []
|
||||
|
||||
if not fiscal_years:
|
||||
|
||||
if not fiscal_years:
|
||||
# if year start date is 2012-04-01, year end date should be 2013-03-31 (hence subdate)
|
||||
cond = ""
|
||||
if fiscal_year:
|
||||
cond += " and fy.name = {0}".format(frappe.db.escape(fiscal_year))
|
||||
if company:
|
||||
cond += """
|
||||
and (not exists (select name
|
||||
from `tabFiscal Year Company` fyc
|
||||
where fyc.parent = fy.name)
|
||||
or exists(select company
|
||||
from `tabFiscal Year Company` fyc
|
||||
where fyc.parent = fy.name
|
||||
and (not exists (select name
|
||||
from `tabFiscal Year Company` fyc
|
||||
where fyc.parent = fy.name)
|
||||
or exists(select company
|
||||
from `tabFiscal Year Company` fyc
|
||||
where fyc.parent = fy.name
|
||||
and fyc.company=%(company)s)
|
||||
)
|
||||
"""
|
||||
|
||||
fiscal_years = frappe.db.sql("""
|
||||
select
|
||||
fy.name, fy.year_start_date, fy.year_end_date
|
||||
from
|
||||
select
|
||||
fy.name, fy.year_start_date, fy.year_end_date
|
||||
from
|
||||
`tabFiscal Year` fy
|
||||
where
|
||||
where
|
||||
disabled = 0 {0}
|
||||
order by
|
||||
order by
|
||||
fy.year_start_date desc""".format(cond), {
|
||||
"company": company
|
||||
}, as_dict=True)
|
||||
|
||||
|
||||
frappe.cache().hset("fiscal_years", company, fiscal_years)
|
||||
|
||||
if transaction_date:
|
||||
@@ -60,10 +60,10 @@ def get_fiscal_years(transaction_date=None, fiscal_year=None, label="Date", verb
|
||||
if fiscal_year and fy.name == fiscal_year:
|
||||
matched = True
|
||||
|
||||
if (transaction_date and getdate(fy.year_start_date) <= transaction_date
|
||||
if (transaction_date and getdate(fy.year_start_date) <= transaction_date
|
||||
and getdate(fy.year_end_date) >= transaction_date):
|
||||
matched = True
|
||||
|
||||
|
||||
if matched:
|
||||
if as_dict:
|
||||
return (fy,)
|
||||
@@ -72,7 +72,7 @@ def get_fiscal_years(transaction_date=None, fiscal_year=None, label="Date", verb
|
||||
|
||||
error_msg = _("""{0} {1} not in any active Fiscal Year.""").format(label, formatdate(transaction_date))
|
||||
if verbose==1: frappe.msgprint(error_msg)
|
||||
raise FiscalYearError, error_msg
|
||||
raise FiscalYearError(error_msg)
|
||||
|
||||
def validate_fiscal_year(date, fiscal_year, company, label="Date", doc=None):
|
||||
years = [f[0] for f in get_fiscal_years(date, label=_(label), company=company)]
|
||||
@@ -158,7 +158,6 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company
|
||||
return flt(bal)
|
||||
|
||||
def get_count_on(account, fieldname, date):
|
||||
|
||||
cond = []
|
||||
if date:
|
||||
cond.append("posting_date <= '%s'" % frappe.db.escape(cstr(date)))
|
||||
@@ -195,11 +194,6 @@ def get_count_on(account, fieldname, date):
|
||||
select name from `tabAccount` ac where ac.name = gle.account
|
||||
and ac.lft >= %s and ac.rgt <= %s
|
||||
)""" % (acc.lft, acc.rgt))
|
||||
|
||||
# If group and currency same as company,
|
||||
# always return balance based on debit and credit in company currency
|
||||
if acc.account_currency == frappe.db.get_value("Company", acc.company, "default_currency"):
|
||||
in_account_currency = False
|
||||
else:
|
||||
cond.append("""gle.account = "%s" """ % (frappe.db.escape(account, percent=False), ))
|
||||
|
||||
@@ -227,7 +221,7 @@ def get_count_on(account, fieldname, date):
|
||||
WHERE docstatus < 2 and posting_date <= %(date)s and against_voucher = %(voucher_no)s
|
||||
and party = %(party)s and name != %(name)s"""
|
||||
.format(select_fields),
|
||||
{"date": date, "voucher_no": gle.voucher_no,
|
||||
{"date": date, "voucher_no": gle.voucher_no,
|
||||
"party": gle.party, "name": gle.name})[0][0]
|
||||
|
||||
outstanding_amount = flt(gle.get(dr_or_cr)) - flt(gle.get(cr_or_dr)) - payment_amount
|
||||
@@ -274,7 +268,7 @@ def add_cc(args=None):
|
||||
|
||||
if not args:
|
||||
args = frappe.local.form_dict
|
||||
|
||||
|
||||
args.doctype = "Cost Center"
|
||||
args = make_tree_args(**args)
|
||||
|
||||
@@ -500,7 +494,8 @@ def get_company_default(company, fieldname):
|
||||
value = frappe.db.get_value("Company", company, fieldname)
|
||||
|
||||
if not value:
|
||||
throw(_("Please set default {0} in Company {1}").format(frappe.get_meta("Company").get_label(fieldname), company))
|
||||
throw(_("Please set default {0} in Company {1}")
|
||||
.format(frappe.get_meta("Company").get_label(fieldname), company))
|
||||
|
||||
return value
|
||||
|
||||
@@ -534,18 +529,18 @@ def get_stock_and_account_difference(account_list=None, posting_date=None):
|
||||
account_balance = get_balance_on(account_data.get('account'), posting_date, in_account_currency=False)
|
||||
stock_value = get_stock_value_on(warehouse, posting_date)
|
||||
if abs(flt(stock_value) - flt(account_balance)) > 0.005:
|
||||
difference.setdefault(account, flt(stock_value) - flt(account_balance))
|
||||
difference.setdefault(account_data.get('account'), flt(stock_value) - flt(account_balance))
|
||||
|
||||
return difference
|
||||
|
||||
def get_currency_precision():
|
||||
def get_currency_precision():
|
||||
precision = cint(frappe.db.get_default("currency_precision"))
|
||||
if not precision:
|
||||
number_format = frappe.db.get_default("number_format") or "#,###.##"
|
||||
precision = get_number_format_info(number_format)[2]
|
||||
|
||||
|
||||
return precision
|
||||
|
||||
|
||||
def get_stock_rbnb_difference(posting_date, company):
|
||||
stock_items = frappe.db.sql_list("""select distinct item_code
|
||||
from `tabStock Ledger Entry` where company=%s""", company)
|
||||
@@ -627,7 +622,8 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
|
||||
'invoice_amount': flt(d.invoice_amount),
|
||||
'payment_amount': flt(d.payment_amount),
|
||||
'outstanding_amount': flt(d.invoice_amount - d.payment_amount, precision),
|
||||
'due_date': frappe.db.get_value(d.voucher_type, d.voucher_no, "due_date"),
|
||||
'due_date': frappe.db.get_value(d.voucher_type, d.voucher_no,
|
||||
"posting_date" if party_type=="Employee" else "due_date"),
|
||||
}))
|
||||
|
||||
outstanding_invoices = sorted(outstanding_invoices, key=lambda k: k['due_date'] or getdate(nowdate()))
|
||||
@@ -654,7 +650,7 @@ def get_companies():
|
||||
@frappe.whitelist()
|
||||
def get_children():
|
||||
from erpnext.accounts.report.financial_statements import sort_root_accounts
|
||||
|
||||
|
||||
args = frappe.local.form_dict
|
||||
doctype, company = args['doctype'], args['company']
|
||||
fieldname = frappe.db.escape(doctype.lower().replace(' ','_'))
|
||||
@@ -695,9 +691,6 @@ def get_children():
|
||||
|
||||
return acc
|
||||
|
||||
def create_payment_gateway_account(gateway):
|
||||
create_payment_gateway_account(gateway)
|
||||
|
||||
def create_payment_gateway_account(gateway):
|
||||
from erpnext.setup.setup_wizard.setup_wizard import create_bank_account
|
||||
|
||||
@@ -738,4 +731,4 @@ def create_payment_gateway_account(gateway):
|
||||
|
||||
except frappe.DuplicateEntryError:
|
||||
# already exists, due to a reinstall?
|
||||
pass
|
||||
pass
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
@@ -1546,6 +1546,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,
|
||||
@@ -1553,7 +1583,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "HTML",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -1568,7 +1598,7 @@
|
||||
"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,
|
||||
@@ -3305,7 +3335,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-06-13 14:29:21.066814",
|
||||
"modified": "2017-07-19 14:03:51.838328",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order",
|
||||
|
||||
@@ -39,6 +39,8 @@ class PurchaseOrder(BuyingController):
|
||||
super(PurchaseOrder, self).validate()
|
||||
|
||||
self.set_status()
|
||||
|
||||
self.validate_supplier()
|
||||
validate_for_items(self)
|
||||
self.check_for_closed_status()
|
||||
|
||||
@@ -65,6 +67,17 @@ class PurchaseOrder(BuyingController):
|
||||
}
|
||||
})
|
||||
|
||||
def validate_supplier(self):
|
||||
prevent_po = frappe.db.get_value("Supplier", self.supplier, 'prevent_pos')
|
||||
if prevent_po:
|
||||
standing = frappe.db.get_value("Supplier Scorecard",self.supplier, 'status')
|
||||
frappe.throw(_("Purchase Orders are not allowed for {0} due to a scorecard standing of {1}.").format(self.supplier, standing))
|
||||
|
||||
warn_po = frappe.db.get_value("Supplier", self.supplier, 'warn_pos')
|
||||
if warn_po:
|
||||
standing = frappe.db.get_value("Supplier Scorecard",self.supplier, 'status')
|
||||
frappe.msgprint(_("{0} currently has a {1} Supplier Scorecard standing, and Purchase Orders to this supplier should be issued with caution.").format(self.supplier, standing), title=_("Caution"), indicator='orange')
|
||||
|
||||
def validate_minimum_order_qty(self):
|
||||
items = list(set([d.item_code for d in self.get("items")]))
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
@@ -45,6 +46,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -74,6 +76,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -104,6 +107,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -132,6 +136,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
@@ -162,6 +167,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
@@ -191,6 +197,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
@@ -220,6 +227,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -252,6 +260,7 @@
|
||||
"width": "300px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -279,6 +288,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -308,6 +318,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -338,6 +349,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -366,6 +378,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
@@ -398,6 +411,7 @@
|
||||
"width": "60px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -431,6 +445,7 @@
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -458,6 +473,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -491,6 +507,7 @@
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -523,6 +540,7 @@
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -550,6 +568,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -579,6 +598,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -608,6 +628,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -635,6 +656,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -664,6 +686,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -691,6 +714,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
@@ -722,6 +746,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -753,6 +778,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -780,6 +806,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -814,6 +841,7 @@
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -845,6 +873,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -874,6 +903,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -902,6 +932,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -932,6 +963,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -962,6 +994,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -990,6 +1023,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1020,6 +1054,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1050,6 +1085,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1078,6 +1114,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1109,6 +1146,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1138,6 +1176,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1171,6 +1210,7 @@
|
||||
"width": "120px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1201,6 +1241,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1231,6 +1272,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1260,6 +1302,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1289,6 +1332,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1318,6 +1362,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1347,6 +1392,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1374,6 +1420,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1406,6 +1453,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1437,6 +1485,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1467,6 +1516,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1499,6 +1549,7 @@
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1529,6 +1580,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1559,6 +1611,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1588,6 +1641,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1619,6 +1673,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1659,7 +1714,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-04-25 18:49:08.604055",
|
||||
"modified": "2017-08-02 22:15:47.411235",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order Item",
|
||||
|
||||
@@ -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"])
|
||||
@@ -44,6 +44,9 @@ frappe.ui.form.on("Request for Quotation",{
|
||||
freeze: true,
|
||||
args: {
|
||||
rfq_name: frm.doc.name
|
||||
},
|
||||
callback: function(r){
|
||||
frm.reload_doc();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -51,6 +54,91 @@ frappe.ui.form.on("Request for Quotation",{
|
||||
|
||||
},
|
||||
|
||||
get_suppliers_button: function (frm) {
|
||||
var doc = frm.doc;
|
||||
var dialog = new frappe.ui.Dialog({
|
||||
title: __("Get Suppliers"),
|
||||
fields: [
|
||||
{ "fieldtype": "Select", "label": __("Get Suppliers By"),
|
||||
"fieldname": "search_type",
|
||||
"options": "Tag\nSupplier Type", "reqd": 1 },
|
||||
{ "fieldtype": "Link", "label": __("Supplier Type"),
|
||||
"fieldname": "supplier_type",
|
||||
"options": "Supplier Type", "reqd": 0,
|
||||
"depends_on": "eval:doc.search_type == 'Supplier Type'"},
|
||||
{ "fieldtype": "Data", "label": __("Tag"),
|
||||
"fieldname": "tag", "reqd": 0,
|
||||
"depends_on": "eval:doc.search_type == 'Tag'" },
|
||||
{ "fieldtype": "Button", "label": __("Add All Suppliers"),
|
||||
"fieldname": "add_suppliers", "cssClass": "btn-primary"},
|
||||
]
|
||||
});
|
||||
|
||||
dialog.fields_dict.add_suppliers.$input.click(function() {
|
||||
var args = dialog.get_values();
|
||||
if(!args) return;
|
||||
dialog.hide();
|
||||
|
||||
//Remove blanks
|
||||
for (var j = 0; j < frm.doc.suppliers.length; j++) {
|
||||
if(!frm.doc.suppliers[j].hasOwnProperty("supplier")) {
|
||||
frm.get_field("suppliers").grid.grid_rows[j].remove();
|
||||
}
|
||||
}
|
||||
|
||||
function load_suppliers(r) {
|
||||
if(r.message) {
|
||||
for (var i = 0; i < r.message.length; i++) {
|
||||
var exists = false;
|
||||
if (r.message[i].constructor === Array){
|
||||
var supplier = r.message[i][0];
|
||||
} else {
|
||||
var supplier = r.message[i].name;
|
||||
}
|
||||
|
||||
for (var j = 0; j < doc.suppliers.length;j++) {
|
||||
if (supplier === doc.suppliers[j].supplier) {
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
if(!exists) {
|
||||
var d = frm.add_child('suppliers');
|
||||
d.supplier = supplier;
|
||||
frm.script_manager.trigger("supplier", d.doctype, d.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
frm.refresh_field("suppliers");
|
||||
}
|
||||
|
||||
if (args.search_type === "Tag" && args.tag) {
|
||||
return frappe.call({
|
||||
type: "GET",
|
||||
method: "frappe.desk.tags.get_tagged_docs",
|
||||
args: {
|
||||
"doctype": "Supplier",
|
||||
"tag": args.tag
|
||||
},
|
||||
callback: load_suppliers
|
||||
});
|
||||
} else if (args.supplier_type) {
|
||||
return frappe.call({
|
||||
method: "frappe.client.get_list",
|
||||
args: {
|
||||
doctype: "Supplier",
|
||||
order_by: "name",
|
||||
fields: ["name"],
|
||||
filters: [["Supplier", "supplier_type", "=", args.supplier_type]]
|
||||
|
||||
},
|
||||
callback: load_suppliers
|
||||
});
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
|
||||
},
|
||||
|
||||
make_suppplier_quotation: function(frm) {
|
||||
var doc = frm.doc;
|
||||
var dialog = new frappe.ui.Dialog({
|
||||
|
||||
@@ -25,7 +25,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,
|
||||
@@ -59,7 +59,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": "Company",
|
||||
"length": 0,
|
||||
@@ -156,7 +156,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": "Date",
|
||||
"length": 0,
|
||||
@@ -236,6 +236,36 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "get_suppliers_button",
|
||||
"fieldtype": "Button",
|
||||
"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": "Get Suppliers",
|
||||
"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,
|
||||
@@ -406,7 +436,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": "Message for Supplier",
|
||||
"length": 0,
|
||||
@@ -786,7 +816,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-06-13 14:29:13.171291",
|
||||
"modified": "2017-07-21 14:06:46.309322",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Request for Quotation",
|
||||
|
||||
@@ -21,6 +21,7 @@ STANDARD_USERS = ("Guest", "Administrator")
|
||||
class RequestforQuotation(BuyingController):
|
||||
def validate(self):
|
||||
self.validate_duplicate_supplier()
|
||||
self.validate_supplier_list()
|
||||
validate_for_items(self)
|
||||
self.update_email_id()
|
||||
|
||||
@@ -29,6 +30,17 @@ class RequestforQuotation(BuyingController):
|
||||
if len(supplier_list) != len(set(supplier_list)):
|
||||
frappe.throw(_("Same supplier has been entered multiple times"))
|
||||
|
||||
def validate_supplier_list(self):
|
||||
for d in self.suppliers:
|
||||
prevent_rfqs = frappe.db.get_value("Supplier", d.supplier, 'prevent_rfqs')
|
||||
if prevent_rfqs:
|
||||
standing = frappe.db.get_value("Supplier Scorecard",d.supplier, 'status')
|
||||
frappe.throw(_("RFQs are not allowed for {0} due to a scorecard standing of {1}").format(d.supplier, standing))
|
||||
warn_rfqs = frappe.db.get_value("Supplier", d.supplier, 'warn_rfqs')
|
||||
if warn_rfqs:
|
||||
standing = frappe.db.get_value("Supplier Scorecard",d.supplier, 'status')
|
||||
frappe.msgprint(_("{0} currently has a {1} Supplier Scorecard standing, and RFQs to this supplier should be issued with caution.").format(d.supplier, standing), title=_("Caution"), indicator='orange')
|
||||
|
||||
def update_email_id(self):
|
||||
for rfq_supplier in self.suppliers:
|
||||
if not rfq_supplier.email_id:
|
||||
@@ -40,6 +52,8 @@ class RequestforQuotation(BuyingController):
|
||||
|
||||
def on_submit(self):
|
||||
frappe.db.set(self, 'status', 'Submitted')
|
||||
for supplier in self.suppliers:
|
||||
supplier.email_sent = 0
|
||||
|
||||
def on_cancel(self):
|
||||
frappe.db.set(self, 'status', 'Cancelled')
|
||||
@@ -54,6 +68,8 @@ class RequestforQuotation(BuyingController):
|
||||
|
||||
self.update_supplier_part_no(rfq_supplier)
|
||||
self.supplier_rfq_mail(rfq_supplier, update_password_link, self.get_link())
|
||||
rfq_supplier.email_sent = 1
|
||||
rfq_supplier.save()
|
||||
|
||||
def get_link(self):
|
||||
# RFQ link for supplier portal
|
||||
@@ -84,7 +100,10 @@ class RequestforQuotation(BuyingController):
|
||||
else:
|
||||
contact = frappe.new_doc("Contact")
|
||||
contact.first_name = rfq_supplier.supplier_name or rfq_supplier.supplier
|
||||
contact.supplier = rfq_supplier.supplier
|
||||
contact.append('links', {
|
||||
'link_doctype': 'Supplier',
|
||||
'link_name': rfq_supplier.supplier
|
||||
})
|
||||
|
||||
if not contact.email_id and not contact.user:
|
||||
contact.email_id = user.name
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
@@ -12,6 +13,7 @@
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -42,6 +44,39 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.docstatus >= 1",
|
||||
"fieldname": "email_sent",
|
||||
"fieldtype": "Check",
|
||||
"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": "Email Sent",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -72,6 +107,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -102,6 +138,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -130,6 +167,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
@@ -160,6 +198,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -190,6 +229,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -219,17 +259,17 @@
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-02-17 16:42:57.254211",
|
||||
"modified": "2017-07-24 06:52:19.542717",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Request for Quotation Supplier",
|
||||
|
||||
@@ -322,6 +322,126 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "warn_rfqs",
|
||||
"fieldtype": "Check",
|
||||
"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": "Warn RFQs",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "warn_pos",
|
||||
"fieldtype": "Check",
|
||||
"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": "Warn POs",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "prevent_rfqs",
|
||||
"fieldtype": "Check",
|
||||
"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": "Prevent RFQs",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "prevent_pos",
|
||||
"fieldtype": "Check",
|
||||
"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": "Prevent POs",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@@ -850,7 +970,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-06-13 14:29:16.310834",
|
||||
"modified": "2017-07-06 16:40:46.935608",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier",
|
||||
|
||||
@@ -1120,6 +1120,36 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fieldname": "tax_breakup",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Tax Breakup",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@@ -1127,7 +1157,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "HTML",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -1142,7 +1172,7 @@
|
||||
"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,
|
||||
@@ -2217,7 +2247,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2017-06-13 14:28:54.466450",
|
||||
"modified": "2017-07-19 13:51:18.929697",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Quotation",
|
||||
|
||||
@@ -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",
|
||||
|
||||
146
erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.js
Normal file
146
erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.js
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
/* global frappe, refresh_field */
|
||||
|
||||
frappe.ui.form.on("Supplier Scorecard", {
|
||||
|
||||
onload: function(frm) {
|
||||
|
||||
if (frm.doc.indicator_color !== "") {
|
||||
frm.set_indicator_formatter("status", function(doc) {
|
||||
return doc.indicator_color.toLowerCase();
|
||||
});
|
||||
}
|
||||
if (frm.doc.__unsaved == 1) {
|
||||
loadAllCriteria(frm);
|
||||
loadAllStandings(frm);
|
||||
}
|
||||
|
||||
},
|
||||
refresh: function(frm) {
|
||||
if (frm.dashboard.hasOwnProperty('heatmap')) {
|
||||
frm.dashboard.heatmap.setLegend([0,20,40,60,80,101],["#991600","#169900"]);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Supplier Scorecard Scoring Standing", {
|
||||
|
||||
standing_name: function(frm, cdt, cdn) {
|
||||
if (frm.doc.standing_name != undefined) {
|
||||
var d = frappe.get_doc(cdt, cdn);
|
||||
return frm.call({
|
||||
method: "erpnext.buying.doctype.supplier_scorecard_standing.supplier_scorecard_standing.get_scoring_standing",
|
||||
child: d,
|
||||
args: {
|
||||
standing_name: d.standing_name
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Supplier Scorecard Scoring Variable", {
|
||||
|
||||
variable_label: function(frm, cdt, cdn) {
|
||||
if (frm.doc.variable_label != undefined) {
|
||||
var d = frappe.get_doc(cdt, cdn);
|
||||
return frm.call({
|
||||
method: "erpnext.buying.doctype.supplier_scorecard_variable.supplier_scorecard_variable.get_scoring_variable",
|
||||
child: d,
|
||||
args: {
|
||||
variable_label: d.variable_label
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Supplier Scorecard Scoring Criteria", {
|
||||
|
||||
criteria_name: function(frm, cdt, cdn) {
|
||||
if (frm.doc.criteria_name != undefined) {
|
||||
var d = frappe.get_doc(cdt, cdn);
|
||||
frm.call({
|
||||
method: "erpnext.buying.doctype.supplier_scorecard_criteria.supplier_scorecard_criteria.get_variables",
|
||||
args: {
|
||||
criteria_name: d.criteria_name
|
||||
},
|
||||
callback: function(r) {
|
||||
for (var i = 0; i < r.message.length; i++)
|
||||
{
|
||||
var exists = false;
|
||||
for (var j = 0; j < frm.doc.variables.length; j++)
|
||||
{
|
||||
if(!frm.doc.variables[j].hasOwnProperty("variable_label")) {
|
||||
frm.get_field("variables").grid.grid_rows[j].remove();
|
||||
}
|
||||
else if(frm.doc.variables[j].variable_label === r.message[i]) {
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
if (!exists){
|
||||
var new_row = frm.add_child("variables");
|
||||
new_row.variable_label = r.message[i];
|
||||
frm.script_manager.trigger("variable_label", new_row.doctype, new_row.name);
|
||||
}
|
||||
|
||||
}
|
||||
refresh_field("variables");
|
||||
}
|
||||
});
|
||||
return frm.call({
|
||||
method: "erpnext.buying.doctype.supplier_scorecard_criteria.supplier_scorecard_criteria.get_scoring_criteria",
|
||||
child: d,
|
||||
args: {
|
||||
criteria_name: d.criteria_name
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var loadAllCriteria = function(frm) {
|
||||
frappe.call({
|
||||
method: "erpnext.buying.doctype.supplier_scorecard_criteria.supplier_scorecard_criteria.get_criteria_list",
|
||||
callback: function(r) {
|
||||
for (var j = 0; j < frm.doc.criteria.length; j++)
|
||||
{
|
||||
if(!frm.doc.criteria[j].hasOwnProperty("criteria_name")) {
|
||||
frm.get_field("criteria").grid.grid_rows[j].remove();
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < r.message.length; i++)
|
||||
{
|
||||
var new_row = frm.add_child("criteria");
|
||||
new_row.criteria_name = r.message[i].name;
|
||||
frm.script_manager.trigger("criteria_name", new_row.doctype, new_row.name);
|
||||
}
|
||||
refresh_field("criteria");
|
||||
}
|
||||
});
|
||||
};
|
||||
var loadAllStandings = function(frm) {
|
||||
frappe.call({
|
||||
method: "erpnext.buying.doctype.supplier_scorecard_standing.supplier_scorecard_standing.get_standings_list",
|
||||
callback: function(r) {
|
||||
for (var j = 0; j < frm.doc.standings.length; j++)
|
||||
{
|
||||
if(!frm.doc.standings[j].hasOwnProperty("standing_name")) {
|
||||
frm.get_field("standings").grid.grid_rows[j].remove();
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < r.message.length; i++)
|
||||
{
|
||||
var new_row = frm.add_child("standings");
|
||||
new_row.standing_name = r.message[i].name;
|
||||
frm.script_manager.trigger("standing_name", new_row.doctype, new_row.name);
|
||||
}
|
||||
refresh_field("standings");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,701 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:supplier",
|
||||
"beta": 1,
|
||||
"creation": "2017-05-29 01:40:54.786555",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "supplier",
|
||||
"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": "Supplier",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Supplier",
|
||||
"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": "supplier_score",
|
||||
"fieldtype": "Data",
|
||||
"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": "Supplier Score",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "indicator_color",
|
||||
"fieldtype": "Data",
|
||||
"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": "Indicator Color",
|
||||
"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": "status",
|
||||
"fieldtype": "Data",
|
||||
"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": "Status",
|
||||
"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": "column_break_2",
|
||||
"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,
|
||||
"default": "Per Month",
|
||||
"fieldname": "period",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Evaluation Period",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Per Month\nPer Week\nPer Year",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fieldname": "scoring_setup",
|
||||
"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": "Scoring Setup",
|
||||
"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,
|
||||
"default": "{total_score} * max( 0, min ( 1 , (12 - {period_number}) / 12) )",
|
||||
"description": "Scorecard variables can be used, as well as:\n{total_score} (the total score from that period),\n{period_number} (the number of periods to present day)\n",
|
||||
"fieldname": "weighting_function",
|
||||
"fieldtype": "Small Text",
|
||||
"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": "Weighting Function",
|
||||
"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": "standings",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Scoring Standings",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Supplier Scorecard Scoring Standing",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fieldname": "criteria_setup",
|
||||
"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": "Criteria Setup",
|
||||
"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": "criteria",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Scoring Criteria",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Supplier Scorecard Scoring Criteria",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "variables",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Supplier Variables",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Supplier Scorecard Scoring Variable",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "eval: doc.status != 'Unknown'",
|
||||
"columns": 0,
|
||||
"fieldname": "scorecard_actions",
|
||||
"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": "Scorecard Actions",
|
||||
"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": "warn_rfqs",
|
||||
"fieldtype": "Check",
|
||||
"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": "Warn for new Request for Quotations",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "warn_pos",
|
||||
"fieldtype": "Check",
|
||||
"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": "Warn for new Purchase Orders",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "prevent_rfqs",
|
||||
"fieldtype": "Check",
|
||||
"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": "Prevent RFQs",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "prevent_pos",
|
||||
"fieldtype": "Check",
|
||||
"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": "Prevent POs",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_16",
|
||||
"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": "notify_supplier",
|
||||
"fieldtype": "Check",
|
||||
"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": "Notify Supplier",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "notify_employee",
|
||||
"fieldtype": "Check",
|
||||
"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": "Notify Employee",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"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": "Employee",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Employee",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-12 07:33:11.874949",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Scorecard",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0
|
||||
}
|
||||
262
erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py
Normal file
262
erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py
Normal file
@@ -0,0 +1,262 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import throw, _
|
||||
from frappe.model.document import Document
|
||||
import time
|
||||
from datetime import timedelta
|
||||
from frappe.utils import nowdate, get_last_day, getdate, add_days, add_years
|
||||
from erpnext.buying.doctype.supplier_scorecard_period.supplier_scorecard_period import make_supplier_scorecard
|
||||
|
||||
class SupplierScorecard(Document):
|
||||
|
||||
def validate(self):
|
||||
self.validate_standings()
|
||||
self.validate_criteria_weights()
|
||||
self.calculate_total_score()
|
||||
self.update_standing()
|
||||
|
||||
def on_update(self):
|
||||
score = make_all_scorecards(self.name)
|
||||
if score > 0:
|
||||
self.save()
|
||||
|
||||
def validate_standings(self):
|
||||
# Check that there are no overlapping scores and check that there are no missing scores
|
||||
score = 0
|
||||
for c1 in self.standings:
|
||||
for c2 in self.standings:
|
||||
if c1 != c2:
|
||||
if (c1.max_grade > c2.min_grade and c1.min_grade < c2.max_grade):
|
||||
throw(_('Overlap in scoring between {0} and {1}').format(c1.standing_name,c2.standing_name))
|
||||
if c2.min_grade == score:
|
||||
score = c2.max_grade
|
||||
if score < 100:
|
||||
throw(_('Unable to find score starting at {0}. You need to have standing scores covering 0 to 100').format(score))
|
||||
|
||||
def validate_criteria_weights(self):
|
||||
|
||||
weight = 0
|
||||
for c in self.criteria:
|
||||
weight += c.weight
|
||||
|
||||
if weight != 100:
|
||||
throw(_('Criteria weights must add up to 100%'))
|
||||
|
||||
def calculate_total_score(self):
|
||||
scorecards = frappe.db.sql("""
|
||||
SELECT
|
||||
scp.name
|
||||
FROM
|
||||
`tabSupplier Scorecard Period` scp
|
||||
WHERE
|
||||
scp.scorecard = %(sc)s
|
||||
ORDER BY
|
||||
scp.end_date DESC""",
|
||||
{"sc": self.name}, as_dict=1)
|
||||
|
||||
period = 0
|
||||
total_score = 0
|
||||
total_max_score = 0
|
||||
for scp in scorecards:
|
||||
my_sc = frappe.get_doc('Supplier Scorecard Period', scp.name)
|
||||
my_scp_weight = self.weighting_function
|
||||
my_scp_weight = my_scp_weight.replace('{period_number}', str(period))
|
||||
|
||||
my_scp_maxweight = my_scp_weight.replace('{total_score}', '100')
|
||||
my_scp_weight = my_scp_weight.replace('{total_score}', str(my_sc.total_score))
|
||||
|
||||
max_score = my_sc.calculate_weighted_score(my_scp_maxweight)
|
||||
score = my_sc.calculate_weighted_score(my_scp_weight)
|
||||
|
||||
total_score += score
|
||||
total_max_score += max_score
|
||||
period += 1
|
||||
if total_max_score > 0:
|
||||
self.supplier_score = round(100.0 * (total_score / total_max_score) ,1)
|
||||
else:
|
||||
self.supplier_score = 100
|
||||
|
||||
def update_standing(self):
|
||||
# Get the setup document
|
||||
|
||||
for standing in self.standings:
|
||||
if (not standing.min_grade or (standing.min_grade <= self.supplier_score)) and \
|
||||
(not standing.max_grade or (standing.max_grade > self.supplier_score)):
|
||||
self.status = standing.standing_name
|
||||
self.indicator_color = standing.standing_color
|
||||
self.notify_supplier = standing.notify_supplier
|
||||
self.notify_employee = standing.notify_employee
|
||||
self.employee_link = standing.employee_link
|
||||
|
||||
#Update supplier standing info
|
||||
for fieldname in ('prevent_pos', 'prevent_rfqs','warn_rfqs','warn_pos'):
|
||||
self.set(fieldname, standing.get(fieldname))
|
||||
frappe.db.set_value("Supplier", self.supplier, fieldname, self.get(fieldname))
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_timeline_data(doctype, name):
|
||||
# Get a list of all the associated scorecards
|
||||
scs = frappe.get_doc(doctype, name)
|
||||
out = {}
|
||||
timeline_data = {}
|
||||
scorecards = frappe.db.sql("""
|
||||
SELECT
|
||||
sc.name
|
||||
FROM
|
||||
`tabSupplier Scorecard Period` sc
|
||||
WHERE
|
||||
sc.scorecard = %(scs)s""",
|
||||
{"scs": scs.name}, as_dict=1)
|
||||
|
||||
for sc in scorecards:
|
||||
start_date, end_date, total_score = frappe.db.get_value('Supplier Scorecard Period', sc.name, ['start_date', 'end_date', 'total_score'])
|
||||
for single_date in daterange(start_date, end_date):
|
||||
timeline_data[time.mktime(single_date.timetuple())] = total_score
|
||||
|
||||
out['timeline_data'] = timeline_data
|
||||
return out
|
||||
|
||||
def daterange(start_date, end_date):
|
||||
for n in range(int ((end_date - start_date).days)+1):
|
||||
yield start_date + timedelta(n)
|
||||
|
||||
def refresh_scorecards():
|
||||
scorecards = frappe.db.sql("""
|
||||
SELECT
|
||||
sc.name
|
||||
FROM
|
||||
`tabSupplier Scorecard` sc""",
|
||||
{}, as_dict=1)
|
||||
for sc in scorecards:
|
||||
# Check to see if any new scorecard periods are created
|
||||
if make_all_scorecards(sc.name) > 0:
|
||||
# Save the scorecard to update the score and standings
|
||||
sc.save()
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_all_scorecards(docname):
|
||||
|
||||
sc = frappe.get_doc('Supplier Scorecard', docname)
|
||||
supplier = frappe.get_doc('Supplier',sc.supplier)
|
||||
|
||||
start_date = getdate(supplier.creation)
|
||||
end_date = get_scorecard_date(sc.period, start_date)
|
||||
todays = getdate(nowdate())
|
||||
|
||||
scp_count = 0
|
||||
first_start_date = todays
|
||||
last_end_date = todays
|
||||
|
||||
while (start_date < todays) and (end_date <= todays):
|
||||
# check to make sure there is no scorecard period already created
|
||||
scorecards = frappe.db.sql("""
|
||||
SELECT
|
||||
scp.name
|
||||
FROM
|
||||
`tabSupplier Scorecard Period` scp
|
||||
WHERE
|
||||
scp.scorecard = %(sc)s
|
||||
AND (
|
||||
(scp.start_date > %(end_date)s
|
||||
AND scp.end_date < %(start_date)s)
|
||||
OR
|
||||
(scp.start_date < %(end_date)s
|
||||
AND scp.end_date > %(start_date)s))
|
||||
ORDER BY
|
||||
scp.end_date DESC""",
|
||||
{"sc": docname, "start_date": start_date, "end_date": end_date, "supplier": supplier}, as_dict=1)
|
||||
if len(scorecards) == 0:
|
||||
period_card = make_supplier_scorecard(docname, None)
|
||||
period_card.start_date = start_date
|
||||
period_card.end_date = end_date
|
||||
period_card.save()
|
||||
scp_count = scp_count + 1
|
||||
if start_date < first_start_date:
|
||||
first_start_date = start_date
|
||||
last_end_date = end_date
|
||||
|
||||
start_date = getdate(add_days(end_date,1))
|
||||
end_date = get_scorecard_date(sc.period, start_date)
|
||||
if scp_count > 0:
|
||||
frappe.msgprint(_("Created {0} scorecards for {1} between: ").format(scp_count, sc.supplier) + str(first_start_date) + " - " + str(last_end_date))
|
||||
return scp_count
|
||||
|
||||
def get_scorecard_date(period, start_date):
|
||||
if period == 'Per Week':
|
||||
end_date = getdate(add_days(start_date,7))
|
||||
elif period == 'Per Month':
|
||||
end_date = get_last_day(start_date)
|
||||
elif period == 'Per Year':
|
||||
end_date = add_days(add_years(start_date,1), -1)
|
||||
return end_date
|
||||
|
||||
def make_default_records():
|
||||
install_variable_docs = [
|
||||
{"param_name": "total_accepted_items", "variable_label": "Total Accepted Items", \
|
||||
"path": "get_total_accepted_items"},
|
||||
{"param_name": "total_accepted_amount", "variable_label": "Total Accepted Amount", \
|
||||
"path": "get_total_accepted_amount"},
|
||||
{"param_name": "total_rejected_items", "variable_label": "Total Rejected Items", \
|
||||
"path": "get_total_rejected_items"},
|
||||
{"param_name": "total_rejected_amount", "variable_label": "Total Rejected Amount", \
|
||||
"path": "get_total_rejected_amount"},
|
||||
{"param_name": "total_received_items", "variable_label": "Total Received Items", \
|
||||
"path": "get_total_received_items"},
|
||||
{"param_name": "total_received_amount", "variable_label": "Total Received Amount", \
|
||||
"path": "get_total_received_amount"},
|
||||
{"param_name": "rfq_response_days", "variable_label": "RFQ Response Days", \
|
||||
"path": "get_rfq_response_days"},
|
||||
{"param_name": "sq_total_items", "variable_label": "SQ Total Items", \
|
||||
"path": "get_sq_total_items"},
|
||||
{"param_name": "sq_total_number", "variable_label": "SQ Total Number", \
|
||||
"path": "get_sq_total_number"},
|
||||
{"param_name": "rfq_total_number", "variable_label": "RFQ Total Number", \
|
||||
"path": "get_rfq_total_number"},
|
||||
{"param_name": "rfq_total_items", "variable_label": "RFQ Total Items", \
|
||||
"path": "get_rfq_total_items"},
|
||||
{"param_name": "tot_item_days", "variable_label": "Total Item Days", \
|
||||
"path": "get_item_workdays"},
|
||||
{"param_name": "on_time_shipment_num", "variable_label": "# of On Time Shipments", "path": \
|
||||
"get_on_time_shipments"},
|
||||
{"param_name": "cost_of_delayed_shipments", "variable_label": "Cost of Delayed Shipments", \
|
||||
"path": "get_cost_of_delayed_shipments"},
|
||||
{"param_name": "cost_of_on_time_shipments", "variable_label": "Cost of On Time Shipments", \
|
||||
"path": "get_cost_of_on_time_shipments"},
|
||||
{"param_name": "total_working_days", "variable_label": "Total Working Days", \
|
||||
"path": "get_total_workdays"},
|
||||
{"param_name": "tot_cost_shipments", "variable_label": "Total Cost of Shipments", \
|
||||
"path": "get_total_cost_of_shipments"},
|
||||
{"param_name": "tot_days_late", "variable_label": "Total Days Late", \
|
||||
"path": "get_total_days_late"},
|
||||
{"param_name": "total_shipments", "variable_label": "Total Shipments", \
|
||||
"path": "get_total_shipments"}
|
||||
]
|
||||
install_standing_docs = [
|
||||
{"min_grade": 0.0, "prevent_rfqs": 1, "notify_supplier": 0, "max_grade": 30.0, "prevent_pos": 1, \
|
||||
"standing_color": "Red", "notify_employee": 0, "standing_name": "Very Poor"},
|
||||
{"min_grade": 30.0, "prevent_rfqs": 1, "notify_supplier": 0, "max_grade": 50.0, "prevent_pos": 0, \
|
||||
"standing_color": "Red", "notify_employee": 0, "standing_name": "Poor"},
|
||||
{"min_grade": 50.0, "prevent_rfqs": 0, "notify_supplier": 0, "max_grade": 80.0, "prevent_pos": 0, \
|
||||
"standing_color": "Green", "notify_employee": 0, "standing_name": "Average"},
|
||||
{"min_grade": 80.0, "prevent_rfqs": 0, "notify_supplier": 0, "max_grade": 100.0, "prevent_pos": 0, \
|
||||
"standing_color": "Blue", "notify_employee": 0, "standing_name": "Excellent"},
|
||||
]
|
||||
|
||||
for d in install_variable_docs:
|
||||
try:
|
||||
d['doctype'] = "Supplier Scorecard Variable"
|
||||
frappe.get_doc(d).insert()
|
||||
except frappe.NameError:
|
||||
pass
|
||||
for d in install_standing_docs:
|
||||
try:
|
||||
d['doctype'] = "Supplier Scorecard Standing"
|
||||
frappe.get_doc(d).insert()
|
||||
except frappe.NameError:
|
||||
pass
|
||||
@@ -0,0 +1,15 @@
|
||||
from frappe import _
|
||||
|
||||
def get_data():
|
||||
return {
|
||||
'heatmap': True,
|
||||
'heatmap_message': _('This covers all scorecards tied to this Setup'),
|
||||
'fieldname': 'supplier',
|
||||
'method' : 'erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.get_timeline_data',
|
||||
'transactions': [
|
||||
{
|
||||
'label': _('Scorecards'),
|
||||
'items': ['Supplier Scorecard Period']
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
/* global frappe, __ */
|
||||
|
||||
frappe.listview_settings["Supplier Scorecard"] = {
|
||||
add_fields: ["indicator_color", "status"],
|
||||
get_indicator: function(doc) {
|
||||
|
||||
if (doc.indicator_color) {
|
||||
return [__(doc.status), doc.indicator_color.toLowerCase(), "status,=," + doc.status];
|
||||
} else {
|
||||
return [__("Unknown"), "darkgrey", "status,=,''"];
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
@@ -0,0 +1,190 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
class TestSupplierScorecard(unittest.TestCase):
|
||||
|
||||
def test_create_scorecard(self):
|
||||
delete_test_scorecards()
|
||||
my_doc = make_supplier_scorecard()
|
||||
doc = my_doc.insert()
|
||||
self.assertEqual(doc.name, valid_scorecard[0].get("supplier"))
|
||||
|
||||
def test_criteria_weight(self):
|
||||
delete_test_scorecards()
|
||||
my_doc = make_supplier_scorecard()
|
||||
for d in my_doc.criteria:
|
||||
d.weight = 0
|
||||
self.assertRaises(frappe.ValidationError,my_doc.insert)
|
||||
|
||||
def test_missing_variable(self):
|
||||
delete_test_scorecards()
|
||||
my_doc = make_supplier_scorecard()
|
||||
del my_doc.variables
|
||||
self.assertRaises(frappe.ValidationError,my_doc.insert)
|
||||
|
||||
def make_supplier_scorecard():
|
||||
my_doc = frappe.get_doc(valid_scorecard[0])
|
||||
|
||||
# Make sure the criteria exist (making them)
|
||||
for d in valid_scorecard[0].get("criteria"):
|
||||
if not frappe.db.exists("Supplier Scorecard Criteria", d.get("criteria_name")):
|
||||
d["doctype"] = "Supplier Scorecard Criteria"
|
||||
d["name"] = d.get("criteria_name")
|
||||
my_criteria = frappe.get_doc(d)
|
||||
my_criteria.insert()
|
||||
return my_doc
|
||||
|
||||
|
||||
def delete_test_scorecards():
|
||||
my_doc = make_supplier_scorecard()
|
||||
if frappe.db.exists("Supplier Scorecard", my_doc.name):
|
||||
# Delete all the periods, then delete the scorecard
|
||||
frappe.db.sql("""delete from `tabSupplier Scorecard Period` where scorecard = %(scorecard)s""", {'scorecard': my_doc.name})
|
||||
frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Criteria` where parenttype = 'Supplier Scorecard Period'""")
|
||||
frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Standing` where parenttype = 'Supplier Scorecard Period'""")
|
||||
frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Variable` where parenttype = 'Supplier Scorecard Period'""")
|
||||
frappe.delete_doc(my_doc.doctype, my_doc.name)
|
||||
|
||||
valid_scorecard = [
|
||||
{
|
||||
"standings":[
|
||||
{
|
||||
"min_grade":0.0,"name":"Very Poor",
|
||||
"prevent_rfqs":1,
|
||||
"notify_supplier":0,
|
||||
"doctype":"Supplier Scorecard Standing",
|
||||
"max_grade":30.0,
|
||||
"prevent_pos":1,
|
||||
"warn_pos":0,
|
||||
"warn_rfqs":0,
|
||||
"standing_color":"Red",
|
||||
"notify_employee":0,
|
||||
"standing_name":"Very Poor",
|
||||
"parenttype":"Supplier Scorecard",
|
||||
"parentfield":"standings"
|
||||
},
|
||||
{
|
||||
"min_grade":30.0,
|
||||
"name":"Poor",
|
||||
"prevent_rfqs":1,
|
||||
"notify_supplier":0,
|
||||
"doctype":"Supplier Scorecard Standing",
|
||||
"max_grade":50.0,
|
||||
"prevent_pos":0,
|
||||
"warn_pos":0,
|
||||
"warn_rfqs":0,
|
||||
"standing_color":"Red",
|
||||
"notify_employee":0,
|
||||
"standing_name":"Poor",
|
||||
"parenttype":"Supplier Scorecard",
|
||||
"parentfield":"standings"
|
||||
},
|
||||
{
|
||||
"min_grade":50.0,
|
||||
"name":"Average",
|
||||
"prevent_rfqs":0,
|
||||
"notify_supplier":0,
|
||||
"doctype":"Supplier Scorecard Standing",
|
||||
"max_grade":80.0,
|
||||
"prevent_pos":0,
|
||||
"warn_pos":0,
|
||||
"warn_rfqs":0,
|
||||
"standing_color":"Green",
|
||||
"notify_employee":0,
|
||||
"standing_name":"Average",
|
||||
"parenttype":"Supplier Scorecard",
|
||||
"parentfield":"standings"
|
||||
},
|
||||
{
|
||||
"min_grade":80.0,
|
||||
"name":"Excellent",
|
||||
"prevent_rfqs":0,
|
||||
"notify_supplier":0,
|
||||
"doctype":"Supplier Scorecard Standing",
|
||||
"max_grade":100.0,
|
||||
"prevent_pos":0,
|
||||
"warn_pos":0,
|
||||
"warn_rfqs":0,
|
||||
"standing_color":"Blue",
|
||||
"notify_employee":0,
|
||||
"standing_name":"Excellent",
|
||||
"parenttype":"Supplier Scorecard",
|
||||
"parentfield":"standings"
|
||||
}
|
||||
],
|
||||
"prevent_pos":0,
|
||||
"variables": [
|
||||
{
|
||||
"param_name":"cost_of_on_time_shipments",
|
||||
"doctype":"Supplier Scorecard Scoring Variable",
|
||||
"parenttype":"Supplier Scorecard",
|
||||
"variable_label":"Cost of On Time Shipments",
|
||||
"path":"get_cost_of_on_time_shipments",
|
||||
"parentfield":"variables"
|
||||
},
|
||||
{
|
||||
"param_name":"tot_cost_shipments",
|
||||
"doctype":"Supplier Scorecard Scoring Variable",
|
||||
"parenttype":"Supplier Scorecard",
|
||||
"variable_label":"Total Cost of Shipments",
|
||||
"path":"get_total_cost_of_shipments",
|
||||
"parentfield":"variables"
|
||||
},
|
||||
{
|
||||
"param_name":"tot_days_late",
|
||||
"doctype":"Supplier Scorecard Scoring Variable",
|
||||
"parenttype":"Supplier Scorecard",
|
||||
"variable_label":"Total Days Late",
|
||||
"path":"get_total_days_late",
|
||||
"parentfield":"variables"
|
||||
},
|
||||
{
|
||||
"param_name":"total_working_days",
|
||||
"doctype":"Supplier Scorecard Scoring Variable",
|
||||
"parenttype":"Supplier Scorecard",
|
||||
"variable_label":"Total Working Days",
|
||||
"path":"get_total_workdays",
|
||||
"parentfield":"variables"
|
||||
},
|
||||
{
|
||||
"param_name":"on_time_shipment_num",
|
||||
"doctype":"Supplier Scorecard Scoring Variable",
|
||||
"parenttype":"Supplier Scorecard",
|
||||
"variable_label":"# of On Time Shipments",
|
||||
"path":"get_on_time_shipments",
|
||||
"parentfield":"variables"
|
||||
},
|
||||
{
|
||||
"param_name":"total_shipments",
|
||||
"doctype":"Supplier Scorecard Scoring Variable",
|
||||
"parenttype":"Supplier Scorecard",
|
||||
"variable_label":"Total Shipments",
|
||||
"path":"get_total_shipments",
|
||||
"parentfield":"variables"
|
||||
}
|
||||
],
|
||||
"period":"Per Month",
|
||||
"doctype":"Supplier Scorecard",
|
||||
"warn_pos":0,
|
||||
"warn_rfqs":0,
|
||||
"notify_supplier":0,
|
||||
"criteria":[
|
||||
{
|
||||
"weight":100.0,
|
||||
"doctype":"Supplier Scorecard Scoring Criteria",
|
||||
"formula":"(({cost_of_on_time_shipments} / {tot_cost_shipments}) if {tot_cost_shipments} > 0 else 1 )* 100 ",
|
||||
"criteria_name":"Delivery",
|
||||
"max_score":100.0,
|
||||
}
|
||||
],
|
||||
"supplier":"_Test Supplier",
|
||||
"name":"_Test Supplier",
|
||||
"weighting_function":"{total_score} * max( 0, min ( 1 , (12 - {period_number}) / 12) )",
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
/* global frappe */
|
||||
|
||||
frappe.ui.form.on("Supplier Scorecard Criteria", {
|
||||
refresh: function() {}
|
||||
});
|
||||
@@ -0,0 +1,184 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:criteria_name",
|
||||
"beta": 1,
|
||||
"creation": "2017-05-29 01:32:43.064891",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "criteria_name",
|
||||
"fieldtype": "Data",
|
||||
"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": "Criteria Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "weight",
|
||||
"fieldtype": "Percent",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Criteria Weight",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "100",
|
||||
"fieldname": "max_score",
|
||||
"fieldtype": "Float",
|
||||
"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": "Max Score",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "formula",
|
||||
"fieldtype": "Small Text",
|
||||
"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": "Criteria Formula",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-17 10:30:47.458285",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Scorecard Criteria",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
import re
|
||||
from frappe.model.document import Document
|
||||
|
||||
class InvalidFormulaVariable(frappe.ValidationError): pass
|
||||
|
||||
class SupplierScorecardCriteria(Document):
|
||||
def validate(self):
|
||||
self.validate_variables()
|
||||
self.validate_formula()
|
||||
|
||||
def validate_variables(self):
|
||||
# make sure all the variables exist
|
||||
_get_variables(self)
|
||||
|
||||
def validate_formula(self):
|
||||
# evaluate the formula with 0's to make sure it is valid
|
||||
test_formula = self.formula.replace("\r", "").replace("\n", "")
|
||||
|
||||
regex = r"\{(.*?)\}"
|
||||
|
||||
mylist = re.finditer(regex, test_formula, re.MULTILINE | re.DOTALL)
|
||||
for dummy1, match in enumerate(mylist):
|
||||
for dummy2 in range(0, len(match.groups())):
|
||||
test_formula = test_formula.replace('{' + match.group(1) + '}', "0")
|
||||
|
||||
test_formula = test_formula.replace('<','<').replace('>','>')
|
||||
try:
|
||||
frappe.safe_eval(test_formula, None, {'max':max, 'min': min})
|
||||
except Exception:
|
||||
frappe.throw(_("Error evaluating the criteria formula"))
|
||||
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_scoring_criteria(criteria_name):
|
||||
criteria = frappe.get_doc("Supplier Scorecard Criteria", criteria_name)
|
||||
|
||||
return criteria
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_criteria_list():
|
||||
criteria = frappe.db.sql("""
|
||||
SELECT
|
||||
scs.name
|
||||
FROM
|
||||
`tabSupplier Scorecard Criteria` scs""",
|
||||
{}, as_dict=1)
|
||||
|
||||
return criteria
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_variables(criteria_name):
|
||||
criteria = frappe.get_doc("Supplier Scorecard Criteria", criteria_name)
|
||||
return _get_variables(criteria)
|
||||
|
||||
def _get_variables(criteria):
|
||||
my_variables = []
|
||||
regex = r"\{(.*?)\}"
|
||||
|
||||
mylist = re.finditer(regex, criteria.formula, re.MULTILINE | re.DOTALL)
|
||||
for dummy1, match in enumerate(mylist):
|
||||
for dummy2 in range(0, len(match.groups())):
|
||||
try:
|
||||
#var = frappe.get_doc("Supplier Scorecard Variable", {'param_name' : d})
|
||||
var = frappe.db.sql("""
|
||||
SELECT
|
||||
scv.name
|
||||
FROM
|
||||
`tabSupplier Scorecard Variable` scv
|
||||
WHERE
|
||||
param_name=%(param)s""",
|
||||
{'param':match.group(1)},)[0][0]
|
||||
my_variables.append(var)
|
||||
except Exception:
|
||||
# Ignore the ones where the variable can't be found
|
||||
frappe.throw(_('Unable to find variable: ') + str(match.group(1)), InvalidFormulaVariable)
|
||||
#pass
|
||||
|
||||
|
||||
#frappe.msgprint(str(my_variables))
|
||||
return my_variables
|
||||
@@ -0,0 +1,75 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
class TestSupplierScorecardCriteria(unittest.TestCase):
|
||||
def test_variables_exist(self):
|
||||
delete_test_scorecards()
|
||||
for d in test_good_criteria:
|
||||
frappe.get_doc(d).insert()
|
||||
|
||||
self.assertRaises(frappe.ValidationError,frappe.get_doc(test_bad_criteria[0]).insert)
|
||||
|
||||
def test_formula_validate(self):
|
||||
delete_test_scorecards()
|
||||
self.assertRaises(frappe.ValidationError,frappe.get_doc(test_bad_criteria[1]).insert)
|
||||
self.assertRaises(frappe.ValidationError,frappe.get_doc(test_bad_criteria[2]).insert)
|
||||
|
||||
def delete_test_scorecards():
|
||||
# Delete all the periods so we can delete all the criteria
|
||||
frappe.db.sql("""delete from `tabSupplier Scorecard Period`""")
|
||||
frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Criteria` where parenttype = 'Supplier Scorecard Period'""")
|
||||
frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Standing` where parenttype = 'Supplier Scorecard Period'""")
|
||||
frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Variable` where parenttype = 'Supplier Scorecard Period'""")
|
||||
|
||||
for d in test_good_criteria:
|
||||
if frappe.db.exists("Supplier Scorecard Criteria", d.get("name")):
|
||||
# Delete all the periods, then delete the scorecard
|
||||
frappe.delete_doc(d.get("doctype"), d.get("name"))
|
||||
|
||||
for d in test_bad_criteria:
|
||||
if frappe.db.exists("Supplier Scorecard Criteria", d.get("name")):
|
||||
# Delete all the periods, then delete the scorecard
|
||||
frappe.delete_doc(d.get("doctype"), d.get("name"))
|
||||
|
||||
test_good_criteria = [
|
||||
{
|
||||
"name":"Delivery",
|
||||
"weight":40.0,
|
||||
"doctype":"Supplier Scorecard Criteria",
|
||||
"formula":"(({cost_of_on_time_shipments} / {tot_cost_shipments}) if {tot_cost_shipments} > 0 else 1 )* 100",
|
||||
"criteria_name":"Delivery",
|
||||
"max_score":100.0
|
||||
},
|
||||
]
|
||||
|
||||
test_bad_criteria = [
|
||||
{
|
||||
"name":"Fake Criteria 1",
|
||||
"weight":40.0,
|
||||
"doctype":"Supplier Scorecard Criteria",
|
||||
"formula":"(({fake_variable} / {tot_cost_shipments}) if {tot_cost_shipments} > 0 else 1 )* 100", # Invalid variable name
|
||||
"criteria_name":"Fake Criteria 1",
|
||||
"max_score":100.0
|
||||
},
|
||||
{
|
||||
"name":"Fake Criteria 2",
|
||||
"weight":40.0,
|
||||
"doctype":"Supplier Scorecard Criteria",
|
||||
"formula":"(({cost_of_on_time_shipments} / {tot_cost_shipments}))* 100", # Force 0 divided by 0
|
||||
"criteria_name":"Fake Criteria 2",
|
||||
"max_score":100.0
|
||||
},
|
||||
{
|
||||
"name":"Fake Criteria 3",
|
||||
"weight":40.0,
|
||||
"doctype":"Supplier Scorecard Criteria",
|
||||
"formula":"(({cost_of_on_time_shipments} {cost_of_on_time_shipments} / {tot_cost_shipments}))* 100", # Two variables beside eachother
|
||||
"criteria_name":"Fake Criteria 3",
|
||||
"max_score":100.0
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
/* global frappe */
|
||||
|
||||
|
||||
frappe.ui.form.on("Supplier Scorecard Period", {
|
||||
onload: function(frm) {
|
||||
frm.get_field("variables").grid.toggle_display("value", true);
|
||||
frm.get_field("criteria").grid.toggle_display("score", true);
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,397 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "naming_series:",
|
||||
"beta": 1,
|
||||
"creation": "2017-05-30 00:38:18.773013",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "supplier",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Supplier",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Supplier",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"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": "Naming Series",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "SSC-",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "total_score",
|
||||
"fieldtype": "Percent",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Period Score",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_2",
|
||||
"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": "start_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Start Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "end_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": "End Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_11",
|
||||
"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": "Calculations",
|
||||
"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": "criteria",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Criteria",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Supplier Scorecard Scoring Criteria",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "variables",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Variables",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Supplier Scorecard Scoring Variable",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fieldname": "sec_ref",
|
||||
"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": "Reference",
|
||||
"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": "scorecard",
|
||||
"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": "Supplier Scorecard Setup",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Supplier Scorecard",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 1,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-12 07:33:26.130861",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Scorecard Period",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import throw, _
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
import erpnext.buying.doctype.supplier_scorecard_variable.supplier_scorecard_variable as variable_functions
|
||||
|
||||
class SupplierScorecardPeriod(Document):
|
||||
|
||||
def validate(self):
|
||||
self.validate_criteria_weights()
|
||||
self.calculate_variables()
|
||||
self.calculate_criteria()
|
||||
self.calculate_score()
|
||||
|
||||
def validate_criteria_weights(self):
|
||||
|
||||
weight = 0
|
||||
for c in self.criteria:
|
||||
weight += c.weight
|
||||
|
||||
if weight != 100:
|
||||
throw(_('Criteria weights must add up to 100%'))
|
||||
|
||||
def calculate_variables(self):
|
||||
for var in self.variables:
|
||||
|
||||
if '.' in var.path:
|
||||
method_to_call = import_string_path(var.path)
|
||||
var.value = method_to_call(self)
|
||||
else:
|
||||
method_to_call = getattr(variable_functions, var.path)
|
||||
var.value = method_to_call(self)
|
||||
|
||||
|
||||
|
||||
def calculate_criteria(self):
|
||||
#Get the criteria
|
||||
for crit in self.criteria:
|
||||
|
||||
#me = ""
|
||||
my_eval_statement = crit.formula.replace("\r", "").replace("\n", "")
|
||||
#for let in my_eval_statement:
|
||||
# me += let.encode('hex') + " "
|
||||
#frappe.msgprint(me)
|
||||
|
||||
for var in self.variables:
|
||||
if var.value:
|
||||
if var.param_name in my_eval_statement:
|
||||
my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', "{:.2f}".format(var.value))
|
||||
else:
|
||||
if var.param_name in my_eval_statement:
|
||||
my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', '0.0')
|
||||
|
||||
#frappe.msgprint(my_eval_statement )
|
||||
|
||||
my_eval_statement = my_eval_statement.replace('<','<').replace('>','>')
|
||||
|
||||
try:
|
||||
crit.score = min(crit.max_score, max( 0 ,frappe.safe_eval(my_eval_statement, None, {'max':max, 'min': min})))
|
||||
except Exception:
|
||||
frappe.throw(_("Could not solve criteria score function for {0}. Make sure the formula is valid.".format(crit.criteria_name)),frappe.ValidationError)
|
||||
crit.score = 0
|
||||
|
||||
def calculate_score(self):
|
||||
myscore = 0
|
||||
for crit in self.criteria:
|
||||
myscore += crit.score * crit.weight/100.0
|
||||
self.total_score = myscore
|
||||
|
||||
def calculate_weighted_score(self, weighing_function):
|
||||
my_eval_statement = weighing_function.replace("\r", "").replace("\n", "")
|
||||
|
||||
for var in self.variables:
|
||||
if var.value:
|
||||
if var.param_name in my_eval_statement:
|
||||
my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', "{:.2f}".format(var.value))
|
||||
else:
|
||||
if var.param_name in my_eval_statement:
|
||||
my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', '0.0')
|
||||
|
||||
my_eval_statement = my_eval_statement.replace('<','<').replace('>','>')
|
||||
|
||||
try:
|
||||
weighed_score = frappe.safe_eval(my_eval_statement, None, {'max':max, 'min': min})
|
||||
except Exception:
|
||||
frappe.throw(_("Could not solve weighted score function. Make sure the formula is valid."),frappe.ValidationError)
|
||||
weighed_score = 0
|
||||
return weighed_score
|
||||
|
||||
|
||||
|
||||
def import_string_path(path):
|
||||
components = path.split('.')
|
||||
mod = __import__(components[0])
|
||||
for comp in components[1:]:
|
||||
mod = getattr(mod, comp)
|
||||
return mod
|
||||
|
||||
|
||||
def post_process(source, target):
|
||||
pass
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_supplier_scorecard(source_name, target_doc=None):
|
||||
#def update_item(obj, target, source_parent):
|
||||
# target.qty = flt(obj.qty) - flt(obj.received_qty)
|
||||
# target.stock_qty = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.conversion_factor)
|
||||
# target.amount = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.rate)
|
||||
# target.base_amount = (flt(obj.qty) - flt(obj.received_qty)) * \
|
||||
# flt(obj.rate) * flt(source_parent.conversion_rate)
|
||||
|
||||
doc = get_mapped_doc("Supplier Scorecard", source_name, {
|
||||
"Supplier Scorecard": {
|
||||
"doctype": "Supplier Scorecard Period"
|
||||
},
|
||||
"Supplier Scorecard Scoring Variable": {
|
||||
"doctype": "Supplier Scorecard Scoring Variable",
|
||||
"add_if_empty": True
|
||||
},
|
||||
"Supplier Scorecard Scoring Constraint": {
|
||||
"doctype": "Supplier Scorecard Scoring Constraint",
|
||||
"add_if_empty": True
|
||||
}
|
||||
}, target_doc, post_process)
|
||||
|
||||
return doc
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
class TestSupplierScorecardPeriod(unittest.TestCase):
|
||||
pass
|
||||
@@ -0,0 +1,280 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 1,
|
||||
"creation": "2017-05-29 01:32:17.988454",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 3,
|
||||
"fieldname": "criteria_name",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Criteria Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Supplier Scorecard Criteria",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_2",
|
||||
"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,
|
||||
"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": 2,
|
||||
"fieldname": "weight",
|
||||
"fieldtype": "Percent",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Criteria Weight",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_4",
|
||||
"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,
|
||||
"default": "100",
|
||||
"fieldname": "max_score",
|
||||
"fieldtype": "Float",
|
||||
"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": "Max Score",
|
||||
"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": "section_break_6",
|
||||
"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,
|
||||
"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": "formula",
|
||||
"fieldtype": "Small Text",
|
||||
"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": "Criteria Formula",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "score",
|
||||
"fieldtype": "Percent",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Score",
|
||||
"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
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-12 07:33:41.532361",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Scorecard Scoring Criteria",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class SupplierScorecardScoringCriteria(Document):
|
||||
pass
|
||||
@@ -0,0 +1,491 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 1,
|
||||
"creation": "2017-05-29 01:36:22.697234",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 3,
|
||||
"fieldname": "standing_name",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Standing Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Supplier Scorecard Standing",
|
||||
"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": "column_break_2",
|
||||
"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": "standing_color",
|
||||
"fieldtype": "Select",
|
||||
"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": "Color",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Blue\nPurple\nGreen\nYellow\nOrange\nRed",
|
||||
"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": "section_break_4",
|
||||
"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,
|
||||
"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": 2,
|
||||
"fieldname": "min_grade",
|
||||
"fieldtype": "Percent",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Min Grade",
|
||||
"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": 2,
|
||||
"fieldname": "max_grade",
|
||||
"fieldtype": "Percent",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Max Grade",
|
||||
"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": "actions",
|
||||
"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": "Actions",
|
||||
"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": "warn_rfqs",
|
||||
"fieldtype": "Check",
|
||||
"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": "Warn RFQs",
|
||||
"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": "warn_pos",
|
||||
"fieldtype": "Check",
|
||||
"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": "Warn Purchase Orders",
|
||||
"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": "prevent_rfqs",
|
||||
"fieldtype": "Check",
|
||||
"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": "Prevent RFQs",
|
||||
"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": "prevent_pos",
|
||||
"fieldtype": "Check",
|
||||
"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": "Prevent Purchase Orders",
|
||||
"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": "column_break_10",
|
||||
"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": "notify_supplier",
|
||||
"fieldtype": "Check",
|
||||
"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": "Notify Supplier",
|
||||
"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": "notify_employee",
|
||||
"fieldtype": "Check",
|
||||
"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": "Notify Employee",
|
||||
"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": "employee_link",
|
||||
"fieldtype": "Link",
|
||||
"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": "Employee ",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Employee",
|
||||
"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
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-12 07:33:20.615684",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Scorecard Scoring Standing",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class SupplierScorecardScoringStanding(Document):
|
||||
pass
|
||||
@@ -0,0 +1,222 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 1,
|
||||
"creation": "2017-05-29 01:30:06.105240",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 3,
|
||||
"fieldname": "variable_label",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Variable Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Supplier Scorecard Variable",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"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": "Description",
|
||||
"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": "is_custom",
|
||||
"fieldtype": "Check",
|
||||
"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": "Custom?",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "param_name",
|
||||
"fieldtype": "Data",
|
||||
"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": "Parameter Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "path",
|
||||
"fieldtype": "Data",
|
||||
"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": "Path",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fieldname": "value",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Value",
|
||||
"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
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-12 07:33:36.671502",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Scorecard Scoring Variable",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class SupplierScorecardScoringVariable(Document):
|
||||
pass
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
/* global frappe */
|
||||
|
||||
frappe.ui.form.on("Supplier Scorecard Standing", {
|
||||
refresh: function() {
|
||||
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,424 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:standing_name",
|
||||
"beta": 1,
|
||||
"creation": "2017-05-29 01:36:47.893639",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "standing_name",
|
||||
"fieldtype": "Data",
|
||||
"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": "Standing Name",
|
||||
"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": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "standing_color",
|
||||
"fieldtype": "Select",
|
||||
"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": "Color",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Blue\nPurple\nGreen\nYellow\nOrange\nRed",
|
||||
"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": "min_grade",
|
||||
"fieldtype": "Percent",
|
||||
"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": "Min Grade",
|
||||
"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": "max_grade",
|
||||
"fieldtype": "Percent",
|
||||
"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": "Max Grade",
|
||||
"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": "column_break_5",
|
||||
"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": "warn_rfqs",
|
||||
"fieldtype": "Check",
|
||||
"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": "Warn RFQs",
|
||||
"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": "warn_pos",
|
||||
"fieldtype": "Check",
|
||||
"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": "Warn Purchase Orders",
|
||||
"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": "prevent_rfqs",
|
||||
"fieldtype": "Check",
|
||||
"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": "Prevent RFQs",
|
||||
"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": "prevent_pos",
|
||||
"fieldtype": "Check",
|
||||
"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": "Prevent Purchase Orders",
|
||||
"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": "notify_supplier",
|
||||
"fieldtype": "Check",
|
||||
"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": "Notify Supplier",
|
||||
"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": "notify_employee",
|
||||
"fieldtype": "Check",
|
||||
"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": "Notify Other",
|
||||
"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": "employee_link",
|
||||
"fieldtype": "Link",
|
||||
"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": "Other",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Employee",
|
||||
"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
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-12 07:33:16.560273",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Scorecard Standing",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class SupplierScorecardStanding(Document):
|
||||
pass
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_scoring_standing(standing_name):
|
||||
standing = frappe.get_doc("Supplier Scorecard Standing", standing_name)
|
||||
|
||||
return standing
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_standings_list():
|
||||
standings = frappe.db.sql("""
|
||||
SELECT
|
||||
scs.name
|
||||
FROM
|
||||
`tabSupplier Scorecard Standing` scs""",
|
||||
{}, as_dict=1)
|
||||
|
||||
return standings
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
class TestSupplierScorecardStanding(unittest.TestCase):
|
||||
pass
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
/* global frappe */
|
||||
|
||||
frappe.ui.form.on("Supplier Scorecard Variable", {
|
||||
refresh: function() {
|
||||
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,242 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:variable_label",
|
||||
"beta": 1,
|
||||
"creation": "2017-05-29 01:30:34.688389",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "variable_label",
|
||||
"fieldtype": "Data",
|
||||
"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": "Variable Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "is_custom",
|
||||
"fieldtype": "Check",
|
||||
"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": "Custom?",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "param_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Parameter Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "path",
|
||||
"fieldtype": "Data",
|
||||
"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": "Path",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_5",
|
||||
"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": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"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": "Description",
|
||||
"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
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-12 07:33:31.395262",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Scorecard Variable",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
||||
@@ -0,0 +1,503 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import sys
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import getdate
|
||||
|
||||
class VariablePathNotFound(frappe.ValidationError): pass
|
||||
|
||||
class SupplierScorecardVariable(Document):
|
||||
def validate(self):
|
||||
self.validate_path_exists()
|
||||
|
||||
def validate_path_exists(self):
|
||||
if '.' in self.path:
|
||||
try:
|
||||
from erpnext.buying.doctype.supplier_scorecard_period.supplier_scorecard_period import import_string_path
|
||||
import_string_path(self.path)
|
||||
except AttributeError:
|
||||
frappe.throw(_("Could not find path for " + self.path), VariablePathNotFound)
|
||||
|
||||
else:
|
||||
if not hasattr(sys.modules[__name__], self.path):
|
||||
frappe.throw(_("Could not find path for " + self.path), VariablePathNotFound)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_scoring_variable(variable_label):
|
||||
variable = frappe.get_doc("Supplier Scorecard Variable", variable_label)
|
||||
|
||||
return variable
|
||||
|
||||
def get_total_workdays(scorecard):
|
||||
""" Gets the number of days in this period"""
|
||||
delta = getdate(scorecard.end_date) - getdate(scorecard.start_date)
|
||||
return delta.days
|
||||
|
||||
def get_item_workdays(scorecard):
|
||||
""" Gets the number of days in this period"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
total_item_days = frappe.db.sql("""
|
||||
SELECT
|
||||
SUM(DATEDIFF( %(end_date)s, po_item.schedule_date) * (po_item.qty))
|
||||
FROM
|
||||
`tabPurchase Order Item` po_item,
|
||||
`tabPurchase Order` po
|
||||
WHERE
|
||||
po.supplier = %(supplier)s
|
||||
AND po_item.received_qty < po_item.qty
|
||||
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND po_item.parent = po.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if not total_item_days:
|
||||
total_item_days = 0
|
||||
return total_item_days
|
||||
|
||||
|
||||
|
||||
def get_total_cost_of_shipments(scorecard):
|
||||
""" Gets the total cost of all shipments in the period (based on Purchase Orders)"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
SUM(po_item.base_amount)
|
||||
FROM
|
||||
`tabPurchase Order Item` po_item,
|
||||
`tabPurchase Order` po
|
||||
WHERE
|
||||
po.supplier = %(supplier)s
|
||||
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND po_item.docstatus = 1
|
||||
AND po_item.parent = po.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if data:
|
||||
return data
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_cost_of_delayed_shipments(scorecard):
|
||||
""" Gets the total cost of all delayed shipments in the period (based on Purchase Receipts - POs)"""
|
||||
return get_total_cost_of_shipments(scorecard) - get_cost_of_on_time_shipments(scorecard)
|
||||
|
||||
def get_cost_of_on_time_shipments(scorecard):
|
||||
""" Gets the total cost of all on_time shipments in the period (based on Purchase Receipts)"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
|
||||
total_delivered_on_time_costs = frappe.db.sql("""
|
||||
SELECT
|
||||
SUM(pr_item.base_amount)
|
||||
FROM
|
||||
`tabPurchase Order Item` po_item,
|
||||
`tabPurchase Receipt Item` pr_item,
|
||||
`tabPurchase Order` po,
|
||||
`tabPurchase Receipt` pr
|
||||
WHERE
|
||||
po.supplier = %(supplier)s
|
||||
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND po_item.schedule_date >= pr.posting_date
|
||||
AND pr_item.docstatus = 1
|
||||
AND pr_item.purchase_order_item = po_item.name
|
||||
AND po_item.parent = po.name
|
||||
AND pr_item.parent = pr.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if total_delivered_on_time_costs:
|
||||
return total_delivered_on_time_costs
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
def get_total_days_late(scorecard):
|
||||
""" Gets the number of item days late in the period (based on Purchase Receipts vs POs)"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
total_delivered_late_days = frappe.db.sql("""
|
||||
SELECT
|
||||
SUM(DATEDIFF(pr.posting_date,po_item.schedule_date)* pr_item.qty)
|
||||
FROM
|
||||
`tabPurchase Order Item` po_item,
|
||||
`tabPurchase Receipt Item` pr_item,
|
||||
`tabPurchase Order` po,
|
||||
`tabPurchase Receipt` pr
|
||||
WHERE
|
||||
po.supplier = %(supplier)s
|
||||
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND po_item.schedule_date < pr.posting_date
|
||||
AND pr_item.docstatus = 1
|
||||
AND pr_item.purchase_order_item = po_item.name
|
||||
AND po_item.parent = po.name
|
||||
AND pr_item.parent = pr.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
if not total_delivered_late_days:
|
||||
total_delivered_late_days = 0
|
||||
|
||||
total_missed_late_days = frappe.db.sql("""
|
||||
SELECT
|
||||
SUM(DATEDIFF( %(end_date)s, po_item.schedule_date) * (po_item.qty - po_item.received_qty))
|
||||
FROM
|
||||
`tabPurchase Order Item` po_item,
|
||||
`tabPurchase Order` po
|
||||
WHERE
|
||||
po.supplier = %(supplier)s
|
||||
AND po_item.received_qty < po_item.qty
|
||||
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND po_item.parent = po.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if not total_missed_late_days:
|
||||
total_missed_late_days = 0
|
||||
return total_missed_late_days + total_delivered_late_days
|
||||
|
||||
def get_on_time_shipments(scorecard):
|
||||
""" Gets the number of late shipments (counting each item) in the period (based on Purchase Receipts vs POs)"""
|
||||
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
total_items_delivered_on_time = frappe.db.sql("""
|
||||
SELECT
|
||||
COUNT(pr_item.qty)
|
||||
FROM
|
||||
`tabPurchase Order Item` po_item,
|
||||
`tabPurchase Receipt Item` pr_item,
|
||||
`tabPurchase Order` po,
|
||||
`tabPurchase Receipt` pr
|
||||
WHERE
|
||||
po.supplier = %(supplier)s
|
||||
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND po_item.schedule_date <= pr.posting_date
|
||||
AND po_item.qty = pr_item.qty
|
||||
AND pr_item.docstatus = 1
|
||||
AND pr_item.purchase_order_item = po_item.name
|
||||
AND po_item.parent = po.name
|
||||
AND pr_item.parent = pr.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if not total_items_delivered_on_time:
|
||||
total_items_delivered_on_time = 0
|
||||
return total_items_delivered_on_time
|
||||
|
||||
def get_late_shipments(scorecard):
|
||||
""" Gets the number of late shipments (counting each item) in the period (based on Purchase Receipts vs POs)"""
|
||||
return get_total_shipments(scorecard) - get_on_time_shipments(scorecard)
|
||||
|
||||
def get_total_received(scorecard):
|
||||
""" Gets the total number of received shipments in the period (based on Purchase Receipts)"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
COUNT(pr_item.base_amount)
|
||||
FROM
|
||||
`tabPurchase Receipt Item` pr_item,
|
||||
`tabPurchase Receipt` pr
|
||||
WHERE
|
||||
pr.supplier = %(supplier)s
|
||||
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND pr_item.docstatus = 1
|
||||
AND pr_item.parent = pr.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if not data:
|
||||
data = 0
|
||||
return data
|
||||
|
||||
def get_total_received_amount(scorecard):
|
||||
""" Gets the total amount (in company currency) received in the period (based on Purchase Receipts)"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
SUM(pr_item.received_qty * pr_item.base_rate)
|
||||
FROM
|
||||
`tabPurchase Receipt Item` pr_item,
|
||||
`tabPurchase Receipt` pr
|
||||
WHERE
|
||||
pr.supplier = %(supplier)s
|
||||
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND pr_item.docstatus = 1
|
||||
AND pr_item.parent = pr.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if not data:
|
||||
data = 0
|
||||
return data
|
||||
|
||||
def get_total_received_items(scorecard):
|
||||
""" Gets the total number of received shipments in the period (based on Purchase Receipts)"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
SUM(pr_item.received_qty)
|
||||
FROM
|
||||
`tabPurchase Receipt Item` pr_item,
|
||||
`tabPurchase Receipt` pr
|
||||
WHERE
|
||||
pr.supplier = %(supplier)s
|
||||
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND pr_item.docstatus = 1
|
||||
AND pr_item.parent = pr.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if not data:
|
||||
data = 0
|
||||
return data
|
||||
|
||||
def get_total_rejected_amount(scorecard):
|
||||
""" Gets the total amount (in company currency) rejected in the period (based on Purchase Receipts)"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
SUM(pr_item.rejected_qty * pr_item.base_rate)
|
||||
FROM
|
||||
`tabPurchase Receipt Item` pr_item,
|
||||
`tabPurchase Receipt` pr
|
||||
WHERE
|
||||
pr.supplier = %(supplier)s
|
||||
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND pr_item.docstatus = 1
|
||||
AND pr_item.parent = pr.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if not data:
|
||||
data = 0
|
||||
return data
|
||||
|
||||
def get_total_rejected_items(scorecard):
|
||||
""" Gets the total number of rejected items in the period (based on Purchase Receipts)"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
SUM(pr_item.rejected_qty)
|
||||
FROM
|
||||
`tabPurchase Receipt Item` pr_item,
|
||||
`tabPurchase Receipt` pr
|
||||
WHERE
|
||||
pr.supplier = %(supplier)s
|
||||
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND pr_item.docstatus = 1
|
||||
AND pr_item.parent = pr.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if not data:
|
||||
data = 0
|
||||
return data
|
||||
|
||||
def get_total_accepted_amount(scorecard):
|
||||
""" Gets the total amount (in company currency) accepted in the period (based on Purchase Receipts)"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
SUM(pr_item.qty * pr_item.base_rate)
|
||||
FROM
|
||||
`tabPurchase Receipt Item` pr_item,
|
||||
`tabPurchase Receipt` pr
|
||||
WHERE
|
||||
pr.supplier = %(supplier)s
|
||||
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND pr_item.docstatus = 1
|
||||
AND pr_item.parent = pr.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if not data:
|
||||
data = 0
|
||||
return data
|
||||
|
||||
def get_total_accepted_items(scorecard):
|
||||
""" Gets the total number of rejected items in the period (based on Purchase Receipts)"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
SUM(pr_item.qty)
|
||||
FROM
|
||||
`tabPurchase Receipt Item` pr_item,
|
||||
`tabPurchase Receipt` pr
|
||||
WHERE
|
||||
pr.supplier = %(supplier)s
|
||||
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND pr_item.docstatus = 1
|
||||
AND pr_item.parent = pr.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if not data:
|
||||
data = 0
|
||||
return data
|
||||
|
||||
def get_total_shipments(scorecard):
|
||||
""" Gets the total number of ordered shipments to arrive in the period (based on Purchase Receipts)"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
COUNT(po_item.base_amount)
|
||||
FROM
|
||||
`tabPurchase Order Item` po_item,
|
||||
`tabPurchase Order` po
|
||||
WHERE
|
||||
po.supplier = %(supplier)s
|
||||
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND po_item.docstatus = 1
|
||||
AND po_item.parent = po.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if not data:
|
||||
data = 0
|
||||
return data
|
||||
|
||||
def get_rfq_total_number(scorecard):
|
||||
""" Gets the total number of RFQs sent to supplier"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
COUNT(rfq.name) as total_rfqs
|
||||
FROM
|
||||
`tabRequest for Quotation Item` rfq_item,
|
||||
`tabRequest for Quotation Supplier` rfq_sup,
|
||||
`tabRequest for Quotation` rfq
|
||||
WHERE
|
||||
rfq_sup.supplier = %(supplier)s
|
||||
AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND rfq_item.docstatus = 1
|
||||
AND rfq_item.parent = rfq.name
|
||||
AND rfq_sup.parent = rfq.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
|
||||
if not data:
|
||||
data = 0
|
||||
return data
|
||||
|
||||
def get_rfq_total_items(scorecard):
|
||||
""" Gets the total number of RFQ items sent to supplier"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
COUNT(rfq_item.name) as total_rfqs
|
||||
FROM
|
||||
`tabRequest for Quotation Item` rfq_item,
|
||||
`tabRequest for Quotation Supplier` rfq_sup,
|
||||
`tabRequest for Quotation` rfq
|
||||
WHERE
|
||||
rfq_sup.supplier = %(supplier)s
|
||||
AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND rfq_item.docstatus = 1
|
||||
AND rfq_item.parent = rfq.name
|
||||
AND rfq_sup.parent = rfq.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
if not data:
|
||||
data = 0
|
||||
return data
|
||||
|
||||
|
||||
def get_sq_total_number(scorecard):
|
||||
""" Gets the total number of RFQ items sent to supplier"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
COUNT(sq.name) as total_sqs
|
||||
FROM
|
||||
`tabRequest for Quotation Item` rfq_item,
|
||||
`tabSupplier Quotation Item` sq_item,
|
||||
`tabRequest for Quotation Supplier` rfq_sup,
|
||||
`tabRequest for Quotation` rfq,
|
||||
`tabSupplier Quotation` sq
|
||||
WHERE
|
||||
rfq_sup.supplier = %(supplier)s
|
||||
AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND sq_item.request_for_quotation_item = rfq_item.name
|
||||
AND sq_item.docstatus = 1
|
||||
AND rfq_item.docstatus = 1
|
||||
AND sq.supplier = %(supplier)s
|
||||
AND sq_item.parent = sq.name
|
||||
AND rfq_item.parent = rfq.name
|
||||
AND rfq_sup.parent = rfq.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
if not data:
|
||||
data = 0
|
||||
return data
|
||||
|
||||
def get_sq_total_items(scorecard):
|
||||
""" Gets the total number of RFQ items sent to supplier"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
|
||||
# Look up all PO Items with delivery dates between our dates
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
COUNT(sq_item.name) as total_sqs
|
||||
FROM
|
||||
`tabRequest for Quotation Item` rfq_item,
|
||||
`tabSupplier Quotation Item` sq_item,
|
||||
`tabSupplier Quotation` sq,
|
||||
`tabRequest for Quotation Supplier` rfq_sup,
|
||||
`tabRequest for Quotation` rfq
|
||||
WHERE
|
||||
rfq_sup.supplier = %(supplier)s
|
||||
AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND sq_item.request_for_quotation_item = rfq_item.name
|
||||
AND sq_item.docstatus = 1
|
||||
AND sq.supplier = %(supplier)s
|
||||
AND sq_item.parent = sq.name
|
||||
AND rfq_item.docstatus = 1
|
||||
AND rfq_item.parent = rfq.name
|
||||
AND rfq_sup.parent = rfq.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
if not data:
|
||||
data = 0
|
||||
return data
|
||||
|
||||
def get_rfq_response_days(scorecard):
|
||||
""" Gets the total number of days it has taken a supplier to respond to rfqs in the period"""
|
||||
supplier = frappe.get_doc('Supplier', scorecard.supplier)
|
||||
total_sq_days = frappe.db.sql("""
|
||||
SELECT
|
||||
SUM(DATEDIFF(sq.transaction_date, rfq.transaction_date))
|
||||
FROM
|
||||
`tabRequest for Quotation Item` rfq_item,
|
||||
`tabSupplier Quotation Item` sq_item,
|
||||
`tabSupplier Quotation` sq,
|
||||
`tabRequest for Quotation Supplier` rfq_sup,
|
||||
`tabRequest for Quotation` rfq
|
||||
WHERE
|
||||
rfq_sup.supplier = %(supplier)s
|
||||
AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
|
||||
AND sq_item.request_for_quotation_item = rfq_item.name
|
||||
AND sq_item.docstatus = 1
|
||||
AND sq.supplier = %(supplier)s
|
||||
AND sq_item.parent = sq.name
|
||||
AND rfq_item.docstatus = 1
|
||||
AND rfq_item.parent = rfq.name
|
||||
AND rfq_sup.parent = rfq.name""",
|
||||
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
|
||||
if not total_sq_days:
|
||||
total_sq_days = 0
|
||||
|
||||
|
||||
return total_sq_days
|
||||
@@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
from erpnext.buying.doctype.supplier_scorecard_variable.supplier_scorecard_variable import VariablePathNotFound
|
||||
|
||||
|
||||
class TestSupplierScorecardVariable(unittest.TestCase):
|
||||
def test_variable_exist(self):
|
||||
for d in test_existing_variables:
|
||||
my_doc = frappe.get_doc("Supplier Scorecard Variable", d.get("name"))
|
||||
self.assertEquals(my_doc.param_name, d.get('param_name'))
|
||||
self.assertEquals(my_doc.variable_label, d.get('variable_label'))
|
||||
self.assertEquals(my_doc.path, d.get('path'))
|
||||
|
||||
def test_path_exists(self):
|
||||
for d in test_good_variables:
|
||||
if frappe.db.exists(d):
|
||||
frappe.delete_doc(d.get("doctype"), d.get("name"))
|
||||
frappe.get_doc(d).insert()
|
||||
|
||||
for d in test_bad_variables:
|
||||
self.assertRaises(VariablePathNotFound,frappe.get_doc(d).insert)
|
||||
|
||||
test_existing_variables = [
|
||||
{
|
||||
"param_name":"total_accepted_items",
|
||||
"name":"Total Accepted Items",
|
||||
"doctype":"Supplier Scorecard Variable",
|
||||
"variable_label":"Total Accepted Items",
|
||||
"path":"get_total_accepted_items"
|
||||
},
|
||||
]
|
||||
|
||||
test_good_variables = [
|
||||
{
|
||||
"param_name":"good_variable1",
|
||||
"name":"Good Variable 1",
|
||||
"doctype":"Supplier Scorecard Variable",
|
||||
"variable_label":"Good Variable 1",
|
||||
"path":"get_total_accepted_items"
|
||||
},
|
||||
]
|
||||
|
||||
test_bad_variables = [
|
||||
{
|
||||
"param_name":"fake_variable1",
|
||||
"name":"Fake Variable 1",
|
||||
"doctype":"Supplier Scorecard Variable",
|
||||
"variable_label":"Fake Variable 1",
|
||||
"path":"get_fake_variable1"
|
||||
},
|
||||
]
|
||||
@@ -1 +1 @@
|
||||
- [ERPNext Manual in German](http://frappe.github.io/erpnext/user/manual/de/) contributed by [CWT Connector & Wire Technology GmbH](http://www.cwt-assembly.com/)
|
||||
- [ERPNext Manual in German](http://erpnext.org/docs/user/manual/de/) contributed by [CWT Connector & Wire Technology GmbH](http://www.cwt-assembly.com/)
|
||||
|
||||
@@ -1 +1 @@
|
||||
- **[Multi-currency Accounting](https://frappe.github.io/erpnext/user/guides/accounts/multi-currency-accounting)**: You can now have an Account in a different currency than your Company's currency
|
||||
- **[Multi-currency Accounting](https://frappe.io/docs/user/guides/accounts/multi-currency-accounting)**: You can now have an Account in a different currency than your Company's currency
|
||||
|
||||
@@ -141,6 +141,32 @@ def get_data():
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": _("Supplier Scorecard"),
|
||||
"items": [
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Supplier Scorecard",
|
||||
"description": _("All Supplier scorecards."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Supplier Scorecard Variable",
|
||||
"description": _("Templates of supplier scorecard variables.")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Supplier Scorecard Criteria",
|
||||
"description": _("Templates of supplier scorecard criteria."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Supplier Scorecard Standing",
|
||||
"description": _("Templates of supplier standings."),
|
||||
},
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": _("Other Reports"),
|
||||
"icon": "fa fa-list",
|
||||
|
||||
@@ -1,34 +1,3 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
docs_version = "7.x.x"
|
||||
|
||||
source_link = "https://github.com/frappe/erpnext"
|
||||
docs_base_url = "https://frappe.github.io/erpnext"
|
||||
headline = "ERPNext Documentation"
|
||||
sub_heading = "Detailed explanation for all ERPNext features and developer API"
|
||||
long_description = """ERPNext is a fully featured ERP system designed for Small and Medium Sized
|
||||
business. ERPNext covers a wide range of features including Accounting, CRM,
|
||||
Inventory management, Selling, Purchasing, Manufacturing, Projects, HR &
|
||||
Payroll, Website, E-Commerce and much more.
|
||||
|
||||
ERPNext is based on the Frappe Framework is highly customizable and extendable.
|
||||
You can create Custom Form, Fields, Scripts and can also create your own Apps
|
||||
to extend ERPNext functionality.
|
||||
|
||||
ERPNext is Open Source under the GNU General Public Licence v3 and has been
|
||||
listed as one of the Best Open Source Softwares in the world by many online
|
||||
blogs."""
|
||||
|
||||
splash_light_background = True
|
||||
google_analytics_id = 'UA-8911157-22'
|
||||
|
||||
def get_context(context):
|
||||
context.brand_html = ('<img class="brand-logo" src="'+context.docs_base_url
|
||||
+'/assets/img/erpnext-docs.png"> ERPNext</img>')
|
||||
context.app.splash_light_background = True
|
||||
context.top_bar_items = [
|
||||
{"label": "User Manual", "url": context.docs_base_url + "/user/manual", "right": 1},
|
||||
{"label": "Videos", "url": context.docs_base_url + "/user/videos", "right": 1},
|
||||
{"label": "API", "url": context.docs_base_url + "/current", "right": 1},
|
||||
{"label": "Forum", "url": 'https://discuss.erpnext.com', "right": 1}
|
||||
]
|
||||
source_link = "https://github.com/frappe/erpnext"
|
||||
@@ -17,6 +17,11 @@ def get_data():
|
||||
"name": "Task",
|
||||
"description": _("Project activity / task."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Project Type",
|
||||
"description": _("Define Project type."),
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"route": "List/Task/Gantt",
|
||||
|
||||
@@ -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"):
|
||||
|
||||
@@ -169,7 +169,6 @@ def create_variant(item, args):
|
||||
|
||||
return variant
|
||||
|
||||
|
||||
def copy_attributes_to_variant(item, variant):
|
||||
from frappe.model import no_value_fields
|
||||
|
||||
@@ -189,6 +188,8 @@ def copy_attributes_to_variant(item, variant):
|
||||
variant.set(field.fieldname, item.get(field.fieldname))
|
||||
variant.variant_of = item.name
|
||||
variant.has_variants = 0
|
||||
if not variant.description:
|
||||
variant.description = ''
|
||||
|
||||
if item.variant_based_on=='Item Attribute':
|
||||
if variant.attributes:
|
||||
|
||||
@@ -60,6 +60,7 @@ def lead_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
|
||||
# searches for customer
|
||||
def customer_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
conditions = []
|
||||
cust_master_name = frappe.defaults.get_user_default("cust_master_name")
|
||||
|
||||
if cust_master_name == "Customer Name":
|
||||
@@ -79,7 +80,7 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
return frappe.db.sql("""select {fields} from `tabCustomer`
|
||||
where docstatus < 2
|
||||
and ({scond}) and disabled=0
|
||||
{mcond}
|
||||
{fcond} {mcond}
|
||||
order by
|
||||
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
|
||||
if(locate(%(_txt)s, customer_name), locate(%(_txt)s, customer_name), 99999),
|
||||
@@ -88,7 +89,8 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
limit %(start)s, %(page_len)s""".format(**{
|
||||
"fields": fields,
|
||||
"scond": searchfields,
|
||||
"mcond": get_match_cond(doctype)
|
||||
"mcond": get_match_cond(doctype),
|
||||
"fcond": get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
|
||||
}), {
|
||||
'txt': "%%%s%%" % txt,
|
||||
'_txt': txt.replace("%", ""),
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
||||
import json
|
||||
import frappe, erpnext
|
||||
from frappe import _, scrub
|
||||
from frappe.utils import cint, flt, cstr, fmt_money, round_based_on_smallest_currency_fraction
|
||||
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
|
||||
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
|
||||
validate_taxes_and_charges, validate_inclusive_tax
|
||||
|
||||
@@ -179,7 +179,6 @@ class calculate_taxes_and_totals(object):
|
||||
|
||||
for n, item in enumerate(self.doc.get("items")):
|
||||
item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
|
||||
|
||||
for i, tax in enumerate(self.doc.get("taxes")):
|
||||
# tax_amount represents the amount of tax for the current step
|
||||
current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map)
|
||||
@@ -202,36 +201,45 @@ class calculate_taxes_and_totals(object):
|
||||
# set tax after discount
|
||||
tax.tax_amount_after_discount_amount += current_tax_amount
|
||||
|
||||
if getattr(tax, "category", None):
|
||||
# if just for valuation, do not add the tax amount in total
|
||||
# hence, setting it as 0 for further steps
|
||||
current_tax_amount = 0.0 if (tax.category == "Valuation") \
|
||||
else current_tax_amount
|
||||
current_tax_amount = self.get_tax_amount_if_for_valuation_or_deduction(current_tax_amount, tax)
|
||||
|
||||
current_tax_amount *= -1.0 if (tax.add_deduct_tax == "Deduct") else 1.0
|
||||
|
||||
# Calculate tax.total viz. grand total till that step
|
||||
# note: grand_total_for_current_item contains the contribution of
|
||||
# item's amount, previously applied tax and the current tax on that item
|
||||
if i==0:
|
||||
tax.grand_total_for_current_item = flt(item.net_amount + current_tax_amount, tax.precision("total"))
|
||||
tax.grand_total_for_current_item = flt(item.net_amount + current_tax_amount)
|
||||
else:
|
||||
tax.grand_total_for_current_item = \
|
||||
flt(self.doc.get("taxes")[i-1].grand_total_for_current_item + current_tax_amount, tax.precision("total"))
|
||||
|
||||
# in tax.total, accumulate grand total of each item
|
||||
tax.total += tax.grand_total_for_current_item
|
||||
flt(self.doc.get("taxes")[i-1].grand_total_for_current_item + current_tax_amount)
|
||||
|
||||
# set precision in the last item iteration
|
||||
if n == len(self.doc.get("items")) - 1:
|
||||
self.round_off_totals(tax)
|
||||
self.set_cumulative_total(i, tax)
|
||||
|
||||
self._set_in_company_currency(tax,
|
||||
["total", "tax_amount", "tax_amount_after_discount_amount"])
|
||||
|
||||
# adjust Discount Amount loss in last tax iteration
|
||||
if i == (len(self.doc.get("taxes")) - 1) and self.discount_amount_applied \
|
||||
and self.doc.discount_amount and self.doc.apply_discount_on == "Grand Total":
|
||||
self.adjust_discount_amount_loss(tax)
|
||||
|
||||
def get_tax_amount_if_for_valuation_or_deduction(self, tax_amount, tax):
|
||||
# if just for valuation, do not add the tax amount in total
|
||||
# if tax/charges is for deduction, multiply by -1
|
||||
if getattr(tax, "category", None):
|
||||
tax_amount = 0.0 if (tax.category == "Valuation") else tax_amount
|
||||
tax_amount *= -1.0 if (tax.add_deduct_tax == "Deduct") else 1.0
|
||||
return tax_amount
|
||||
|
||||
def set_cumulative_total(self, row_idx, tax):
|
||||
tax_amount = tax.tax_amount_after_discount_amount
|
||||
tax_amount = self.get_tax_amount_if_for_valuation_or_deduction(tax_amount, tax)
|
||||
|
||||
if row_idx == 0:
|
||||
tax.total = flt(self.doc.net_total + tax_amount, tax.precision("total"))
|
||||
else:
|
||||
tax.total = flt(self.doc.get("taxes")[row_idx-1].total + tax_amount, tax.precision("total"))
|
||||
|
||||
def get_current_tax_amount(self, item, tax, item_tax_map):
|
||||
tax_rate = self._get_tax_rate(tax, item_tax_map)
|
||||
@@ -251,8 +259,6 @@ class calculate_taxes_and_totals(object):
|
||||
current_tax_amount = (tax_rate / 100.0) * \
|
||||
self.doc.get("taxes")[cint(tax.row_id) - 1].grand_total_for_current_item
|
||||
|
||||
current_tax_amount = flt(current_tax_amount, tax.precision("tax_amount"))
|
||||
|
||||
self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount)
|
||||
|
||||
return current_tax_amount
|
||||
@@ -267,11 +273,9 @@ class calculate_taxes_and_totals(object):
|
||||
tax.item_wise_tax_detail[key] = [tax_rate,flt(item_wise_tax_amount, tax.precision("base_tax_amount"))]
|
||||
|
||||
def round_off_totals(self, tax):
|
||||
tax.total = flt(tax.total, tax.precision("total"))
|
||||
tax.tax_amount = flt(tax.tax_amount, tax.precision("tax_amount"))
|
||||
tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount, tax.precision("tax_amount"))
|
||||
|
||||
self._set_in_company_currency(tax, ["total", "tax_amount", "tax_amount_after_discount_amount"])
|
||||
tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount,
|
||||
tax.precision("tax_amount"))
|
||||
|
||||
def adjust_discount_amount_loss(self, tax):
|
||||
discount_amount_loss = self.doc.grand_total - flt(self.doc.discount_amount) - tax.total
|
||||
@@ -509,103 +513,75 @@ class calculate_taxes_and_totals(object):
|
||||
return rate_with_margin
|
||||
|
||||
def set_item_wise_tax_breakup(self):
|
||||
item_tax = {}
|
||||
tax_accounts = []
|
||||
company_currency = erpnext.get_company_currency(self.doc.company)
|
||||
self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
|
||||
|
||||
item_tax, tax_accounts = self.get_item_tax(item_tax, tax_accounts, company_currency)
|
||||
|
||||
headings = get_table_column_headings(tax_accounts)
|
||||
|
||||
distinct_items = self.get_distinct_items()
|
||||
|
||||
rows = get_table_rows(distinct_items, item_tax, tax_accounts, company_currency)
|
||||
|
||||
if not rows:
|
||||
self.doc.other_charges_calculation = ""
|
||||
else:
|
||||
self.doc.other_charges_calculation = '''
|
||||
<div class="tax-break-up" style="overflow-x: auto;">
|
||||
<table class="table table-bordered table-hover">
|
||||
<thead><tr>{headings}</tr></thead>
|
||||
<tbody>{rows}</tbody>
|
||||
</table>
|
||||
</div>'''.format(**{
|
||||
"headings": "".join(headings),
|
||||
"rows": "".join(rows)
|
||||
})
|
||||
|
||||
def get_item_tax(self, item_tax, tax_accounts, company_currency):
|
||||
for tax in self.doc.taxes:
|
||||
tax_amount_precision = tax.precision("tax_amount")
|
||||
tax_rate_precision = tax.precision("rate");
|
||||
|
||||
item_tax_map = self._load_item_tax_rate(tax.item_wise_tax_detail)
|
||||
for item_code, tax_data in item_tax_map.items():
|
||||
if not item_tax.get(item_code):
|
||||
item_tax[item_code] = {}
|
||||
|
||||
if isinstance(tax_data, list):
|
||||
tax_rate = ""
|
||||
if tax_data[0]:
|
||||
if tax.charge_type == "Actual":
|
||||
tax_rate = fmt_money(flt(tax_data[0], tax_amount_precision),
|
||||
tax_amount_precision, company_currency)
|
||||
else:
|
||||
tax_rate = cstr(flt(tax_data[0], tax_rate_precision)) + "%"
|
||||
|
||||
tax_amount = fmt_money(flt(tax_data[1], tax_amount_precision),
|
||||
tax_amount_precision, company_currency)
|
||||
|
||||
item_tax[item_code][tax.name] = [tax_rate, tax_amount]
|
||||
else:
|
||||
item_tax[item_code][tax.name] = [cstr(flt(tax_data, tax_rate_precision)) + "%", ""]
|
||||
tax_accounts.append([tax.name, tax.account_head])
|
||||
|
||||
return item_tax, tax_accounts
|
||||
|
||||
def get_itemised_tax_breakup_html(doc):
|
||||
if not doc.taxes:
|
||||
return
|
||||
frappe.flags.company = doc.company
|
||||
|
||||
def get_distinct_items(self):
|
||||
distinct_item_names = []
|
||||
distinct_items = []
|
||||
for item in self.doc.items:
|
||||
item_code = item.item_code or item.item_name
|
||||
if item_code not in distinct_item_names:
|
||||
distinct_item_names.append(item_code)
|
||||
distinct_items.append(item)
|
||||
|
||||
return distinct_items
|
||||
# get headers
|
||||
tax_accounts = list(set([d.description for d in doc.taxes]))
|
||||
headers = get_itemised_tax_breakup_header(doc.doctype + " Item", tax_accounts)
|
||||
|
||||
# get tax breakup data
|
||||
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(doc)
|
||||
|
||||
frappe.flags.company = None
|
||||
|
||||
return 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(doc.company)
|
||||
)
|
||||
)
|
||||
|
||||
def get_table_column_headings(tax_accounts):
|
||||
headings_name = [_("Item Name"), _("Taxable Amount")] + [d[1] for d in tax_accounts]
|
||||
headings = []
|
||||
for head in headings_name:
|
||||
if head == _("Item Name"):
|
||||
headings.append('<th style="min-width: 120px;" class="text-left">' + (head or "") + "</th>")
|
||||
else:
|
||||
headings.append('<th style="min-width: 80px;" class="text-right">' + (head or "") + "</th>")
|
||||
@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())
|
||||
|
||||
return headings
|
||||
|
||||
def get_table_rows(distinct_items, item_tax, tax_accounts, company_currency):
|
||||
rows = []
|
||||
for item in distinct_items:
|
||||
item_tax_record = item_tax.get(item.item_code or item.item_name)
|
||||
if not item_tax_record:
|
||||
continue
|
||||
|
||||
taxes = []
|
||||
for head in tax_accounts:
|
||||
if item_tax_record[head[0]]:
|
||||
taxes.append("<td class='text-right'>(" + item_tax_record[head[0]][0] + ") "
|
||||
+ item_tax_record[head[0]][1] + "</td>")
|
||||
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:
|
||||
taxes.append("<td></td>")
|
||||
|
||||
rows.append("<tr><td>{item_name}</td><td class='text-right'>{taxable_amount}</td>{taxes}</tr>".format(**{
|
||||
"item_name": item.item_name,
|
||||
"taxable_amount": fmt_money(item.net_amount, item.precision("net_amount"), company_currency),
|
||||
"taxes": "".join(taxes)
|
||||
}))
|
||||
|
||||
return rows
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user