Compare commits
584 Commits
fix-get_si
...
v12.6.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84a5e34319 | ||
|
|
d1bbda6d71 | ||
|
|
c2f6782658 | ||
|
|
7c0398c8e3 | ||
|
|
bf0f9c5cb4 | ||
|
|
3f1682a4f3 | ||
|
|
82661aa042 | ||
|
|
1d94f6c848 | ||
|
|
d21a9fa917 | ||
|
|
e655648b18 | ||
|
|
a5b836d3d4 | ||
|
|
8a7ecebc03 | ||
|
|
7cf245895e | ||
|
|
738517c6e8 | ||
|
|
a6cd666b10 | ||
|
|
bc8a881e64 | ||
|
|
224059e7ba | ||
|
|
6f454dce20 | ||
|
|
7f58f6af39 | ||
|
|
3ddcc2e5c7 | ||
|
|
756f47af04 | ||
|
|
b9e1d9ad7d | ||
|
|
169ba6f9b2 | ||
|
|
7c0e89d785 | ||
|
|
dd8059a3aa | ||
|
|
0dcd5a0f34 | ||
|
|
d2a2837034 | ||
|
|
281a9fdf07 | ||
|
|
e7a6a4b009 | ||
|
|
5c760175d1 | ||
|
|
11fb93d022 | ||
|
|
43a0011987 | ||
|
|
37886a72ef | ||
|
|
98573fb868 | ||
|
|
4d954f1a5f | ||
|
|
46053f6c8f | ||
|
|
6f3941c9cc | ||
|
|
cd71114c15 | ||
|
|
e2a31f221a | ||
|
|
97dfe2ac32 | ||
|
|
ee003495f6 | ||
|
|
08f0e9d6f3 | ||
|
|
4d6fb59bfb | ||
|
|
0317576434 | ||
|
|
b607963fba | ||
|
|
d08cff9efc | ||
|
|
2f2cef6c5f | ||
|
|
875e0f5fb2 | ||
|
|
6c4cddccf6 | ||
|
|
69d3c4ff25 | ||
|
|
1f80c8dffe | ||
|
|
12cdf0fb52 | ||
|
|
b6a3a06c4b | ||
|
|
2728590471 | ||
|
|
7766530afc | ||
|
|
d7839eb8ac | ||
|
|
6a734ecd34 | ||
|
|
acd93b3bd1 | ||
|
|
94200b1179 | ||
|
|
a6bf96322b | ||
|
|
27163e60bb | ||
|
|
1041516e8e | ||
|
|
b7bbd827fd | ||
|
|
fda7cbeca4 | ||
|
|
2fc58b3327 | ||
|
|
3fcd575f53 | ||
|
|
0cee807dfb | ||
|
|
a51c56c4b3 | ||
|
|
d2f26e57d2 | ||
|
|
b7790c0394 | ||
|
|
d17e0b5aca | ||
|
|
f08b5e4866 | ||
|
|
78ae5e7721 | ||
|
|
5fb66a3953 | ||
|
|
d952e71d97 | ||
|
|
fe337dfb66 | ||
|
|
45329232b3 | ||
|
|
30ad21b7d8 | ||
|
|
4e3ad9c3f2 | ||
|
|
2a1e9b542e | ||
|
|
8f458feafc | ||
|
|
e116d8f819 | ||
|
|
f3674ccc6c | ||
|
|
6f35a63f2d | ||
|
|
acbc4f648d | ||
|
|
5475b5f562 | ||
|
|
39861c270c | ||
|
|
6eaa542709 | ||
|
|
2a8981929a | ||
|
|
0aa7aa5996 | ||
|
|
a20bd89c20 | ||
|
|
aa7af30382 | ||
|
|
9921d28ea7 | ||
|
|
b26fd04843 | ||
|
|
1b78d20d3c | ||
|
|
b203406d4c | ||
|
|
5a0017c61a | ||
|
|
df15c758f6 | ||
|
|
588a89f957 | ||
|
|
c74343531f | ||
|
|
a257189c77 | ||
|
|
355051bf75 | ||
|
|
ab8aa43ffb | ||
|
|
a6f56bbc3e | ||
|
|
4e2b9395b9 | ||
|
|
ae9159fbd8 | ||
|
|
8e80c17602 | ||
|
|
8903258362 | ||
|
|
1beeb28908 | ||
|
|
2d2aa7d664 | ||
|
|
cd6b60df70 | ||
|
|
b18790f5c2 | ||
|
|
f6d7090f07 | ||
|
|
017d280877 | ||
|
|
031d4092d0 | ||
|
|
0119d15adb | ||
|
|
df6cb3c43b | ||
|
|
1ed737cf64 | ||
|
|
c64e46fe67 | ||
|
|
f579b0e3de | ||
|
|
b63c041aa4 | ||
|
|
22f9a5f09f | ||
|
|
e47875340e | ||
|
|
6f28383531 | ||
|
|
95050702f1 | ||
|
|
ae8f717fe5 | ||
|
|
f95ac99baa | ||
|
|
660b4d1e2f | ||
|
|
5bfebaf1c0 | ||
|
|
980e54c5f4 | ||
|
|
efbfeb2d89 | ||
|
|
0676ed08b1 | ||
|
|
e9946672e0 | ||
|
|
6124f83e6e | ||
|
|
2b83debc72 | ||
|
|
fc4cc9ab42 | ||
|
|
cd19974d7a | ||
|
|
cde48a44cf | ||
|
|
57d33f9ce6 | ||
|
|
90a46acc0d | ||
|
|
60634cc829 | ||
|
|
a7c27596bb | ||
|
|
b4e3146665 | ||
|
|
495ab6c7f2 | ||
|
|
0e396a62b1 | ||
|
|
1343a4b755 | ||
|
|
ec45c096a0 | ||
|
|
c7e523cee4 | ||
|
|
9e436336e2 | ||
|
|
a9205adfbd | ||
|
|
f5bff5f15d | ||
|
|
bbeacb9acf | ||
|
|
7027584391 | ||
|
|
372d4e2e05 | ||
|
|
bdfa2ff33a | ||
|
|
787b31674a | ||
|
|
0eb9f7408e | ||
|
|
5c96415eb5 | ||
|
|
d9f8347fc8 | ||
|
|
2a48fe6ce6 | ||
|
|
3ed574532d | ||
|
|
9f58e59a2c | ||
|
|
23c6d6cf16 | ||
|
|
8e0a9e8748 | ||
|
|
67dbeee7b2 | ||
|
|
b4a0c773ae | ||
|
|
ce598530db | ||
|
|
694f57fbb4 | ||
|
|
0f90b870fb | ||
|
|
bd5b37dbb7 | ||
|
|
7e93e87244 | ||
|
|
02f4aa6db6 | ||
|
|
ade2c36123 | ||
|
|
3ef80f2d2e | ||
|
|
85c6480b41 | ||
|
|
f3c94315c3 | ||
|
|
a4219f1cfe | ||
|
|
831a7ddd6f | ||
|
|
43886ca016 | ||
|
|
61b4244837 | ||
|
|
6871979acc | ||
|
|
bb7cf81d52 | ||
|
|
9826291c52 | ||
|
|
08661250d2 | ||
|
|
814001a90f | ||
|
|
eef73a0d92 | ||
|
|
a1e3202054 | ||
|
|
bee017e17c | ||
|
|
a054508211 | ||
|
|
feaa82a8ea | ||
|
|
a175e06149 | ||
|
|
ba4d9469ff | ||
|
|
54c6f91dde | ||
|
|
e552e958de | ||
|
|
7524ecbc59 | ||
|
|
be2ca5f8cc | ||
|
|
d4d641a07e | ||
|
|
8e5b812a97 | ||
|
|
df94f0565e | ||
|
|
637915f295 | ||
|
|
f2838c4a13 | ||
|
|
fe56c7ce39 | ||
|
|
29ecbde445 | ||
|
|
611f212aa4 | ||
|
|
6fbafa1924 | ||
|
|
875bac8bb9 | ||
|
|
b4b410f1d2 | ||
|
|
eec0ee83e2 | ||
|
|
148951e6f3 | ||
|
|
612e3b77fd | ||
|
|
a60849f6ab | ||
|
|
6f27e97980 | ||
|
|
8d9145aaac | ||
|
|
25a7330db0 | ||
|
|
92c999afcb | ||
|
|
9e3dc25b1c | ||
|
|
2a3cd7d601 | ||
|
|
3ca67ceebb | ||
|
|
245fc49089 | ||
|
|
78199dbf0a | ||
|
|
2ac33c9ce9 | ||
|
|
34cd035d8c | ||
|
|
ba4f565ca3 | ||
|
|
5860427bc5 | ||
|
|
89f42eef49 | ||
|
|
eacbfa15c0 | ||
|
|
5d45c2c184 | ||
|
|
b24b0378ea | ||
|
|
144012a5de | ||
|
|
5fb4027375 | ||
|
|
3fa65f1363 | ||
|
|
79f630661a | ||
|
|
61b9fe6a81 | ||
|
|
f38d9d8f0d | ||
|
|
3a67daa1fd | ||
|
|
813726b415 | ||
|
|
87fe2143be | ||
|
|
c759b06f16 | ||
|
|
c32249a72f | ||
|
|
7cd6022a0b | ||
|
|
67274d01e8 | ||
|
|
19d7e43b90 | ||
|
|
05f4be69f4 | ||
|
|
541881162a | ||
|
|
c8884257b9 | ||
|
|
4674fec320 | ||
|
|
c7f0ab8ed6 | ||
|
|
19c5e031a9 | ||
|
|
8b943af911 | ||
|
|
863eb86a1d | ||
|
|
e5fbebe126 | ||
|
|
45be9fe416 | ||
|
|
1596352585 | ||
|
|
4b893b1d51 | ||
|
|
d85e144944 | ||
|
|
4dfff5a271 | ||
|
|
c2b9598966 | ||
|
|
d16e7c096b | ||
|
|
d5676a87a8 | ||
|
|
73dff8993a | ||
|
|
0ef799dff8 | ||
|
|
e8476ef42a | ||
|
|
5511912251 | ||
|
|
514d3c37b9 | ||
|
|
9fef6e1b68 | ||
|
|
37c51f5913 | ||
|
|
7721954bbb | ||
|
|
7e33d875e0 | ||
|
|
0a50088a0e | ||
|
|
6ba6ba27bd | ||
|
|
611e23c149 | ||
|
|
89affd8d09 | ||
|
|
ab2e52ca07 | ||
|
|
8dfd5535f1 | ||
|
|
dc0ea3fdb0 | ||
|
|
b65b525c44 | ||
|
|
8c45ae73b3 | ||
|
|
4872417f86 | ||
|
|
fed9e2861c | ||
|
|
c50f08a23a | ||
|
|
6e115638a1 | ||
|
|
2d37bbedaa | ||
|
|
00f6f114e7 | ||
|
|
437be1162e | ||
|
|
ca4789c9f7 | ||
|
|
e3b6a14ab1 | ||
|
|
eb7893768b | ||
|
|
6e1ef4f5c2 | ||
|
|
d56bc81daf | ||
|
|
7d7027f47c | ||
|
|
a14f72590d | ||
|
|
7086ecb3b0 | ||
|
|
4b401f0573 | ||
|
|
5beee8af58 | ||
|
|
8508ace50e | ||
|
|
c52ef56875 | ||
|
|
4dfe8ab483 | ||
|
|
ea5e0a9d5b | ||
|
|
30111e6403 | ||
|
|
e5a572a4a8 | ||
|
|
83ed7df8cd | ||
|
|
97e93c6257 | ||
|
|
f7cd8c2702 | ||
|
|
f67b3f8a79 | ||
|
|
8356d214e1 | ||
|
|
64f3577148 | ||
|
|
ff3ff9a3c2 | ||
|
|
03c1396fc7 | ||
|
|
4479b93c1a | ||
|
|
da82edf711 | ||
|
|
7b8bf4f4d4 | ||
|
|
07c915d00b | ||
|
|
75b62cdd9f | ||
|
|
54f2d53522 | ||
|
|
55bdaae3ee | ||
|
|
6bbfce13fe | ||
|
|
0980ebe93e | ||
|
|
ded5a255af | ||
|
|
13c29aeec4 | ||
|
|
cf261d0788 | ||
|
|
3074679d7e | ||
|
|
a037f9d55e | ||
|
|
3530d0d7c9 | ||
|
|
3da9967fa8 | ||
|
|
f276e8d6a1 | ||
|
|
9e0d9aa947 | ||
|
|
df363d7dd6 | ||
|
|
81e2f2a45f | ||
|
|
255361ba92 | ||
|
|
67bcfde3de | ||
|
|
b6351b4ca0 | ||
|
|
c5a8d33374 | ||
|
|
f4589da806 | ||
|
|
c5cd7cd65d | ||
|
|
a5e56dfb6f | ||
|
|
adb35d8703 | ||
|
|
db4f3d98ab | ||
|
|
cd2899f429 | ||
|
|
8f6a6e8d2a | ||
|
|
fd68a682ca | ||
|
|
25fd2743a8 | ||
|
|
826989afda | ||
|
|
10622aee7f | ||
|
|
26e86e7576 | ||
|
|
efa7d5c831 | ||
|
|
55cf2477cd | ||
|
|
5c144c992e | ||
|
|
2fcc51dece | ||
|
|
e76670562c | ||
|
|
e1aa48968e | ||
|
|
2faa8f92be | ||
|
|
82c5a2bf45 | ||
|
|
ed386376dc | ||
|
|
65353e5590 | ||
|
|
aab1fb0d6a | ||
|
|
2dec923740 | ||
|
|
6ea509f7f4 | ||
|
|
dfdd684fbf | ||
|
|
b299026280 | ||
|
|
3d2e61eef3 | ||
|
|
47eda0fa6d | ||
|
|
8ec1d8d5da | ||
|
|
6adf617a72 | ||
|
|
7c7291ed4f | ||
|
|
a169292f6e | ||
|
|
5869757860 | ||
|
|
6fefdb5b18 | ||
|
|
8c08db33d7 | ||
|
|
bc15ea68b8 | ||
|
|
ee28663836 | ||
|
|
c522df8f9d | ||
|
|
d0e39e6fac | ||
|
|
4c4da06a71 | ||
|
|
827ac91e7f | ||
|
|
379b6df361 | ||
|
|
2e461551d6 | ||
|
|
2d30dc583c | ||
|
|
9de6083dbf | ||
|
|
9512e55704 | ||
|
|
9635df4f26 | ||
|
|
7bbeb31015 | ||
|
|
1f4b251f53 | ||
|
|
34dabc715b | ||
|
|
3881ce94ef | ||
|
|
065bbc9cb3 | ||
|
|
139bb92df9 | ||
|
|
15c8caac57 | ||
|
|
7b926f228f | ||
|
|
dab963aac0 | ||
|
|
170c9d0ab8 | ||
|
|
f27a6528db | ||
|
|
b139f2fc0f | ||
|
|
498ebfba9d | ||
|
|
2ebafb39ac | ||
|
|
adc1b9dc0a | ||
|
|
b7012a47a2 | ||
|
|
f1036c6985 | ||
|
|
8f6e989f57 | ||
|
|
9609cce7b7 | ||
|
|
e14961a6c6 | ||
|
|
f47afecc42 | ||
|
|
782f45ae5f | ||
|
|
f9ac8f63cf | ||
|
|
411b8e86b3 | ||
|
|
2b14669b58 | ||
|
|
14f624f587 | ||
|
|
98ddbf05b1 | ||
|
|
67d25028b2 | ||
|
|
328d5920bd | ||
|
|
81d614b6bd | ||
|
|
fdb7cec244 | ||
|
|
3aabeb88b4 | ||
|
|
b7fd9a652d | ||
|
|
63bc8f2d90 | ||
|
|
b6d7fba936 | ||
|
|
38540e85e8 | ||
|
|
b3d97a560f | ||
|
|
39436c6d38 | ||
|
|
59cecb29a0 | ||
|
|
55bf951ff5 | ||
|
|
4f543ce42a | ||
|
|
8931b3d602 | ||
|
|
b13eebe657 | ||
|
|
fcb296aafb | ||
|
|
5109b36689 | ||
|
|
2149d7ca4f | ||
|
|
220a208f4e | ||
|
|
0c8e46fdea | ||
|
|
ee4901f4a0 | ||
|
|
a0c847920f | ||
|
|
86e5ff3cf9 | ||
|
|
5dd7503516 | ||
|
|
5cc0e08a41 | ||
|
|
6b00d60b46 | ||
|
|
fecf5a9a15 | ||
|
|
5b4050a4ff | ||
|
|
4d7862ef4c | ||
|
|
6e41475612 | ||
|
|
803e0ec27c | ||
|
|
b3addff99e | ||
|
|
c6e098881f | ||
|
|
200ceb5352 | ||
|
|
8c50f5c23f | ||
|
|
6351a9395c | ||
|
|
fb2153c0eb | ||
|
|
86600ac8b9 | ||
|
|
b76a04b470 | ||
|
|
bb42fc615e | ||
|
|
80913994da | ||
|
|
92ecdbe0c8 | ||
|
|
089dcaed70 | ||
|
|
03a427a9e7 | ||
|
|
764c2c7f17 | ||
|
|
b4d9b80fed | ||
|
|
215274719e | ||
|
|
c920efc156 | ||
|
|
3b9fe1ae6f | ||
|
|
c76c5e699b | ||
|
|
ce6923ecb6 | ||
|
|
03db85f3e7 | ||
|
|
666fba94e2 | ||
|
|
48a8a40703 | ||
|
|
5646816282 | ||
|
|
f8df3c7af2 | ||
|
|
62d4dfa883 | ||
|
|
b8f9fd023b | ||
|
|
0df3c93737 | ||
|
|
e0e7dcd2f6 | ||
|
|
d5b1baed39 | ||
|
|
800545ff5b | ||
|
|
388a177f75 | ||
|
|
821166c628 | ||
|
|
2b8df06f8e | ||
|
|
4e8e466a98 | ||
|
|
31d4482336 | ||
|
|
5cd8c7c722 | ||
|
|
e14d9b5476 | ||
|
|
6a8ff1bebe | ||
|
|
a41d464198 | ||
|
|
980793bde0 | ||
|
|
b7329eac19 | ||
|
|
9ec5cb2570 | ||
|
|
44296a392d | ||
|
|
9097c7e11c | ||
|
|
0256d7549c | ||
|
|
94d8b99ef9 | ||
|
|
3fe1335f7b | ||
|
|
dc7a4ac8af | ||
|
|
c0ff769214 | ||
|
|
0a527b9f9a | ||
|
|
e03871f9de | ||
|
|
c0286780bd | ||
|
|
9cc484650b | ||
|
|
319f126258 | ||
|
|
234de12836 | ||
|
|
4c19000ed9 | ||
|
|
a1651ca5f2 | ||
|
|
4d042cd81a | ||
|
|
d72fae670a | ||
|
|
d458e25dc5 | ||
|
|
43474a3afa | ||
|
|
7daa2a2085 | ||
|
|
45075d8915 | ||
|
|
1de3040ecb | ||
|
|
af10f659d9 | ||
|
|
6f36691c64 | ||
|
|
dfe629aff7 | ||
|
|
23bf2a6647 | ||
|
|
b69cb8080c | ||
|
|
f23b5ed23b | ||
|
|
0a28387c70 | ||
|
|
caae8c57bc | ||
|
|
44ae135c36 | ||
|
|
47e786ef62 | ||
|
|
f10be395c1 | ||
|
|
ac967d09ec | ||
|
|
d1e8e8652f | ||
|
|
72649c207f | ||
|
|
d06b685fdf | ||
|
|
6411a56cdc | ||
|
|
34b3b04fb0 | ||
|
|
b1a2a16f43 | ||
|
|
f092e68a58 | ||
|
|
6d497ccb4c | ||
|
|
a7b97f7bac | ||
|
|
f40d3bd10f | ||
|
|
1e2be32860 | ||
|
|
6aec9e32d4 | ||
|
|
59cc0e5029 | ||
|
|
851f39cee1 | ||
|
|
6822a30f8c | ||
|
|
495ba1618b | ||
|
|
778d7595aa | ||
|
|
a40dbd0384 | ||
|
|
80dfb9f834 | ||
|
|
dabb303358 | ||
|
|
d16ef54665 | ||
|
|
dc248b9458 | ||
|
|
bf0f26b4a4 | ||
|
|
929fd4ce47 | ||
|
|
81c895b21e | ||
|
|
27a21f80d7 | ||
|
|
aa7085e11c | ||
|
|
6e5363ba48 | ||
|
|
53746636c3 | ||
|
|
485d48c101 | ||
|
|
0e1ef35968 | ||
|
|
35effe9be0 | ||
|
|
648d6e46f3 | ||
|
|
d6d9a3ddd7 | ||
|
|
18f05db19a | ||
|
|
586fecfe73 | ||
|
|
14018b3dea | ||
|
|
1c196f958f | ||
|
|
91f2cfb999 | ||
|
|
c0a0331570 | ||
|
|
4ceba43e43 | ||
|
|
9b64e2e24c | ||
|
|
da5e227ad6 | ||
|
|
4f95e5d092 | ||
|
|
6a8fd0102f | ||
|
|
2b172ec4b4 | ||
|
|
5d2ad7fc38 | ||
|
|
3347473aa1 | ||
|
|
7f951b5595 | ||
|
|
208c69f196 | ||
|
|
32b69bf122 | ||
|
|
b1fac1817c | ||
|
|
6516358a71 | ||
|
|
c6e2087673 | ||
|
|
d8469a7bfa | ||
|
|
cf645aceae | ||
|
|
3dd72e238f | ||
|
|
b74ce74ec9 | ||
|
|
074aaa6005 | ||
|
|
9d5f43f4f0 | ||
|
|
7522aadc6e | ||
|
|
326fdcb454 | ||
|
|
c41addec96 | ||
|
|
defed15528 | ||
|
|
cbc29989fe | ||
|
|
73089470b1 | ||
|
|
3798f8bd25 | ||
|
|
f805a76e79 |
@@ -63,6 +63,7 @@ install:
|
||||
- tar -xf /tmp/wkhtmltox.tar.xz -C /tmp
|
||||
- sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
|
||||
- sudo chmod o+x /usr/local/bin/wkhtmltopdf
|
||||
- sudo apt-get install libcups2-dev
|
||||
|
||||
- cd ~/frappe-bench
|
||||
|
||||
@@ -76,5 +77,6 @@ install:
|
||||
- bench --site test_site reinstall --yes
|
||||
|
||||
after_script:
|
||||
- pip install coverage==4.5.4
|
||||
- pip install python-coveralls
|
||||
- coveralls -b apps/erpnext -d ../../sites/.coverage
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"baseUrl": "http://test_site_ui:8000"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
context('Form', () => {
|
||||
before(() => {
|
||||
cy.login('Administrator', 'qwe');
|
||||
cy.visit('/desk');
|
||||
});
|
||||
|
||||
it('create a new opportunity', () => {
|
||||
cy.visit('/desk#Form/Opportunity/New Opportunity 1');
|
||||
cy.get('.page-title').should('contain', 'Not Saved');
|
||||
cy.fill_field('opportunity_from', 'Customer', 'Select');
|
||||
cy.fill_field('party_name', 'Test Customer', 'Link').blur();
|
||||
cy.get('.primary-action').click();
|
||||
cy.get('.page-title').should('contain', 'Open');
|
||||
cy.get('.form-inner-toolbar button:contains("Lost")').click({ force: true });
|
||||
cy.get('.modal input[data-fieldname="lost_reason"]').as('input');
|
||||
cy.get('@input').focus().type('Higher', { delay: 200 });
|
||||
cy.get('.modal .awesomplete ul')
|
||||
.should('be.visible')
|
||||
.get('li:contains("Higher Price")')
|
||||
.click({ force: true });
|
||||
cy.get('@input').focus().type('No Followup', { delay: 200 });
|
||||
cy.get('.modal .awesomplete ul')
|
||||
.should('be.visible')
|
||||
.get('li:contains("No Followup")')
|
||||
.click();
|
||||
|
||||
cy.fill_field('detailed_reason', 'Test Detailed Reason', 'Text');
|
||||
cy.get('.modal button:contains("Declare Lost")').click({ force: true });
|
||||
cy.get('.page-title').should('contain', 'Lost');
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
// module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
// }
|
||||
@@ -1,25 +0,0 @@
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
@@ -1,22 +0,0 @@
|
||||
// ***********************************************************
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// import frappe commands
|
||||
import '../../../frappe/cypress/support/index';
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands';
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
@@ -5,7 +5,7 @@ import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
from frappe.utils import getdate
|
||||
|
||||
__version__ = '12.2.0'
|
||||
__version__ = '12.6.0'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe, json
|
||||
from frappe import _
|
||||
from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate
|
||||
from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate, get_link_to_form
|
||||
from erpnext.accounts.report.general_ledger.general_ledger import execute
|
||||
from frappe.core.page.dashboard.dashboard import cache_source, get_from_date_from_timespan
|
||||
from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_period_ending
|
||||
@@ -30,8 +30,13 @@ def get(chart_name = None, chart = None, no_cache = None, from_date = None, to_d
|
||||
account = filters.get("account")
|
||||
company = filters.get("company")
|
||||
|
||||
if not account and chart:
|
||||
frappe.throw(_("Account is not set for the dashboard chart {0}").format(chart))
|
||||
if not account and chart_name:
|
||||
frappe.throw(_("Account is not set for the dashboard chart {0}")
|
||||
.format(get_link_to_form("Dashboard Chart", chart_name)))
|
||||
|
||||
if not frappe.db.exists("Account", account) and chart_name:
|
||||
frappe.throw(_("Account {0} does not exists in the dashboard chart {1}")
|
||||
.format(account, get_link_to_form("Dashboard Chart", chart_name)))
|
||||
|
||||
if not to_date:
|
||||
to_date = nowdate()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_copy": 1,
|
||||
"allow_import": 1,
|
||||
"creation": "2013-01-30 12:49:46",
|
||||
@@ -196,10 +197,13 @@
|
||||
],
|
||||
"icon": "fa fa-money",
|
||||
"idx": 1,
|
||||
"modified": "2019-10-10 19:10:02.967554",
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2020-03-18 18:35:45.618817",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account",
|
||||
"nsm_parent_field": "parent_account",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
|
||||
@@ -95,28 +95,29 @@ class Account(NestedSet):
|
||||
# ignore validation while creating new compnay or while syncing to child companies
|
||||
if frappe.local.flags.ignore_root_company_validation or self.flags.ignore_root_company_validation:
|
||||
return
|
||||
|
||||
ancestors = get_root_company(self.company)
|
||||
if ancestors:
|
||||
if frappe.get_value("Company", self.company, "allow_account_creation_against_child_company"):
|
||||
return
|
||||
|
||||
if not frappe.db.get_value("Account",
|
||||
{'account_name': self.account_name, 'company': ancestors[0]}, 'name'):
|
||||
frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
|
||||
else:
|
||||
descendants = get_descendants_of('Company', self.company)
|
||||
if not descendants: return
|
||||
|
||||
parent_acc_name_map = {}
|
||||
parent_acc_name = frappe.db.get_value('Account', self.parent_account, "account_name")
|
||||
for d in frappe.db.get_values('Account',
|
||||
{"company": ["in", descendants], "account_name": parent_acc_name},
|
||||
["company", "name"], as_dict=True):
|
||||
parent_acc_name, parent_acc_number = frappe.db.get_value('Account', self.parent_account, \
|
||||
["account_name", "account_number"])
|
||||
filters = {
|
||||
"company": ["in", descendants],
|
||||
"account_name": parent_acc_name,
|
||||
}
|
||||
if parent_acc_number:
|
||||
filters["account_number"] = parent_acc_number
|
||||
|
||||
for d in frappe.db.get_values('Account', filters=filters, fieldname=["company", "name"], as_dict=True):
|
||||
parent_acc_name_map[d["company"]] = d["name"]
|
||||
|
||||
if not parent_acc_name_map: return
|
||||
|
||||
self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name)
|
||||
|
||||
def validate_group_or_ledger(self):
|
||||
@@ -174,7 +175,6 @@ class Account(NestedSet):
|
||||
filters["account_number"] = self.account_number
|
||||
|
||||
child_account = frappe.db.get_value("Account", filters, 'name')
|
||||
|
||||
if not child_account:
|
||||
doc = frappe.copy_doc(self)
|
||||
doc.flags.ignore_root_company_validation = True
|
||||
|
||||
@@ -406,11 +406,11 @@
|
||||
"is_group": 1,
|
||||
"Bewertungskorrektur zu Forderungen aus Lieferungen und Leistungen": {
|
||||
"account_number": "9960"
|
||||
},
|
||||
"Debitoren": {
|
||||
"is_group": 1,
|
||||
"account_number": "10000"
|
||||
},
|
||||
},
|
||||
"Debitoren": {
|
||||
"is_group": 1,
|
||||
"account_number": "10000"
|
||||
},
|
||||
"Forderungen aus Lieferungen und Leistungen": {
|
||||
"account_number": "1200",
|
||||
"account_type": "Receivable"
|
||||
@@ -663,16 +663,22 @@
|
||||
"account_number": "1400"
|
||||
},
|
||||
"Abziehbare Vorsteuer 7 %": {
|
||||
"account_number": "1401"
|
||||
"account_number": "1401",
|
||||
"account_type": "Tax",
|
||||
"tax_rate": 7.0
|
||||
},
|
||||
"Abziehbare Vorsteuer aus innergem. Erwerb": {
|
||||
"account_number": "1402"
|
||||
},
|
||||
"Abziehbare Vorsteuer aus innergem. Erwerb 19%": {
|
||||
"account_number": "1404"
|
||||
"account_number": "1404",
|
||||
"account_type": "Tax",
|
||||
"tax_rate": 19.0
|
||||
},
|
||||
"Abziehbare Vorsteuer 19 %": {
|
||||
"account_number": "1406"
|
||||
"account_number": "1406",
|
||||
"account_type": "Tax",
|
||||
"tax_rate": 19.0
|
||||
},
|
||||
"Abziehbare Vorsteuer nach \u00a7 13b UStG 19 %": {
|
||||
"account_number": "1407"
|
||||
@@ -1197,15 +1203,15 @@
|
||||
"is_group": 1,
|
||||
"Bewertungskorrektur zu Verb. aus Lieferungen und Leistungen": {
|
||||
"account_number": "9964"
|
||||
},
|
||||
"Kreditoren": {
|
||||
"account_number": "70000",
|
||||
"is_group": 1,
|
||||
"Wareneingangs-Verrechnungskonto" : {
|
||||
"account_number": "70001",
|
||||
"account_type": "Stock Received But Not Billed"
|
||||
}
|
||||
},
|
||||
},
|
||||
"Kreditoren": {
|
||||
"account_number": "70000",
|
||||
"is_group": 1,
|
||||
"Wareneingangs-Verrechnungskonto" : {
|
||||
"account_number": "70001",
|
||||
"account_type": "Stock Received But Not Billed"
|
||||
}
|
||||
},
|
||||
"Verb. aus Lieferungen und Leistungen": {
|
||||
"account_number": "3300",
|
||||
"account_type": "Payable"
|
||||
@@ -1488,17 +1494,21 @@
|
||||
},
|
||||
"Umsatzsteuer 7 %": {
|
||||
"account_number": "3801",
|
||||
"account_type": "Tax"
|
||||
"account_type": "Tax",
|
||||
"tax_rate": 7.0
|
||||
},
|
||||
"Umsatzsteuer aus innergem. Erwerb": {
|
||||
"account_number": "3802"
|
||||
},
|
||||
"Umsatzsteuer aus innergem. Erwerb 19 %": {
|
||||
"account_number": "3804"
|
||||
"account_number": "3804",
|
||||
"account_type": "Tax",
|
||||
"tax_rate": 19.0
|
||||
},
|
||||
"Umsatzsteuer 19 %": {
|
||||
"account_number": "3806",
|
||||
"account_type": "Tax"
|
||||
"account_type": "Tax",
|
||||
"tax_rate": 19.0
|
||||
},
|
||||
"Umsatzsteuer aus im Inland steuerpfl. EU-Lieferungen": {
|
||||
"account_number": "3807"
|
||||
@@ -2295,49 +2305,49 @@
|
||||
},
|
||||
"6 - sonstige betriebliche Ertr\u00e4ge": {
|
||||
"root_type": "Income",
|
||||
"is_group": 1,
|
||||
"Erhaltene Boni (Gruppe)": {
|
||||
"is_group": 1,
|
||||
"Erhaltene Boni 7 % Vorsteuer": {
|
||||
"account_number": "5750"
|
||||
},
|
||||
"Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe": {
|
||||
"account_number": "5753"
|
||||
},
|
||||
"Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe 7% Vorsteuer": {
|
||||
"account_number": "5754"
|
||||
},
|
||||
"Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe 19% Vorsteuer": {
|
||||
"account_number": "5755"
|
||||
},
|
||||
"Erhaltene Boni 19 % Vorsteuer": {
|
||||
"account_number": "5760"
|
||||
},
|
||||
"Erhaltene Boni": {
|
||||
"account_number": "5769"
|
||||
}
|
||||
},
|
||||
"Erhaltene Rabatte (Gruppe)": {
|
||||
"is_group": 1,
|
||||
"Erhaltene Rabatte": {
|
||||
"account_number": "5770"
|
||||
},
|
||||
"Erhaltene Rabatte 7 % Vorsteuer": {
|
||||
"account_number": "5780"
|
||||
},
|
||||
"Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe": {
|
||||
"account_number": "5783"
|
||||
},
|
||||
"Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe 7% Vorsteuer": {
|
||||
"account_number": "5784"
|
||||
},
|
||||
"Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe 19% Vorsteuer": {
|
||||
"account_number": "5785"
|
||||
},
|
||||
"Erhaltene Rabatte 19 % Vorsteuer": {
|
||||
"account_number": "5790"
|
||||
}
|
||||
},
|
||||
"is_group": 1,
|
||||
"Erhaltene Boni (Gruppe)": {
|
||||
"is_group": 1,
|
||||
"Erhaltene Boni 7 % Vorsteuer": {
|
||||
"account_number": "5750"
|
||||
},
|
||||
"Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe": {
|
||||
"account_number": "5753"
|
||||
},
|
||||
"Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe 7% Vorsteuer": {
|
||||
"account_number": "5754"
|
||||
},
|
||||
"Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe 19% Vorsteuer": {
|
||||
"account_number": "5755"
|
||||
},
|
||||
"Erhaltene Boni 19 % Vorsteuer": {
|
||||
"account_number": "5760"
|
||||
},
|
||||
"Erhaltene Boni": {
|
||||
"account_number": "5769"
|
||||
}
|
||||
},
|
||||
"Erhaltene Rabatte (Gruppe)": {
|
||||
"is_group": 1,
|
||||
"Erhaltene Rabatte": {
|
||||
"account_number": "5770"
|
||||
},
|
||||
"Erhaltene Rabatte 7 % Vorsteuer": {
|
||||
"account_number": "5780"
|
||||
},
|
||||
"Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe": {
|
||||
"account_number": "5783"
|
||||
},
|
||||
"Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe 7% Vorsteuer": {
|
||||
"account_number": "5784"
|
||||
},
|
||||
"Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe 19% Vorsteuer": {
|
||||
"account_number": "5785"
|
||||
},
|
||||
"Erhaltene Rabatte 19 % Vorsteuer": {
|
||||
"account_number": "5790"
|
||||
}
|
||||
},
|
||||
"Andere aktivierte Eigenleistungen": {
|
||||
"account_number": "4820"
|
||||
},
|
||||
@@ -2660,8 +2670,8 @@
|
||||
},
|
||||
"7 - sonstige betriebliche Aufwendungen": {
|
||||
"root_type": "Expense",
|
||||
"is_group": 1,
|
||||
"Erl\u00f6sschm\u00e4lerungen (Gruppe)": {
|
||||
"is_group": 1,
|
||||
"Erl\u00f6sschm\u00e4lerungen (Gruppe)": {
|
||||
"is_group": 1,
|
||||
"Erl\u00f6sschm\u00e4lerungen": {
|
||||
"account_number": "4700"
|
||||
@@ -2744,7 +2754,7 @@
|
||||
"Gew\u00e4hrte Rabatte 19 % USt": {
|
||||
"account_number": "4790"
|
||||
}
|
||||
},
|
||||
},
|
||||
"Sonstige betriebliche Aufwendungen": {
|
||||
"account_number": "6300"
|
||||
},
|
||||
|
||||
@@ -172,7 +172,7 @@ def get_doctypes_with_dimensions():
|
||||
return doclist
|
||||
|
||||
def get_accounting_dimensions(as_list=True):
|
||||
accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "disabled"])
|
||||
accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "disabled", "document_type"])
|
||||
|
||||
if as_list:
|
||||
return [d.fieldname for d in accounting_dimensions]
|
||||
@@ -186,6 +186,18 @@ def get_checks_for_pl_and_bs_accounts():
|
||||
|
||||
return dimensions
|
||||
|
||||
def get_dimension_with_children(doctype, dimension):
|
||||
|
||||
if isinstance(dimension, list):
|
||||
dimension = dimension[0]
|
||||
|
||||
all_dimensions = []
|
||||
lft, rgt = frappe.db.get_value(doctype, dimension, ["lft", "rgt"])
|
||||
children = frappe.get_all(doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]})
|
||||
all_dimensions += [c.name for c in children]
|
||||
|
||||
return all_dimensions
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_dimension_filters():
|
||||
dimension_filters = frappe.db.sql("""
|
||||
|
||||
@@ -41,8 +41,8 @@ class AccountingPeriod(Document):
|
||||
|
||||
def get_doctypes_for_closing(self):
|
||||
docs_for_closing = []
|
||||
doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", "Bank Reconciliation",
|
||||
"Asset", "Purchase Order", "Sales Order", "Leave Application", "Leave Allocation", "Stock Entry"]
|
||||
doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", \
|
||||
"Bank Reconciliation", "Asset", "Stock Entry"]
|
||||
closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes]
|
||||
for closed_doctype in closed_doctypes:
|
||||
docs_for_closing.append(closed_doctype)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
frappe.ui.form.on('Accounts Settings', {
|
||||
refresh: function(frm) {
|
||||
frm.set_df_property("acc_frozen_upto", "label", "Books Closed Through");
|
||||
frm.set_df_property("frozen_accounts_modifier", "label", "Role Allowed to Close Books & Make Changes to Closed Periods");
|
||||
frm.set_df_property("credit_controller", "label", "Credit Manager");
|
||||
}
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2017-05-29 21:35:13.136357",
|
||||
@@ -82,7 +83,7 @@
|
||||
"default": "0",
|
||||
"fieldname": "is_default",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is the Default Account"
|
||||
"label": "Is Default Account"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
@@ -211,7 +212,8 @@
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"modified": "2019-10-02 01:34:12.417601",
|
||||
"links": [],
|
||||
"modified": "2020-01-29 20:42:26.458316",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Account",
|
||||
|
||||
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
|
||||
import frappe, json
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from frappe.desk.search import sanitize_searchfield
|
||||
|
||||
class BankGuarantee(Document):
|
||||
def validate(self):
|
||||
@@ -22,5 +23,8 @@ class BankGuarantee(Document):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_vouchar_detials(column_list, doctype, docname):
|
||||
column_list = json.loads(column_list)
|
||||
for col in column_list:
|
||||
sanitize_searchfield(col)
|
||||
return frappe.db.sql(''' select {columns} from `tab{doctype}` where name=%s'''
|
||||
.format(columns=", ".join(json.loads(column_list)), doctype=doctype), docname, as_dict=1)[0]
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
|
||||
frappe.ui.form.on("Bank Reconciliation", {
|
||||
setup: function(frm) {
|
||||
frm.add_fetch("bank_account", "account_currency", "account_currency");
|
||||
frm.add_fetch("account", "account_currency", "account_currency");
|
||||
},
|
||||
|
||||
onload: function(frm) {
|
||||
|
||||
let default_bank_account = frappe.defaults.get_user_default("Company")?
|
||||
locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]: "";
|
||||
frm.set_value("bank_account", default_bank_account);
|
||||
frm.set_value("account", default_bank_account);
|
||||
|
||||
frm.set_query("bank_account", function() {
|
||||
frm.set_query("account", function() {
|
||||
return {
|
||||
"filters": {
|
||||
"account_type": ["in",["Bank","Cash"]],
|
||||
|
||||
@@ -19,10 +19,9 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Select account head of the bank where cheque was deposited.",
|
||||
"fetch_from": "bank_account_no.account",
|
||||
"fetch_from": "bank_account.account",
|
||||
"fetch_if_empty": 1,
|
||||
"fieldname": "bank_account",
|
||||
"fieldname": "account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
@@ -31,7 +30,7 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Bank Account",
|
||||
"label": "Account",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Account",
|
||||
@@ -164,7 +163,6 @@
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
@@ -183,8 +181,9 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Select the Bank Account to reconcile.",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "bank_account_no",
|
||||
"fieldname": "bank_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
@@ -193,12 +192,11 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Bank Account No",
|
||||
"label": "Bank Account",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Bank Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
@@ -450,7 +448,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2019-04-09 18:41:06.110453",
|
||||
"modified": "2020-01-22 00:00:00.000000",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Reconciliation",
|
||||
@@ -483,4 +481,4 @@
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,17 +13,15 @@ form_grid_templates = {
|
||||
|
||||
class BankReconciliation(Document):
|
||||
def get_payment_entries(self):
|
||||
if not (self.bank_account and self.from_date and self.to_date):
|
||||
msgprint(_("Bank Account, From Date and To Date are Mandatory"))
|
||||
return
|
||||
if not (self.from_date and self.to_date):
|
||||
frappe.throw(_("From Date and To Date are Mandatory"))
|
||||
|
||||
if not self.account:
|
||||
frappe.throw(_("Account is mandatory to get payment entries"))
|
||||
|
||||
condition = ""
|
||||
if not self.include_reconciled_entries:
|
||||
condition = " and (clearance_date is null or clearance_date='0000-00-00')"
|
||||
|
||||
account_cond = ""
|
||||
if self.bank_account_no:
|
||||
account_cond = " and t2.bank_account_no = {0}".format(frappe.db.escape(self.bank_account_no))
|
||||
condition = "and (clearance_date IS NULL or clearance_date='0000-00-00')"
|
||||
|
||||
journal_entries = frappe.db.sql("""
|
||||
select
|
||||
@@ -34,15 +32,15 @@ class BankReconciliation(Document):
|
||||
from
|
||||
`tabJournal Entry` t1, `tabJournal Entry Account` t2
|
||||
where
|
||||
t2.parent = t1.name and t2.account = %s and t1.docstatus=1
|
||||
and t1.posting_date >= %s and t1.posting_date <= %s
|
||||
and ifnull(t1.is_opening, 'No') = 'No' {0} {1}
|
||||
t2.parent = t1.name and t2.account = %(account)s and t1.docstatus=1
|
||||
and t1.posting_date >= %(from)s and t1.posting_date <= %(to)s
|
||||
and ifnull(t1.is_opening, 'No') = 'No' {condition}
|
||||
group by t2.account, t1.name
|
||||
order by t1.posting_date ASC, t1.name DESC
|
||||
""".format(condition, account_cond), (self.bank_account, self.from_date, self.to_date), as_dict=1)
|
||||
""".format(condition=condition), {"account": self.account, "from": self.from_date, "to": self.to_date}, as_dict=1)
|
||||
|
||||
if self.bank_account_no:
|
||||
condition = " and bank_account = %(bank_account_no)s"
|
||||
if self.bank_account:
|
||||
condition += 'and bank_account = %(bank_account)s'
|
||||
|
||||
payment_entries = frappe.db.sql("""
|
||||
select
|
||||
@@ -55,12 +53,12 @@ class BankReconciliation(Document):
|
||||
from `tabPayment Entry`
|
||||
where
|
||||
(paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
|
||||
and posting_date >= %(from)s and posting_date <= %(to)s {0}
|
||||
and posting_date >= %(from)s and posting_date <= %(to)s
|
||||
{condition}
|
||||
order by
|
||||
posting_date ASC, name DESC
|
||||
""".format(condition),
|
||||
{"account":self.bank_account, "from":self.from_date,
|
||||
"to":self.to_date, "bank_account_no": self.bank_account_no}, as_dict=1)
|
||||
""".format(condition=condition), {"account": self.account, "from":self.from_date,
|
||||
"to": self.to_date, "bank_account": self.bank_account}, as_dict=1)
|
||||
|
||||
pos_entries = []
|
||||
if self.include_pos_transactions:
|
||||
@@ -72,11 +70,10 @@ class BankReconciliation(Document):
|
||||
from `tabSales Invoice Payment` sip, `tabSales Invoice` si, `tabAccount` account
|
||||
where
|
||||
sip.account=%(account)s and si.docstatus=1 and sip.parent = si.name
|
||||
and account.name = sip.account and si.posting_date >= %(from)s and si.posting_date <= %(to)s {0}
|
||||
and account.name = sip.account and si.posting_date >= %(from)s and si.posting_date <= %(to)s
|
||||
order by
|
||||
si.posting_date ASC, si.name DESC
|
||||
""".format(condition),
|
||||
{"account":self.bank_account, "from":self.from_date, "to":self.to_date}, as_dict=1)
|
||||
""", {"account":self.account, "from":self.from_date, "to":self.to_date}, as_dict=1)
|
||||
|
||||
entries = sorted(list(payment_entries)+list(journal_entries+list(pos_entries)),
|
||||
key=lambda k: k['posting_date'] or getdate(nowdate()))
|
||||
|
||||
@@ -15,8 +15,8 @@ def upload_bank_statement():
|
||||
with open(frappe.uploaded_file, "rb") as upfile:
|
||||
fcontent = upfile.read()
|
||||
else:
|
||||
from frappe.utils.file_manager import get_uploaded_content
|
||||
fname, fcontent = get_uploaded_content()
|
||||
fcontent = frappe.local.uploaded_file
|
||||
fname = frappe.local.uploaded_filename
|
||||
|
||||
if frappe.safe_encode(fname).lower().endswith("csv".encode('utf-8')):
|
||||
from frappe.utils.csvutils import read_csv_content
|
||||
|
||||
@@ -110,6 +110,15 @@
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.docstatus==1",
|
||||
"fieldname": "clearance_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Clearance Date",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
@@ -122,7 +131,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-12-06 10:57:02.635141",
|
||||
"modified": "2020-01-22 00:00:00.000000",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Transaction Payments",
|
||||
@@ -138,4 +147,4 @@
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,10 +210,10 @@ def get_requested_amount(args, budget):
|
||||
item_code = args.get('item_code')
|
||||
condition = get_other_condition(args, budget, 'Material Request')
|
||||
|
||||
data = frappe.db.sql(""" select ifnull((sum(mri.stock_qty - mri.ordered_qty) * rate), 0) as amount
|
||||
from `tabMaterial Request Item` mri, `tabMaterial Request` mr where mr.name = mri.parent and
|
||||
mri.item_code = %s and mr.docstatus = 1 and mri.stock_qty > mri.ordered_qty and {0} and
|
||||
mr.material_request_type = 'Purchase' and mr.status != 'Stopped'""".format(condition), item_code, as_list=1)
|
||||
data = frappe.db.sql(""" select ifnull((sum(child.stock_qty - child.ordered_qty) * rate), 0) as amount
|
||||
from `tabMaterial Request Item` child, `tabMaterial Request` parent where parent.name = child.parent and
|
||||
child.item_code = %s and parent.docstatus = 1 and child.stock_qty > child.ordered_qty and {0} and
|
||||
parent.material_request_type = 'Purchase' and parent.status != 'Stopped'""".format(condition), item_code, as_list=1)
|
||||
|
||||
return data[0][0] if data else 0
|
||||
|
||||
@@ -221,10 +221,10 @@ def get_ordered_amount(args, budget):
|
||||
item_code = args.get('item_code')
|
||||
condition = get_other_condition(args, budget, 'Purchase Order')
|
||||
|
||||
data = frappe.db.sql(""" select ifnull(sum(poi.amount - poi.billed_amt), 0) as amount
|
||||
from `tabPurchase Order Item` poi, `tabPurchase Order` po where
|
||||
po.name = poi.parent and poi.item_code = %s and po.docstatus = 1 and poi.amount > poi.billed_amt
|
||||
and po.status != 'Closed' and {0}""".format(condition), item_code, as_list=1)
|
||||
data = frappe.db.sql(""" select ifnull(sum(child.amount - child.billed_amt), 0) as amount
|
||||
from `tabPurchase Order Item` child, `tabPurchase Order` parent where
|
||||
parent.name = child.parent and child.item_code = %s and parent.docstatus = 1 and child.amount > child.billed_amt
|
||||
and parent.status != 'Closed' and {0}""".format(condition), item_code, as_list=1)
|
||||
|
||||
return data[0][0] if data else 0
|
||||
|
||||
@@ -233,16 +233,15 @@ def get_other_condition(args, budget, for_doc):
|
||||
budget_against_field = frappe.scrub(args.get("budget_against_field"))
|
||||
|
||||
if budget_against_field and args.get(budget_against_field):
|
||||
condition += " and %s = '%s'" %(budget_against_field, args.get(budget_against_field))
|
||||
condition += " and child.%s = '%s'" %(budget_against_field, args.get(budget_against_field))
|
||||
|
||||
if args.get('fiscal_year'):
|
||||
date_field = 'schedule_date' if for_doc == 'Material Request' else 'transaction_date'
|
||||
start_date, end_date = frappe.db.get_value('Fiscal Year', args.get('fiscal_year'),
|
||||
['year_start_date', 'year_end_date'])
|
||||
|
||||
alias = 'mr' if for_doc == 'Material Request' else 'po'
|
||||
condition += """ and %s.%s
|
||||
between '%s' and '%s' """ %(alias, date_field, start_date, end_date)
|
||||
condition += """ and parent.%s
|
||||
between '%s' and '%s' """ %(date_field, start_date, end_date)
|
||||
|
||||
return condition
|
||||
|
||||
|
||||
@@ -32,10 +32,12 @@ frappe.ui.form.on('C-Form Invoice Detail', {
|
||||
invoice_no(frm, cdt, cdn) {
|
||||
let d = frappe.get_doc(cdt, cdn);
|
||||
|
||||
frm.call('get_invoice_details', {
|
||||
invoice_no: d.invoice_no
|
||||
}).then(r => {
|
||||
frappe.model.set_value(cdt, cdn, r.message);
|
||||
});
|
||||
if (d.invoice_no) {
|
||||
frm.call('get_invoice_details', {
|
||||
invoice_no: d.invoice_no
|
||||
}).then(r => {
|
||||
frappe.model.set_value(cdt, cdn, r.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -96,7 +96,11 @@ def build_forest(data):
|
||||
if parent_account == account_name == child:
|
||||
return [parent_account]
|
||||
elif account_name == child:
|
||||
return [child] + return_parent(data, parent_account)
|
||||
parent_account_list = return_parent(data, parent_account)
|
||||
if not parent_account_list:
|
||||
frappe.throw(_("The parent account {0} does not exists")
|
||||
.format(parent_account))
|
||||
return [child] + parent_account_list
|
||||
|
||||
charts_map, paths = {}, []
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_copy": 1,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
@@ -123,10 +124,13 @@
|
||||
],
|
||||
"icon": "fa fa-money",
|
||||
"idx": 1,
|
||||
"modified": "2019-09-16 14:44:17.103548",
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2020-03-18 18:35:43.334214",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cost Center",
|
||||
"nsm_parent_field": "parent_cost_center",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
@@ -162,7 +166,6 @@
|
||||
"role": "Purchase User"
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"search_fields": "parent_cost_center, is_group",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
"in_list_view": 1,
|
||||
"label": "Invoice",
|
||||
"options": "Sales Invoice",
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "sales_invoice.customer",
|
||||
@@ -60,7 +61,7 @@
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"modified": "2019-09-26 11:05:36.016772",
|
||||
"modified": "2020-02-20 16:16:20.724620",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Discounted Invoice",
|
||||
|
||||
@@ -7,4 +7,4 @@ from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class DiscountedInvoice(Document):
|
||||
pass
|
||||
pass
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,6 @@ class GLEntry(Document):
|
||||
self.validate_and_set_fiscal_year()
|
||||
self.pl_must_have_cost_center()
|
||||
self.validate_cost_center()
|
||||
self.validate_dimensions_for_pl_and_bs()
|
||||
|
||||
if not self.flags.from_repost:
|
||||
self.check_pl_account()
|
||||
@@ -39,6 +38,7 @@ class GLEntry(Document):
|
||||
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
|
||||
if not from_repost:
|
||||
self.validate_account_details(adv_adj)
|
||||
self.validate_dimensions_for_pl_and_bs()
|
||||
check_freezing_date(self.posting_date, adv_adj)
|
||||
|
||||
validate_frozen_account(self.account, adv_adj)
|
||||
@@ -232,10 +232,13 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
|
||||
if bal < 0 and not on_cancel:
|
||||
frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal)))
|
||||
|
||||
# Update outstanding amt on against voucher
|
||||
if against_voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]:
|
||||
ref_doc = frappe.get_doc(against_voucher_type, against_voucher)
|
||||
ref_doc.db_set('outstanding_amount', bal)
|
||||
|
||||
# Didn't use db_set for optimisation purpose
|
||||
ref_doc.outstanding_amount = bal
|
||||
frappe.db.set_value(against_voucher_type, against_voucher, 'outstanding_amount', bal)
|
||||
|
||||
ref_doc.set_status(update=True)
|
||||
|
||||
def validate_frozen_account(account, adv_adj=None):
|
||||
@@ -274,6 +277,9 @@ def update_against_account(voucher_type, voucher_no):
|
||||
if d.against != new_against:
|
||||
frappe.db.set_value("GL Entry", d.name, "against", new_against)
|
||||
|
||||
def on_doctype_update():
|
||||
frappe.db.add_index("GL Entry", ["against_voucher_type", "against_voucher"])
|
||||
frappe.db.add_index("GL Entry", ["voucher_type", "voucher_no"])
|
||||
|
||||
def rename_gle_sle_docs():
|
||||
for doctype in ["GL Entry", "Stock Ledger Entry"]:
|
||||
|
||||
@@ -190,7 +190,6 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
||||
if(jvd.reference_type==="Employee Advance") {
|
||||
return {
|
||||
filters: {
|
||||
'status': ['=', 'Unpaid'],
|
||||
'docstatus': 1
|
||||
}
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,6 @@ from erpnext.controllers.accounts_controller import AccountsController
|
||||
from erpnext.accounts.utils import get_balance_on, get_account_currency
|
||||
from erpnext.accounts.party import get_party_account
|
||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
||||
from erpnext.hr.doctype.loan.loan import update_disbursement_status, update_total_amount_paid
|
||||
from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import get_party_account_based_on_invoice_discounting
|
||||
|
||||
from six import string_types, iteritems
|
||||
@@ -457,11 +456,12 @@ class JournalEntry(AccountsController):
|
||||
def set_print_format_fields(self):
|
||||
bank_amount = party_amount = total_amount = 0.0
|
||||
currency = bank_account_currency = party_account_currency = pay_to_recd_from= None
|
||||
party_type = None
|
||||
for d in self.get('accounts'):
|
||||
if d.party_type in ['Customer', 'Supplier'] and d.party:
|
||||
party_type = d.party_type
|
||||
if not pay_to_recd_from:
|
||||
pay_to_recd_from = frappe.db.get_value(d.party_type, d.party,
|
||||
"customer_name" if d.party_type=="Customer" else "supplier_name")
|
||||
pay_to_recd_from = d.party
|
||||
|
||||
if pay_to_recd_from and pay_to_recd_from == d.party:
|
||||
party_amount += (d.debit_in_account_currency or d.credit_in_account_currency)
|
||||
@@ -471,8 +471,9 @@ class JournalEntry(AccountsController):
|
||||
bank_amount += (d.debit_in_account_currency or d.credit_in_account_currency)
|
||||
bank_account_currency = d.account_currency
|
||||
|
||||
if pay_to_recd_from:
|
||||
self.pay_to_recd_from = pay_to_recd_from
|
||||
if party_type and pay_to_recd_from:
|
||||
self.pay_to_recd_from = frappe.db.get_value(party_type, pay_to_recd_from,
|
||||
"customer_name" if party_type=="Customer" else "supplier_name")
|
||||
if bank_amount:
|
||||
total_amount = bank_amount
|
||||
currency = bank_account_currency
|
||||
@@ -606,8 +607,8 @@ class JournalEntry(AccountsController):
|
||||
for d in self.accounts:
|
||||
if d.reference_type=="Loan" and flt(d.debit) > 0:
|
||||
doc = frappe.get_doc("Loan", d.reference_name)
|
||||
update_disbursement_status(doc)
|
||||
update_total_amount_paid(doc)
|
||||
doc.update_total_amount_paid()
|
||||
doc.set_status()
|
||||
|
||||
def validate_expense_claim(self):
|
||||
for d in self.accounts:
|
||||
@@ -968,7 +969,7 @@ def get_exchange_rate(posting_date, account=None, account_currency=None, company
|
||||
|
||||
# The date used to retreive the exchange rate here is the date passed
|
||||
# in as an argument to this function.
|
||||
elif (not exchange_rate or exchange_rate==1) and account_currency and posting_date:
|
||||
elif (not exchange_rate or flt(exchange_rate)==1) and account_currency and posting_date:
|
||||
exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
|
||||
else:
|
||||
exchange_rate = 1
|
||||
|
||||
@@ -90,7 +90,6 @@
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "Customer",
|
||||
"fieldname": "party_type",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
@@ -272,7 +271,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-10-02 12:23:21.693443",
|
||||
"modified": "2020-01-13 12:41:33.968025",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Journal Entry Account",
|
||||
|
||||
@@ -11,6 +11,7 @@ class ModeofPayment(Document):
|
||||
def validate(self):
|
||||
self.validate_accounts()
|
||||
self.validate_repeating_companies()
|
||||
self.validate_pos_mode_of_payment()
|
||||
|
||||
def validate_repeating_companies(self):
|
||||
"""Error when Same Company is entered multiple times in accounts"""
|
||||
@@ -27,3 +28,15 @@ class ModeofPayment(Document):
|
||||
if frappe.db.get_value("Account", entry.default_account, "company") != entry.company:
|
||||
frappe.throw(_("Account {0} does not match with Company {1} in Mode of Account: {2}")
|
||||
.format(entry.default_account, entry.company, self.name))
|
||||
|
||||
def validate_pos_mode_of_payment(self):
|
||||
if not self.enabled:
|
||||
pos_profiles = frappe.db.sql("""SELECT sip.parent FROM `tabSales Invoice Payment` sip
|
||||
WHERE sip.parenttype = 'POS Profile' and sip.mode_of_payment = %s""", (self.name))
|
||||
pos_profiles = list(map(lambda x: x[0], pos_profiles))
|
||||
|
||||
if pos_profiles:
|
||||
message = "POS Profile " + frappe.bold(", ".join(pos_profiles)) + " contains \
|
||||
Mode of Payment " + frappe.bold(str(self.name)) + ". Please remove them to disable this mode."
|
||||
frappe.throw(_(message), title="Not Allowed")
|
||||
|
||||
|
||||
@@ -652,14 +652,16 @@ frappe.ui.form.on('Payment Entry', {
|
||||
(frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student")
|
||||
) {
|
||||
if(total_positive_outstanding > total_negative_outstanding)
|
||||
frm.set_value("paid_amount",
|
||||
total_positive_outstanding - total_negative_outstanding);
|
||||
if (!frm.doc.paid_amount)
|
||||
frm.set_value("paid_amount",
|
||||
total_positive_outstanding - total_negative_outstanding);
|
||||
} else if (
|
||||
total_negative_outstanding &&
|
||||
total_positive_outstanding < total_negative_outstanding
|
||||
) {
|
||||
frm.set_value("received_amount",
|
||||
total_negative_outstanding - total_positive_outstanding);
|
||||
if (!frm.doc.received_amount)
|
||||
frm.set_value("received_amount",
|
||||
total_negative_outstanding - total_positive_outstanding);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,9 @@ class PaymentEntry(AccountsController):
|
||||
|
||||
self.bank = bank_data.bank
|
||||
self.bank_account_no = bank_data.bank_account_no
|
||||
self.set(field, bank_data.account)
|
||||
|
||||
if not self.get(field):
|
||||
self.set(field, bank_data.account)
|
||||
|
||||
def validate_allocated_amount(self):
|
||||
for d in self.get("references"):
|
||||
@@ -911,7 +913,10 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
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)
|
||||
if dt not in ("Sales Invoice", "Purchase Invoice"):
|
||||
party_account_currency = get_account_currency(party_account)
|
||||
else:
|
||||
party_account_currency = doc.get("party_account_currency") or get_account_currency(party_account)
|
||||
|
||||
# payment type
|
||||
if (dt == "Sales Order" or (dt in ("Sales Invoice", "Fees") and doc.outstanding_amount > 0)) \
|
||||
|
||||
@@ -149,6 +149,49 @@ class TestPaymentEntry(unittest.TestCase):
|
||||
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", pi.name, "outstanding_amount"))
|
||||
self.assertEqual(outstanding_amount, 0)
|
||||
|
||||
|
||||
def test_payment_against_sales_invoice_to_check_status(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.insert()
|
||||
pe.submit()
|
||||
|
||||
outstanding_amount, status = frappe.db.get_value("Sales Invoice", si.name, ["outstanding_amount", "status"])
|
||||
self.assertEqual(flt(outstanding_amount), 0)
|
||||
self.assertEqual(status, 'Paid')
|
||||
|
||||
pe.cancel()
|
||||
|
||||
outstanding_amount, status = frappe.db.get_value("Sales Invoice", si.name, ["outstanding_amount", "status"])
|
||||
self.assertEqual(flt(outstanding_amount), 100)
|
||||
self.assertEqual(status, 'Unpaid')
|
||||
|
||||
def test_payment_against_purchase_invoice_to_check_status(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.insert()
|
||||
pe.submit()
|
||||
|
||||
outstanding_amount, status = frappe.db.get_value("Purchase Invoice", pi.name, ["outstanding_amount", "status"])
|
||||
self.assertEqual(flt(outstanding_amount), 0)
|
||||
self.assertEqual(status, 'Paid')
|
||||
|
||||
pe.cancel()
|
||||
|
||||
outstanding_amount, status = frappe.db.get_value("Purchase Invoice", pi.name, ["outstanding_amount", "status"])
|
||||
self.assertEqual(flt(outstanding_amount), 250)
|
||||
self.assertEqual(status, 'Unpaid')
|
||||
|
||||
def test_payment_entry_against_ec(self):
|
||||
|
||||
payable = frappe.get_cached_value('Company', "_Test Company", 'default_payable_account')
|
||||
@@ -566,4 +609,4 @@ class TestPaymentEntry(unittest.TestCase):
|
||||
self.assertEqual(expected_party_account_balance, party_account_balance)
|
||||
|
||||
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
|
||||
accounts_settings.save()
|
||||
accounts_settings.save()
|
||||
@@ -23,6 +23,8 @@ class PaymentReconciliation(Document):
|
||||
|
||||
if self.party_type in ["Customer", "Supplier"]:
|
||||
dr_or_cr_notes = self.get_dr_or_cr_notes()
|
||||
else:
|
||||
dr_or_cr_notes = []
|
||||
|
||||
self.add_payment_entries(payment_entries + journal_entries + dr_or_cr_notes)
|
||||
|
||||
@@ -90,6 +92,7 @@ class PaymentReconciliation(Document):
|
||||
FROM `tab{doc}`, `tabGL Entry`
|
||||
WHERE
|
||||
(`tab{doc}`.name = `tabGL Entry`.against_voucher or `tab{doc}`.name = `tabGL Entry`.voucher_no)
|
||||
and `tab{doc}`.{party_type_field} = %(party)s
|
||||
and `tab{doc}`.is_return = 1 and `tab{doc}`.return_against IS NULL
|
||||
and `tabGL Entry`.against_voucher_type = %(voucher_type)s
|
||||
and `tab{doc}`.docstatus = 1 and `tabGL Entry`.party = %(party)s
|
||||
@@ -97,12 +100,17 @@ class PaymentReconciliation(Document):
|
||||
GROUP BY `tab{doc}`.name
|
||||
Having
|
||||
amount > 0
|
||||
""".format(doc=voucher_type, dr_or_cr=dr_or_cr, reconciled_dr_or_cr=reconciled_dr_or_cr), {
|
||||
'party': self.party,
|
||||
'party_type': self.party_type,
|
||||
'voucher_type': voucher_type,
|
||||
'account': self.receivable_payable_account
|
||||
}, as_dict=1)
|
||||
""".format(
|
||||
doc=voucher_type,
|
||||
dr_or_cr=dr_or_cr,
|
||||
reconciled_dr_or_cr=reconciled_dr_or_cr,
|
||||
party_type_field=frappe.scrub(self.party_type)),
|
||||
{
|
||||
'party': self.party,
|
||||
'party_type': self.party_type,
|
||||
'voucher_type': voucher_type,
|
||||
'account': self.receivable_payable_account
|
||||
}, as_dict=1)
|
||||
|
||||
def add_payment_entries(self, entries):
|
||||
self.set('payments', [])
|
||||
|
||||
@@ -2,6 +2,16 @@ cur_frm.add_fetch("payment_gateway_account", "payment_account", "payment_account
|
||||
cur_frm.add_fetch("payment_gateway_account", "payment_gateway", "payment_gateway")
|
||||
cur_frm.add_fetch("payment_gateway_account", "message", "message")
|
||||
|
||||
frappe.ui.form.on("Payment Request", {
|
||||
setup: function(frm) {
|
||||
frm.set_query("party_type", function() {
|
||||
return {
|
||||
query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
frappe.ui.form.on("Payment Request", "onload", function(frm, dt, dn){
|
||||
if (frm.doc.reference_doctype) {
|
||||
frappe.call({
|
||||
|
||||
@@ -126,12 +126,12 @@ class PaymentRequest(Document):
|
||||
|
||||
return controller.get_payment_url(**{
|
||||
"amount": flt(self.grand_total, self.precision("grand_total")),
|
||||
"title": data.company.encode("utf-8"),
|
||||
"description": self.subject.encode("utf-8"),
|
||||
"title": frappe.as_unicode(data.company),
|
||||
"description": frappe.as_unicode(self.subject),
|
||||
"reference_doctype": "Payment Request",
|
||||
"reference_docname": self.name,
|
||||
"payer_email": self.email_to or frappe.session.user,
|
||||
"payer_name": frappe.safe_encode(data.customer_name),
|
||||
"payer_name": frappe.as_unicode(data.customer_name),
|
||||
"order_id": self.name,
|
||||
"currency": self.currency
|
||||
})
|
||||
@@ -350,13 +350,13 @@ def get_amount(ref_doc):
|
||||
if dt in ["Sales Order", "Purchase Order"]:
|
||||
grand_total = flt(ref_doc.grand_total) - flt(ref_doc.advance_paid)
|
||||
|
||||
if dt in ["Sales Invoice", "Purchase Invoice"]:
|
||||
elif dt in ["Sales Invoice", "Purchase Invoice"]:
|
||||
if ref_doc.party_account_currency == ref_doc.currency:
|
||||
grand_total = flt(ref_doc.outstanding_amount)
|
||||
else:
|
||||
grand_total = flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate
|
||||
|
||||
if dt == "Fees":
|
||||
elif dt == "Fees":
|
||||
grand_total = ref_doc.outstanding_amount
|
||||
|
||||
if grand_total > 0 :
|
||||
@@ -373,6 +373,7 @@ def get_existing_payment_request_amount(ref_dt, ref_dn):
|
||||
reference_doctype = %s
|
||||
and reference_name = %s
|
||||
and docstatus = 1
|
||||
and status != 'Paid'
|
||||
""", (ref_dt, ref_dn))
|
||||
return flt(existing_payment_request_amount[0][0]) if existing_payment_request_amount else 0
|
||||
|
||||
@@ -474,4 +475,4 @@ def make_payment_order(source_name, target_doc=None):
|
||||
}
|
||||
}, target_doc, set_missing_values)
|
||||
|
||||
return doclist
|
||||
return doclist
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"autoname": "Prompt",
|
||||
"creation": "2013-05-24 12:15:51",
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"disabled",
|
||||
"section_break_2",
|
||||
@@ -50,6 +51,7 @@
|
||||
"income_account",
|
||||
"expense_account",
|
||||
"taxes_and_charges",
|
||||
"tax_category",
|
||||
"apply_discount_on",
|
||||
"accounting_dimensions_section",
|
||||
"cost_center",
|
||||
@@ -381,11 +383,17 @@
|
||||
{
|
||||
"fieldname": "dimension_col_break",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "tax_category",
|
||||
"fieldtype": "Link",
|
||||
"label": "Tax Category",
|
||||
"options": "Tax Category"
|
||||
}
|
||||
],
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"modified": "2019-05-25 22:56:30.352693",
|
||||
"modified": "2020-01-24 15:52:03.797701",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Profile",
|
||||
|
||||
@@ -389,8 +389,7 @@
|
||||
"fieldname": "rate_or_discount",
|
||||
"fieldtype": "Select",
|
||||
"label": "Rate or Discount",
|
||||
"options": "\nRate\nDiscount Percentage\nDiscount Amount",
|
||||
"reqd": 1
|
||||
"options": "\nRate\nDiscount Percentage\nDiscount Amount"
|
||||
},
|
||||
{
|
||||
"default": "Grand Total",
|
||||
@@ -439,19 +438,20 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:!doc.mixed_conditions",
|
||||
"depends_on": "eval:!doc.mixed_conditions && doc.apply_on != 'Transaction'",
|
||||
"fieldname": "same_item",
|
||||
"fieldtype": "Check",
|
||||
"label": "Same Item"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.same_item || doc.mixed_conditions",
|
||||
"depends_on": "eval:(!doc.same_item || doc.apply_on == 'Transaction') || doc.mixed_conditions",
|
||||
"fieldname": "free_item",
|
||||
"fieldtype": "Link",
|
||||
"label": "Free Item",
|
||||
"options": "Item"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "free_qty",
|
||||
"fieldtype": "Float",
|
||||
"label": "Qty"
|
||||
@@ -554,7 +554,7 @@
|
||||
],
|
||||
"icon": "fa fa-gift",
|
||||
"idx": 1,
|
||||
"modified": "2019-10-15 12:39:40.399792",
|
||||
"modified": "2019-12-18 17:29:22.957077",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Pricing Rule",
|
||||
|
||||
@@ -34,6 +34,9 @@ class PricingRule(Document):
|
||||
|
||||
def validate_duplicate_apply_on(self):
|
||||
field = apply_on_dict.get(self.apply_on)
|
||||
if not field:
|
||||
return False
|
||||
|
||||
values = [d.get(frappe.scrub(self.apply_on)) for d in self.get(field)]
|
||||
|
||||
if len(values) != len(set(values)):
|
||||
@@ -48,6 +51,9 @@ class PricingRule(Document):
|
||||
if tocheck and not self.get(tocheck):
|
||||
throw(_("{0} is required").format(self.meta.get_label(tocheck)), frappe.MandatoryError)
|
||||
|
||||
if self.price_or_product_discount == 'Price' and not self.rate_or_discount:
|
||||
throw(_("Rate or Discount is required for the price discount."), frappe.MandatoryError)
|
||||
|
||||
def validate_applicable_for_selling_or_buying(self):
|
||||
if not self.selling and not self.buying:
|
||||
throw(_("Atleast one of the Selling or Buying must be selected"))
|
||||
@@ -183,7 +189,7 @@ def get_serial_no_for_item(args):
|
||||
|
||||
def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=False):
|
||||
from erpnext.accounts.doctype.pricing_rule.utils import (get_pricing_rules,
|
||||
get_applied_pricing_rules, get_pricing_rule_items)
|
||||
get_applied_pricing_rules, get_pricing_rule_items, get_product_discount_rule)
|
||||
|
||||
if isinstance(doc, string_types):
|
||||
doc = json.loads(doc)
|
||||
@@ -242,9 +248,11 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa
|
||||
if pricing_rule.coupon_code_based==1 and args.coupon_code==None:
|
||||
return item_details
|
||||
|
||||
if (not pricing_rule.validate_applied_rule and
|
||||
pricing_rule.price_or_product_discount == "Price"):
|
||||
apply_price_discount_pricing_rule(pricing_rule, item_details, args)
|
||||
if not pricing_rule.validate_applied_rule:
|
||||
if pricing_rule.price_or_product_discount == "Price":
|
||||
apply_price_discount_rule(pricing_rule, item_details, args)
|
||||
else:
|
||||
get_product_discount_rule(pricing_rule, item_details, args, doc)
|
||||
|
||||
item_details.has_pricing_rule = 1
|
||||
|
||||
@@ -294,7 +302,7 @@ def get_pricing_rule_details(args, pricing_rule):
|
||||
'child_docname': args.get('child_docname')
|
||||
})
|
||||
|
||||
def apply_price_discount_pricing_rule(pricing_rule, item_details, args):
|
||||
def apply_price_discount_rule(pricing_rule, item_details, args):
|
||||
item_details.pricing_rule_for = pricing_rule.rate_or_discount
|
||||
|
||||
if ((pricing_rule.margin_type == 'Amount' and pricing_rule.currency == args.currency)
|
||||
@@ -414,4 +422,4 @@ def get_item_uoms(doctype, txt, searchfield, start, page_len, filters):
|
||||
|
||||
return frappe.get_all('UOM Conversion Detail',
|
||||
filters = {'parent': ('in', items), 'uom': ("like", "{0}%".format(txt))},
|
||||
fields = ["distinct uom"], as_list=1)
|
||||
fields = ["distinct uom"], as_list=1)
|
||||
|
||||
@@ -9,6 +9,8 @@ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_orde
|
||||
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
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
from erpnext.healthcare.doctype.lab_test_template.lab_test_template import make_item_price
|
||||
|
||||
class TestPricingRule(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@@ -145,6 +147,52 @@ class TestPricingRule(unittest.TestCase):
|
||||
self.assertEquals(details.get("margin_type"), "Percentage")
|
||||
self.assertEquals(details.get("margin_rate_or_amount"), 10)
|
||||
|
||||
def test_mixed_conditions_for_item_group(self):
|
||||
for item in ["Mixed Cond Item 1", "Mixed Cond Item 2"]:
|
||||
make_item(item, {"item_group": "Products"})
|
||||
make_item_price(item, "_Test Price List", 100)
|
||||
|
||||
test_record = {
|
||||
"doctype": "Pricing Rule",
|
||||
"title": "_Test Pricing Rule for Item Group",
|
||||
"apply_on": "Item Group",
|
||||
"item_groups": [
|
||||
{
|
||||
"item_group": "Products",
|
||||
},
|
||||
{
|
||||
"item_group": "Seed",
|
||||
},
|
||||
],
|
||||
"selling": 1,
|
||||
"mixed_conditions": 1,
|
||||
"currency": "USD",
|
||||
"rate_or_discount": "Discount Percentage",
|
||||
"discount_percentage": 10,
|
||||
"applicable_for": "Customer Group",
|
||||
"customer_group": "All Customer Groups",
|
||||
"company": "_Test Company"
|
||||
}
|
||||
frappe.get_doc(test_record.copy()).insert()
|
||||
|
||||
args = frappe._dict({
|
||||
"item_code": "Mixed Cond Item 1",
|
||||
"item_group": "Products",
|
||||
"company": "_Test Company",
|
||||
"price_list": "_Test Price List",
|
||||
"currency": "_Test Currency",
|
||||
"doctype": "Sales Order",
|
||||
"conversion_rate": 1,
|
||||
"price_list_currency": "_Test Currency",
|
||||
"plc_conversion_rate": 1,
|
||||
"order_type": "Sales",
|
||||
"customer": "_Test Customer",
|
||||
"customer_group": "_Test Customer Group",
|
||||
"name": None
|
||||
})
|
||||
details = get_item_details(args)
|
||||
self.assertEquals(details.get("discount_percentage"), 10)
|
||||
|
||||
def test_pricing_rule_for_variants(self):
|
||||
from erpnext.stock.get_item_details import get_item_details
|
||||
from frappe import MandatoryError
|
||||
@@ -278,6 +326,66 @@ class TestPricingRule(unittest.TestCase):
|
||||
self.assertEquals(item.discount_amount, 110)
|
||||
self.assertEquals(item.rate, 990)
|
||||
|
||||
def test_pricing_rule_for_product_discount_on_same_item(self):
|
||||
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
||||
test_record = {
|
||||
"doctype": "Pricing Rule",
|
||||
"title": "_Test Pricing Rule",
|
||||
"apply_on": "Item Code",
|
||||
"currency": "USD",
|
||||
"items": [{
|
||||
"item_code": "_Test Item",
|
||||
}],
|
||||
"selling": 1,
|
||||
"rate_or_discount": "Discount Percentage",
|
||||
"rate": 0,
|
||||
"min_qty": 0,
|
||||
"max_qty": 7,
|
||||
"discount_percentage": 17.5,
|
||||
"price_or_product_discount": "Product",
|
||||
"same_item": 1,
|
||||
"free_qty": 1,
|
||||
"company": "_Test Company"
|
||||
}
|
||||
frappe.get_doc(test_record.copy()).insert()
|
||||
|
||||
# With pricing rule
|
||||
so = make_sales_order(item_code="_Test Item", qty=1)
|
||||
so.load_from_db()
|
||||
self.assertEqual(so.items[1].is_free_item, 1)
|
||||
self.assertEqual(so.items[1].item_code, "_Test Item")
|
||||
|
||||
|
||||
def test_pricing_rule_for_product_discount_on_different_item(self):
|
||||
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
||||
test_record = {
|
||||
"doctype": "Pricing Rule",
|
||||
"title": "_Test Pricing Rule",
|
||||
"apply_on": "Item Code",
|
||||
"currency": "USD",
|
||||
"items": [{
|
||||
"item_code": "_Test Item",
|
||||
}],
|
||||
"selling": 1,
|
||||
"rate_or_discount": "Discount Percentage",
|
||||
"rate": 0,
|
||||
"min_qty": 0,
|
||||
"max_qty": 7,
|
||||
"discount_percentage": 17.5,
|
||||
"price_or_product_discount": "Product",
|
||||
"same_item": 0,
|
||||
"free_item": "_Test Item 2",
|
||||
"free_qty": 1,
|
||||
"company": "_Test Company"
|
||||
}
|
||||
frappe.get_doc(test_record.copy()).insert()
|
||||
|
||||
# With pricing rule
|
||||
so = make_sales_order(item_code="_Test Item", qty=1)
|
||||
so.load_from_db()
|
||||
self.assertEqual(so.items[1].is_free_item, 1)
|
||||
self.assertEqual(so.items[1].item_code, "_Test Item 2")
|
||||
|
||||
def make_pricing_rule(**args):
|
||||
args = frappe._dict(args)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ from __future__ import unicode_literals
|
||||
import frappe, copy, json
|
||||
from frappe import throw, _
|
||||
from six import string_types
|
||||
from frappe.utils import flt, cint, get_datetime
|
||||
from frappe.utils import flt, cint, get_datetime, get_link_to_form, today
|
||||
from erpnext.setup.doctype.item_group.item_group import get_child_item_groups
|
||||
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
|
||||
from erpnext.stock.get_item_details import get_conversion_factor
|
||||
@@ -245,7 +245,7 @@ def filter_pricing_rules(args, pricing_rules, doc=None):
|
||||
|
||||
def validate_quantity_and_amount_for_suggestion(args, qty, amount, item_code, transaction_type):
|
||||
fieldname, msg = '', ''
|
||||
type_of_transaction = 'purcahse' if transaction_type == "buying" else "sale"
|
||||
type_of_transaction = 'purchase' if transaction_type == 'buying' else 'sale'
|
||||
|
||||
for field, value in {'min_qty': qty, 'min_amt': amount}.items():
|
||||
if (args.get(field) and value < args.get(field)
|
||||
@@ -284,7 +284,7 @@ def filter_pricing_rules_for_qty_amount(qty, rate, pricing_rules, args=None):
|
||||
status = True
|
||||
|
||||
# if user has created item price against the transaction UOM
|
||||
if rule.get("uom") == args.get("uom"):
|
||||
if args and rule.get("uom") == args.get("uom"):
|
||||
conversion_factor = 1.0
|
||||
|
||||
if status and (flt(rate) >= (flt(rule.min_amt) * conversion_factor)
|
||||
@@ -408,7 +408,8 @@ def apply_pricing_rule_on_transaction(doc):
|
||||
conditions = get_other_conditions(conditions, values, doc)
|
||||
|
||||
pricing_rules = frappe.db.sql(""" Select `tabPricing Rule`.* from `tabPricing Rule`
|
||||
where {conditions} """.format(conditions = conditions), values, as_dict=1)
|
||||
where {conditions} and `tabPricing Rule`.disable = 0
|
||||
""".format(conditions = conditions), values, as_dict=1)
|
||||
|
||||
if pricing_rules:
|
||||
pricing_rules = filter_pricing_rules_for_qty_amount(doc.total_qty,
|
||||
@@ -420,39 +421,66 @@ def apply_pricing_rule_on_transaction(doc):
|
||||
doc.set('apply_discount_on', d.apply_discount_on)
|
||||
|
||||
for field in ['additional_discount_percentage', 'discount_amount']:
|
||||
if not d.get(field): continue
|
||||
|
||||
pr_field = ('discount_percentage'
|
||||
if field == 'additional_discount_percentage' else field)
|
||||
|
||||
if not d.get(pr_field): continue
|
||||
|
||||
if d.validate_applied_rule and doc.get(field) < d.get(pr_field):
|
||||
frappe.msgprint(_("User has not applied rule on the invoice {0}")
|
||||
.format(doc.name))
|
||||
else:
|
||||
doc.set(field, d.get(pr_field))
|
||||
|
||||
doc.calculate_taxes_and_totals()
|
||||
elif d.price_or_product_discount == 'Product':
|
||||
apply_pricing_rule_for_free_items(doc, d)
|
||||
item_details = frappe._dict({'parenttype': doc.doctype})
|
||||
get_product_discount_rule(d, item_details, doc=doc)
|
||||
apply_pricing_rule_for_free_items(doc, item_details.free_item_data)
|
||||
doc.set_missing_values()
|
||||
|
||||
def get_applied_pricing_rules(item_row):
|
||||
return (item_row.get("pricing_rules").split(',')
|
||||
if item_row.get("pricing_rules") else [])
|
||||
|
||||
def apply_pricing_rule_for_free_items(doc, pricing_rule):
|
||||
if pricing_rule.get('free_item'):
|
||||
def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
|
||||
free_item = pricing_rule.free_item
|
||||
if pricing_rule.same_item:
|
||||
free_item = item_details.item_code or args.item_code
|
||||
|
||||
if not free_item:
|
||||
frappe.throw(_("Free item not set in the pricing rule {0}")
|
||||
.format(get_link_to_form("Pricing Rule", pricing_rule.name)))
|
||||
|
||||
item_details.free_item_data = {
|
||||
'item_code': free_item,
|
||||
'qty': pricing_rule.free_qty or 1,
|
||||
'rate': pricing_rule.free_item_rate or 0,
|
||||
'price_list_rate': pricing_rule.free_item_rate or 0,
|
||||
'is_free_item': 1
|
||||
}
|
||||
|
||||
item_data = frappe.get_cached_value('Item', free_item, ['item_name',
|
||||
'description', 'stock_uom'], as_dict=1)
|
||||
|
||||
item_details.free_item_data.update(item_data)
|
||||
item_details.free_item_data['uom'] = pricing_rule.free_item_uom or item_data.stock_uom
|
||||
item_details.free_item_data['conversion_factor'] = get_conversion_factor(free_item,
|
||||
item_details.free_item_data['uom']).get("conversion_factor", 1)
|
||||
|
||||
if item_details.get("parenttype") == 'Purchase Order':
|
||||
item_details.free_item_data['schedule_date'] = doc.schedule_date if doc else today()
|
||||
|
||||
if item_details.get("parenttype") == 'Sales Order':
|
||||
item_details.free_item_data['delivery_date'] = doc.delivery_date if doc else today()
|
||||
|
||||
def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False):
|
||||
if pricing_rule_args.get('item_code'):
|
||||
items = [d.item_code for d in doc.items
|
||||
if d.item_code == (d.item_code
|
||||
if pricing_rule.get('same_item') else pricing_rule.get('free_item')) and d.is_free_item]
|
||||
if d.item_code == (pricing_rule_args.get("item_code")) and d.is_free_item]
|
||||
|
||||
if not items:
|
||||
doc.append('items', {
|
||||
'item_code': pricing_rule.get('free_item'),
|
||||
'qty': pricing_rule.get('free_qty'),
|
||||
'uom': pricing_rule.get('free_item_uom'),
|
||||
'rate': pricing_rule.get('free_item_rate') or 0,
|
||||
'is_free_item': 1
|
||||
})
|
||||
|
||||
doc.set_missing_values()
|
||||
doc.append('items', pricing_rule_args)
|
||||
|
||||
def get_pricing_rule_items(pr_doc):
|
||||
apply_on_data = []
|
||||
@@ -462,13 +490,13 @@ def get_pricing_rule_items(pr_doc):
|
||||
|
||||
for d in pr_doc.get(pricing_rule_apply_on):
|
||||
if apply_on == 'item_group':
|
||||
get_child_item_groups(d.get(apply_on))
|
||||
apply_on_data.extend(get_child_item_groups(d.get(apply_on)))
|
||||
else:
|
||||
apply_on_data.append(d.get(apply_on))
|
||||
|
||||
if pr_doc.apply_rule_on_other:
|
||||
apply_on = frappe.scrub(pr_doc.apply_rule_on_other)
|
||||
apply_on_data.append(pr_doc.get(apply_on))
|
||||
apply_on_data.append(pr_doc.get("other_" + apply_on))
|
||||
|
||||
return list(set(apply_on_data))
|
||||
|
||||
@@ -480,7 +508,7 @@ def validate_coupon_code(coupon_name):
|
||||
frappe.throw(_("Sorry,coupon code validity has not started"))
|
||||
elif coupon.valid_upto:
|
||||
if coupon.valid_upto < getdate(today()) :
|
||||
frappe.throw(_("Sorry,coupon code validity has expired"))
|
||||
frappe.throw(_("Sorry,coupon code validity has expired"))
|
||||
elif coupon.used>=coupon.maximum_use:
|
||||
frappe.throw(_("Sorry,coupon code are exhausted"))
|
||||
else:
|
||||
|
||||
@@ -167,8 +167,15 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
make_comment_dialog_and_block_invoice: function(){
|
||||
const me = this;
|
||||
|
||||
const title = __('Add Comment');
|
||||
const title = __('Block Invoice');
|
||||
const fields = [
|
||||
{
|
||||
fieldname: 'release_date',
|
||||
read_only: 0,
|
||||
fieldtype:'Date',
|
||||
label: __('Release Date'),
|
||||
default: me.frm.doc.release_date
|
||||
},
|
||||
{
|
||||
fieldname: 'hold_comment',
|
||||
read_only: 0,
|
||||
@@ -187,7 +194,11 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
const dialog_data = me.dialog.get_values();
|
||||
frappe.call({
|
||||
'method': 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.block_invoice',
|
||||
'args': {'name': me.frm.doc.name, 'hold_comment': dialog_data.hold_comment},
|
||||
'args': {
|
||||
'name': me.frm.doc.name,
|
||||
'hold_comment': dialog_data.hold_comment,
|
||||
'release_date': dialog_data.release_date
|
||||
},
|
||||
'callback': (r) => me.frm.reload_doc()
|
||||
});
|
||||
me.dialog.hide();
|
||||
@@ -330,23 +341,6 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
frm: cur_frm
|
||||
})
|
||||
},
|
||||
|
||||
item_code: function(frm, cdt, cdn) {
|
||||
var row = locals[cdt][cdn];
|
||||
if(row.item_code) {
|
||||
frappe.call({
|
||||
method: "erpnext.assets.doctype.asset_category.asset_category.get_asset_category_account",
|
||||
args: {
|
||||
"item": row.item_code,
|
||||
"fieldname": "fixed_asset_account",
|
||||
"company": frm.doc.company
|
||||
},
|
||||
callback: function(r, rt) {
|
||||
frappe.model.set_value(cdt, cdn, "expense_account", r.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cur_frm.script_manager.make(erpnext.accounts.PurchaseInvoice);
|
||||
@@ -399,21 +393,11 @@ cur_frm.fields_dict['items'].grid.get_field("item_code").get_query = function(do
|
||||
|
||||
cur_frm.fields_dict['credit_to'].get_query = function(doc) {
|
||||
// filter on Account
|
||||
if (doc.supplier) {
|
||||
return {
|
||||
filters: {
|
||||
'account_type': 'Payable',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
filters: {
|
||||
'report_type': 'Balance Sheet',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
return {
|
||||
filters: {
|
||||
'account_type': 'Payable',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-05-21 16:16:39",
|
||||
@@ -417,6 +418,7 @@
|
||||
"fieldname": "contact_email",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Contact Email",
|
||||
"options": "Email",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
@@ -705,7 +707,7 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"label": "Taxes and Charges Calculation",
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "HTML",
|
||||
@@ -1287,7 +1289,8 @@
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 204,
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-09-17 22:31:42.666601",
|
||||
"links": [],
|
||||
"modified": "2019-12-30 19:13:49.610538",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
||||
@@ -248,7 +248,7 @@ class PurchaseInvoice(BuyingController):
|
||||
def set_against_expense_account(self):
|
||||
against_accounts = []
|
||||
for item in self.get("items"):
|
||||
if item.expense_account not in against_accounts:
|
||||
if item.expense_account and (item.expense_account not in against_accounts):
|
||||
against_accounts.append(item.expense_account)
|
||||
|
||||
self.against_expense_account = ",".join(against_accounts)
|
||||
@@ -368,7 +368,7 @@ class PurchaseInvoice(BuyingController):
|
||||
update_outstanding_amt(self.credit_to, "Supplier", self.supplier,
|
||||
self.doctype, self.return_against if cint(self.is_return) and self.return_against else self.name)
|
||||
|
||||
if repost_future_gle and cint(self.update_stock) and self.auto_accounting_for_stock:
|
||||
if (repost_future_gle or self.flags.repost_future_gle) and cint(self.update_stock) and self.auto_accounting_for_stock:
|
||||
from erpnext.controllers.stock_controller import update_gl_entries_after
|
||||
items, warehouses = self.get_items_and_warehouses()
|
||||
update_gl_entries_after(self.posting_date, self.posting_time,
|
||||
@@ -830,7 +830,11 @@ class PurchaseInvoice(BuyingController):
|
||||
)
|
||||
|
||||
def make_gle_for_rounding_adjustment(self, gl_entries):
|
||||
if self.rounding_adjustment:
|
||||
# if rounding adjustment in small and conversion rate is also small then
|
||||
# base_rounding_adjustment may become zero due to small precision
|
||||
# eg: rounding_adjustment = 0.01 and exchange rate = 0.05 and precision of base_rounding_adjustment is 2
|
||||
# then base_rounding_adjustment becomes zero and error is thrown in GL Entry
|
||||
if self.rounding_adjustment and self.base_rounding_adjustment:
|
||||
round_off_account, round_off_cost_center = \
|
||||
get_round_off_account_and_cost_center(self.company)
|
||||
|
||||
@@ -862,6 +866,7 @@ class PurchaseInvoice(BuyingController):
|
||||
# because updating ordered qty in bin depends upon updated ordered qty in PO
|
||||
if self.update_stock == 1:
|
||||
self.update_stock_ledger()
|
||||
self.delete_auto_created_batches()
|
||||
|
||||
self.make_gl_entries_on_cancel()
|
||||
self.update_project()
|
||||
@@ -923,9 +928,10 @@ class PurchaseInvoice(BuyingController):
|
||||
def on_recurring(self, reference_doc, auto_repeat_doc):
|
||||
self.due_date = None
|
||||
|
||||
def block_invoice(self, hold_comment=None):
|
||||
def block_invoice(self, hold_comment=None, release_date=None):
|
||||
self.db_set('on_hold', 1)
|
||||
self.db_set('hold_comment', cstr(hold_comment))
|
||||
self.db_set('release_date', release_date)
|
||||
|
||||
def unblock_invoice(self):
|
||||
self.db_set('on_hold', 0)
|
||||
@@ -1009,12 +1015,15 @@ def unblock_invoice(name):
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def block_invoice(name, hold_comment):
|
||||
def block_invoice(name, release_date, hold_comment=None):
|
||||
if frappe.db.exists('Purchase Invoice', name):
|
||||
pi = frappe.get_doc('Purchase Invoice', name)
|
||||
pi.block_invoice(hold_comment)
|
||||
pi.block_invoice(hold_comment, release_date)
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_inter_company_sales_invoice(source_name, target_doc=None):
|
||||
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction
|
||||
return make_inter_company_transaction("Purchase Invoice", source_name, target_doc)
|
||||
|
||||
def on_doctype_update():
|
||||
frappe.db.add_index("Purchase Invoice", ["supplier", "is_return", "return_against"])
|
||||
@@ -0,0 +1,3 @@
|
||||
{% include "erpnext/regional/india/taxes.js" %}
|
||||
|
||||
erpnext.setup_auto_gst_taxation('Purchase Invoice');
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "hash",
|
||||
"creation": "2013-05-22 12:43:10",
|
||||
"doctype": "DocType",
|
||||
@@ -197,7 +198,6 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "UOM",
|
||||
"options": "UOM",
|
||||
"print_hide": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
@@ -507,7 +507,8 @@
|
||||
"depends_on": "enable_deferred_expense",
|
||||
"fieldname": "service_stop_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Service Stop Date"
|
||||
"label": "Service Stop Date",
|
||||
"no_copy": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
@@ -523,13 +524,15 @@
|
||||
"depends_on": "enable_deferred_expense",
|
||||
"fieldname": "service_start_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Service Start Date"
|
||||
"label": "Service Start Date",
|
||||
"no_copy": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "enable_deferred_expense",
|
||||
"fieldname": "service_end_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Service End Date"
|
||||
"label": "Service End Date",
|
||||
"no_copy": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "reference",
|
||||
@@ -766,7 +769,8 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-11-21 16:27:52.043744",
|
||||
"links": [],
|
||||
"modified": "2020-03-05 14:20:17.297284",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice Item",
|
||||
|
||||
@@ -1,300 +1,108 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:title",
|
||||
"beta": 0,
|
||||
"creation": "2013-01-10 16:34:08",
|
||||
"custom": 0,
|
||||
"description": "Standard tax template that can be applied to all Purchase Transactions. This template can contain list of tax heads and also other expense heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Consider Tax or Charge for: In this section you can specify if the tax / charge is only for valuation (not a part of total) or only for total (does not add value to the item) or for both.\n10. Add or Deduct: Whether you want to add or deduct the tax.",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"editable_grid": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2013-01-10 16:34:08",
|
||||
"description": "Standard tax template that can be applied to all Purchase Transactions. This template can contain list of tax heads and also other expense heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Consider Tax or Charge for: In this section you can specify if the tax / charge is only for valuation (not a part of total) or only for total (does not add value to the item) or for both.\n10. Add or Deduct: Whether you want to add or deduct the tax.",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"field_order": [
|
||||
"title",
|
||||
"is_default",
|
||||
"disabled",
|
||||
"column_break4",
|
||||
"company",
|
||||
"tax_category",
|
||||
"section_break6",
|
||||
"taxes"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Title",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "title",
|
||||
"oldfieldtype": "Data",
|
||||
"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
|
||||
},
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"label": "Title",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "title",
|
||||
"oldfieldtype": "Data",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "is_default",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"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
|
||||
},
|
||||
"default": "0",
|
||||
"fieldname": "is_default",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Default"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "disabled",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Disabled",
|
||||
"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
|
||||
},
|
||||
"default": "0",
|
||||
"fieldname": "disabled",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Disabled"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break4",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
"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
|
||||
},
|
||||
"fieldname": "column_break4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"remember_last_selected_value": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break6",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
"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
|
||||
},
|
||||
"fieldname": "section_break6",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "taxes",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Purchase Taxes and Charges",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "purchase_tax_details",
|
||||
"oldfieldtype": "Table",
|
||||
"options": "Purchase Taxes and Charges",
|
||||
"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
|
||||
"fieldname": "taxes",
|
||||
"fieldtype": "Table",
|
||||
"label": "Purchase Taxes and Charges",
|
||||
"oldfieldname": "purchase_tax_details",
|
||||
"oldfieldtype": "Table",
|
||||
"options": "Purchase Taxes and Charges"
|
||||
},
|
||||
{
|
||||
"fieldname": "tax_category",
|
||||
"fieldtype": "Link",
|
||||
"label": "Tax Category",
|
||||
"options": "Tax Category"
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"icon": "fa fa-money",
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-11-07 05:18:44.095798",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Taxes and Charges Template",
|
||||
"owner": "wasim@webnotestech.com",
|
||||
],
|
||||
"icon": "fa fa-money",
|
||||
"idx": 1,
|
||||
"modified": "2019-11-25 13:05:26.220275",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Taxes and Charges Template",
|
||||
"owner": "wasim@webnotestech.com",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Manager"
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Master Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Master Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Purchase User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
"read": 1,
|
||||
"role": "Purchase User"
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"sort_order": "DESC",
|
||||
"track_seen": 0
|
||||
],
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -152,8 +152,11 @@ def update_multi_mode_option(doc, pos_profile):
|
||||
|
||||
|
||||
def get_mode_of_payment(doc):
|
||||
return frappe.db.sql(""" select mpa.default_account, mpa.parent, mp.type as type from `tabMode of Payment Account` mpa, \
|
||||
`tabMode of Payment` mp where mpa.parent = mp.name and mpa.company = %(company)s""", {'company': doc.company}, as_dict=1)
|
||||
return frappe.db.sql("""
|
||||
select mpa.default_account, mpa.parent, mp.type as type
|
||||
from `tabMode of Payment Account` mpa,`tabMode of Payment` mp
|
||||
where mpa.parent = mp.name and mpa.company = %(company)s and mp.enabled = 1""",
|
||||
{'company': doc.company}, as_dict=1)
|
||||
|
||||
|
||||
def update_tax_table(doc):
|
||||
@@ -204,7 +207,7 @@ def get_customers_list(pos_profile={}):
|
||||
if pos_profile.get('customer_groups'):
|
||||
# Get customers based on the customer groups defined in the POS profile
|
||||
for d in pos_profile.get('customer_groups'):
|
||||
customer_groups.extend([d.name for d in get_child_nodes('Customer Group', d.customer_group)])
|
||||
customer_groups.extend([d.get('name') for d in get_child_nodes('Customer Group', d.get('customer_group'))])
|
||||
cond = "customer_group in (%s)" % (', '.join(['%s'] * len(customer_groups)))
|
||||
|
||||
return frappe.db.sql(""" select name, customer_name, customer_group,
|
||||
@@ -384,7 +387,9 @@ def get_pricing_rule_data(doc):
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_invoice(doc_list={}, email_queue_list={}, customers_list={}):
|
||||
def make_invoice(pos_profile, doc_list={}, email_queue_list={}, customers_list={}):
|
||||
import json
|
||||
|
||||
if isinstance(doc_list, string_types):
|
||||
doc_list = json.loads(doc_list)
|
||||
|
||||
@@ -418,7 +423,11 @@ def make_invoice(doc_list={}, email_queue_list={}, customers_list={}):
|
||||
name_list.append(name)
|
||||
|
||||
email_queue = make_email_queue(email_queue_list)
|
||||
customers = get_customers_list()
|
||||
|
||||
if isinstance(pos_profile, string_types):
|
||||
pos_profile = json.loads(pos_profile)
|
||||
|
||||
customers = get_customers_list(pos_profile)
|
||||
return {
|
||||
'invoice': name_list,
|
||||
'email_queue': email_queue,
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
{% include "erpnext/regional/india/taxes.js" %}
|
||||
|
||||
erpnext.setup_auto_gst_taxation('Sales Invoice');
|
||||
|
||||
frappe.ui.form.on("Sales Invoice", {
|
||||
setup: function(frm) {
|
||||
frm.set_query('transporter', function() {
|
||||
@@ -34,5 +38,8 @@ frappe.ui.form.on("Sales Invoice", {
|
||||
}
|
||||
}, __("Make"));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -556,22 +556,11 @@ cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
|
||||
}
|
||||
|
||||
cur_frm.set_query("debit_to", function(doc) {
|
||||
// filter on Account
|
||||
if (doc.customer) {
|
||||
return {
|
||||
filters: {
|
||||
'account_type': 'Receivable',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
filters: {
|
||||
'report_type': 'Balance Sheet',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
return {
|
||||
filters: {
|
||||
'account_type': 'Receivable',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -697,8 +686,8 @@ frappe.ui.form.on('Sales Invoice', {
|
||||
if (frm.doc.company)
|
||||
{
|
||||
frappe.call({
|
||||
method:"frappe.contacts.doctype.address.address.get_default_address",
|
||||
args:{ doctype:'Company',name:frm.doc.company},
|
||||
method:"erpnext.setup.doctype.company.company.get_default_company_address",
|
||||
args:{name:frm.doc.company, existing_address: frm.doc.company_address},
|
||||
callback: function(r){
|
||||
if (r.message){
|
||||
frm.set_value("company_address",r.message)
|
||||
|
||||
@@ -372,7 +372,8 @@
|
||||
"no_copy": 1,
|
||||
"options": "Sales Invoice",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_21",
|
||||
@@ -774,7 +775,7 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"label": "Taxes and Charges Calculation",
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "HTML",
|
||||
@@ -1567,7 +1568,7 @@
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 181,
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-10-05 21:39:49.235990",
|
||||
"modified": "2020-02-10 04:57:11.221180",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
||||
@@ -412,6 +412,9 @@ class SalesInvoice(SellingController):
|
||||
|
||||
if pos:
|
||||
self.allow_print_before_pay = pos.allow_print_before_pay
|
||||
|
||||
if not for_validate:
|
||||
self.tax_category = pos.get("tax_category")
|
||||
|
||||
if not for_validate and not self.customer:
|
||||
self.customer = pos.customer
|
||||
@@ -714,7 +717,7 @@ class SalesInvoice(SellingController):
|
||||
update_outstanding_amt(self.debit_to, "Customer", self.customer,
|
||||
self.doctype, self.return_against if cint(self.is_return) and self.return_against else self.name)
|
||||
|
||||
if repost_future_gle and cint(self.update_stock) \
|
||||
if (repost_future_gle or self.flags.repost_future_gle) and cint(self.update_stock) \
|
||||
and cint(auto_accounting_for_stock):
|
||||
items, warehouses = self.get_items_and_warehouses()
|
||||
update_gl_entries_after(self.posting_date, self.posting_time,
|
||||
@@ -953,7 +956,7 @@ class SalesInvoice(SellingController):
|
||||
)
|
||||
|
||||
def make_gle_for_rounding_adjustment(self, gl_entries):
|
||||
if flt(self.rounding_adjustment, self.precision("rounding_adjustment")):
|
||||
if flt(self.rounding_adjustment, self.precision("rounding_adjustment")) and self.base_rounding_adjustment:
|
||||
round_off_account, round_off_cost_center = \
|
||||
get_round_off_account_and_cost_center(self.company)
|
||||
|
||||
@@ -1048,13 +1051,18 @@ class SalesInvoice(SellingController):
|
||||
continue
|
||||
|
||||
for serial_no in item.serial_no.split("\n"):
|
||||
sales_invoice, item_code = frappe.db.get_value("Serial No", serial_no,
|
||||
["sales_invoice", "item_code"])
|
||||
if sales_invoice and item_code == item.item_code and self.name != sales_invoice:
|
||||
sales_invoice_company = frappe.db.get_value("Sales Invoice", sales_invoice, "company")
|
||||
serial_no_details = frappe.db.get_value("Serial No", serial_no,
|
||||
["sales_invoice", "item_code"], as_dict=1)
|
||||
|
||||
if not serial_no_details:
|
||||
continue
|
||||
|
||||
if serial_no_details.sales_invoice and serial_no_details.item_code == item.item_code \
|
||||
and self.name != serial_no_details.sales_invoice:
|
||||
sales_invoice_company = frappe.db.get_value("Sales Invoice", serial_no_details.sales_invoice, "company")
|
||||
if sales_invoice_company == self.company:
|
||||
frappe.throw(_("Serial Number: {0} is already referenced in Sales Invoice: {1}"
|
||||
.format(serial_no, sales_invoice)))
|
||||
.format(serial_no, serial_no_details.sales_invoice)))
|
||||
|
||||
def update_project(self):
|
||||
if self.project:
|
||||
@@ -1203,48 +1211,39 @@ class SalesInvoice(SellingController):
|
||||
|
||||
self.set_missing_values(for_validate = True)
|
||||
|
||||
def get_discounting_status(self):
|
||||
status = None
|
||||
if self.is_discounted:
|
||||
invoice_discounting_list = frappe.db.sql("""
|
||||
select status
|
||||
from `tabInvoice Discounting` id, `tabDiscounted Invoice` d
|
||||
where
|
||||
id.name = d.parent
|
||||
and d.sales_invoice=%s
|
||||
and id.docstatus=1
|
||||
and status in ('Disbursed', 'Settled')
|
||||
""", self.name)
|
||||
for d in invoice_discounting_list:
|
||||
status = d[0]
|
||||
if status == "Disbursed":
|
||||
break
|
||||
return status
|
||||
|
||||
def set_status(self, update=False, status=None, update_modified=True):
|
||||
if self.is_new():
|
||||
if self.get('amended_from'):
|
||||
self.status = 'Draft'
|
||||
return
|
||||
|
||||
precision = self.precision("outstanding_amount")
|
||||
outstanding_amount = flt(self.outstanding_amount, precision)
|
||||
due_date = getdate(self.due_date)
|
||||
nowdate = getdate()
|
||||
|
||||
discounting_status = None
|
||||
if self.is_discounted:
|
||||
discountng_status = get_discounting_status(self.name)
|
||||
|
||||
if not status:
|
||||
if self.docstatus == 2:
|
||||
status = "Cancelled"
|
||||
elif self.docstatus == 1:
|
||||
if flt(self.outstanding_amount) > 0 and getdate(self.due_date) < getdate(nowdate()) and self.is_discounted and self.get_discounting_status()=='Disbursed':
|
||||
if outstanding_amount > 0 and due_date < nowdate and self.is_discounted and discountng_status=='Disbursed':
|
||||
self.status = "Overdue and Discounted"
|
||||
elif flt(self.outstanding_amount) > 0 and getdate(self.due_date) < getdate(nowdate()):
|
||||
elif outstanding_amount > 0 and due_date < nowdate:
|
||||
self.status = "Overdue"
|
||||
elif flt(self.outstanding_amount) > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.is_discounted and self.get_discounting_status()=='Disbursed':
|
||||
elif outstanding_amount > 0 and due_date >= nowdate and self.is_discounted and discountng_status=='Disbursed':
|
||||
self.status = "Unpaid and Discounted"
|
||||
elif flt(self.outstanding_amount) > 0 and getdate(self.due_date) >= getdate(nowdate()):
|
||||
elif outstanding_amount > 0 and due_date >= nowdate:
|
||||
self.status = "Unpaid"
|
||||
#Check if outstanding amount is 0 due to credit note issued against invoice
|
||||
elif flt(self.outstanding_amount) <= 0 and self.is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}):
|
||||
elif outstanding_amount <= 0 and self.is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}):
|
||||
self.status = "Credit Note Issued"
|
||||
elif self.is_return == 1:
|
||||
self.status = "Return"
|
||||
elif flt(self.outstanding_amount)<=0:
|
||||
elif outstanding_amount<=0:
|
||||
self.status = "Paid"
|
||||
else:
|
||||
self.status = "Submitted"
|
||||
@@ -1254,6 +1253,26 @@ class SalesInvoice(SellingController):
|
||||
if update:
|
||||
self.db_set('status', self.status, update_modified = update_modified)
|
||||
|
||||
def get_discounting_status(sales_invoice):
|
||||
status = None
|
||||
|
||||
invoice_discounting_list = frappe.db.sql("""
|
||||
select status
|
||||
from `tabInvoice Discounting` id, `tabDiscounted Invoice` d
|
||||
where
|
||||
id.name = d.parent
|
||||
and d.sales_invoice=%s
|
||||
and id.docstatus=1
|
||||
and status in ('Disbursed', 'Settled')
|
||||
""", sales_invoice)
|
||||
|
||||
for d in invoice_discounting_list:
|
||||
status = d[0]
|
||||
if status == "Disbursed":
|
||||
break
|
||||
|
||||
return status
|
||||
|
||||
def validate_inter_company_party(doctype, party, company, inter_company_reference):
|
||||
if not party:
|
||||
return
|
||||
@@ -1421,6 +1440,21 @@ def get_inter_company_details(doc, doctype):
|
||||
"company": company
|
||||
}
|
||||
|
||||
def get_internal_party(parties, link_doctype, doc):
|
||||
if len(parties) == 1:
|
||||
party = parties[0].name
|
||||
else:
|
||||
# If more than one Internal Supplier/Customer, get supplier/customer on basis of address
|
||||
if doc.get('company_address') or doc.get('shipping_address'):
|
||||
party = frappe.db.get_value("Dynamic Link", {"parent": doc.get('company_address') or doc.get('shipping_address'),
|
||||
"parenttype": "Address", "link_doctype": link_doctype}, "link_name")
|
||||
|
||||
if not party:
|
||||
party = parties[0].name
|
||||
else:
|
||||
party = parties[0].name
|
||||
|
||||
return party
|
||||
|
||||
def validate_inter_company_transaction(doc, doctype):
|
||||
|
||||
@@ -1509,6 +1543,9 @@ def get_loyalty_programs(customer):
|
||||
else:
|
||||
return lp_details
|
||||
|
||||
def on_doctype_update():
|
||||
frappe.db.add_index("Sales Invoice", ["customer", "is_return", "return_against"])
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_invoice_discounting(source_name, target_doc=None):
|
||||
invoice = frappe.get_doc("Sales Invoice", source_name)
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
import unittest, copy, time
|
||||
from frappe.utils import nowdate, flt, getdate, cint
|
||||
from frappe.utils import nowdate, flt, getdate, cint, add_days
|
||||
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
|
||||
@@ -728,7 +728,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
def test_make_pos_invoice(self):
|
||||
from erpnext.accounts.doctype.sales_invoice.pos import make_invoice
|
||||
|
||||
make_pos_profile()
|
||||
pos_profile = make_pos_profile()
|
||||
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
|
||||
pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
|
||||
|
||||
@@ -744,7 +744,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
pos.append("taxes", tax)
|
||||
|
||||
invoice_data = [{'09052016142': pos}]
|
||||
si = make_invoice(invoice_data).get('invoice')
|
||||
si = make_invoice(pos_profile, invoice_data).get('invoice')
|
||||
self.assertEqual(si[0], '09052016142')
|
||||
|
||||
sales_invoice = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': '09052016142', 'docstatus': 1})
|
||||
@@ -762,7 +762,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
if allow_negative_stock:
|
||||
frappe.db.set_value('Stock Settings', None, 'allow_negative_stock', 0)
|
||||
|
||||
make_pos_profile()
|
||||
pos_profile = make_pos_profile()
|
||||
timestamp = cint(time.time())
|
||||
|
||||
item = make_item("_Test POS Item")
|
||||
@@ -776,7 +776,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
{'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 330}]
|
||||
|
||||
invoice_data = [{timestamp: pos}]
|
||||
si = make_invoice(invoice_data).get('invoice')
|
||||
si = make_invoice(pos_profile, invoice_data).get('invoice')
|
||||
self.assertEqual(si[0], timestamp)
|
||||
|
||||
sales_invoice = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': timestamp})
|
||||
@@ -785,7 +785,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
timestamp = cint(time.time())
|
||||
pos["offline_pos_name"] = timestamp
|
||||
invoice_data = [{timestamp: pos}]
|
||||
si1 = make_invoice(invoice_data).get('invoice')
|
||||
si1 = make_invoice(pos_profile, invoice_data).get('invoice')
|
||||
self.assertEqual(si1[0], timestamp)
|
||||
|
||||
sales_invoice1 = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': timestamp})
|
||||
@@ -1847,6 +1847,26 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234')
|
||||
self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000)
|
||||
|
||||
def test_item_tax_validity(self):
|
||||
item = frappe.get_doc("Item", "_Test Item 2")
|
||||
|
||||
if item.taxes:
|
||||
item.taxes = []
|
||||
item.save()
|
||||
|
||||
item.append("taxes", {
|
||||
"item_tax_template": "_Test Item Tax Template 1",
|
||||
"valid_from": add_days(nowdate(), 1)
|
||||
})
|
||||
|
||||
item.save()
|
||||
|
||||
sales_invoice = create_sales_invoice(item = "_Test Item 2", do_not_save=1)
|
||||
sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1"
|
||||
self.assertRaises(frappe.ValidationError, sales_invoice.save)
|
||||
|
||||
item.taxes = []
|
||||
item.save()
|
||||
|
||||
def create_sales_invoice(**args):
|
||||
si = frappe.new_doc("Sales Invoice")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "hash",
|
||||
"creation": "2013-06-04 11:02:19",
|
||||
"doctype": "DocType",
|
||||
@@ -484,7 +485,8 @@
|
||||
"depends_on": "enable_deferred_revenue",
|
||||
"fieldname": "service_stop_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Service Stop Date"
|
||||
"label": "Service Stop Date",
|
||||
"no_copy": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
@@ -500,13 +502,15 @@
|
||||
"depends_on": "enable_deferred_revenue",
|
||||
"fieldname": "service_start_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Service Start Date"
|
||||
"label": "Service Start Date",
|
||||
"no_copy": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "enable_deferred_revenue",
|
||||
"fieldname": "service_end_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Service End Date"
|
||||
"label": "Service End Date",
|
||||
"no_copy": 1
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
@@ -783,7 +787,8 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-07-16 16:36:46.527606",
|
||||
"links": [],
|
||||
"modified": "2019-12-04 12:22:38.517710",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Item",
|
||||
|
||||
@@ -1,299 +1,119 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:title",
|
||||
"beta": 0,
|
||||
"creation": "2013-01-10 16:34:09",
|
||||
"custom": 0,
|
||||
"description": "Standard tax template that can be applied to all Sales Transactions. This template can contain list of tax heads and also other expense / income heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Is this Tax included in Basic Rate?: If you check this, it means that this tax will not be shown below the item table, but will be included in the Basic Rate in your main item table. This is useful where you want give a flat price (inclusive of all taxes) price to customers.",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"editable_grid": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2013-01-10 16:34:09",
|
||||
"description": "Standard tax template that can be applied to all Sales Transactions. This template can contain list of tax heads and also other expense / income heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Is this Tax included in Basic Rate?: If you check this, it means that this tax will not be shown below the item table, but will be included in the Basic Rate in your main item table. This is useful where you want give a flat price (inclusive of all taxes) price to customers.",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"title",
|
||||
"is_default",
|
||||
"disabled",
|
||||
"column_break_3",
|
||||
"company",
|
||||
"tax_category",
|
||||
"section_break_5",
|
||||
"taxes"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Title",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "title",
|
||||
"oldfieldtype": "Data",
|
||||
"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
|
||||
},
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"label": "Title",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "title",
|
||||
"oldfieldtype": "Data",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "is_default",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"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
|
||||
},
|
||||
"default": "0",
|
||||
"fieldname": "is_default",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Default"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "disabled",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Disabled",
|
||||
"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
|
||||
},
|
||||
"default": "0",
|
||||
"fieldname": "disabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Disabled"
|
||||
},
|
||||
{
|
||||
"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_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"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
|
||||
},
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "company",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Company",
|
||||
"oldfieldname": "company",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Company",
|
||||
"remember_last_selected_value": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"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
|
||||
},
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "* Will be calculated in the transaction.",
|
||||
"fieldname": "taxes",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Sales Taxes and Charges",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "other_charges",
|
||||
"oldfieldtype": "Table",
|
||||
"options": "Sales Taxes and Charges",
|
||||
"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
|
||||
"description": "* Will be calculated in the transaction.",
|
||||
"fieldname": "taxes",
|
||||
"fieldtype": "Table",
|
||||
"label": "Sales Taxes and Charges",
|
||||
"oldfieldname": "other_charges",
|
||||
"oldfieldtype": "Table",
|
||||
"options": "Sales Taxes and Charges"
|
||||
},
|
||||
{
|
||||
"fieldname": "tax_category",
|
||||
"fieldtype": "Link",
|
||||
"label": "Tax Category",
|
||||
"options": "Tax Category"
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"icon": "fa fa-money",
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-11-07 05:18:41.743257",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Taxes and Charges Template",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"icon": "fa fa-money",
|
||||
"idx": 1,
|
||||
"modified": "2019-11-25 13:06:03.279099",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Taxes and Charges Template",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 1,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales User"
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales Master Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales Master Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"sort_order": "ASC",
|
||||
"track_seen": 0
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -188,7 +188,7 @@
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-11-07 13:31:17.999744",
|
||||
"modified": "2019-12-20 14:48:01.990600",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Share Transfer",
|
||||
@@ -196,6 +196,7 @@
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
@@ -221,6 +222,7 @@
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
@@ -230,6 +232,7 @@
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
|
||||
@@ -70,7 +70,7 @@ class ShippingRule(Document):
|
||||
|
||||
def get_shipping_amount_from_rules(self, value):
|
||||
for condition in self.get("conditions"):
|
||||
if not condition.to_value or (flt(condition.from_value) <= value <= flt(condition.to_value)):
|
||||
if not condition.to_value or (flt(condition.from_value) <= flt(value) <= flt(condition.to_value)):
|
||||
return condition.shipping_amount
|
||||
|
||||
return 0.0
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "ACC-SUB-.YYYY.-.#####",
|
||||
"creation": "2017-07-18 17:50:43.967266",
|
||||
"doctype": "DocType",
|
||||
@@ -155,7 +156,7 @@
|
||||
"fieldname": "apply_additional_discount",
|
||||
"fieldtype": "Select",
|
||||
"label": "Apply Additional Discount On",
|
||||
"options": "\nGrand Total\nNet total"
|
||||
"options": "\nGrand Total\nNet Total"
|
||||
},
|
||||
{
|
||||
"fieldname": "cb_2",
|
||||
@@ -196,7 +197,8 @@
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"modified": "2019-07-25 18:45:38.579579",
|
||||
"links": [],
|
||||
"modified": "2020-01-27 14:37:32.845173",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Subscription",
|
||||
|
||||
@@ -280,7 +280,7 @@ class Subscription(Document):
|
||||
|
||||
if self.additional_discount_percentage or self.additional_discount_amount:
|
||||
discount_on = self.apply_additional_discount
|
||||
invoice.apply_additional_discount = discount_on if discount_on else 'Grand Total'
|
||||
invoice.apply_discount_on = discount_on if discount_on else 'Grand Total'
|
||||
|
||||
# Subscription period
|
||||
invoice.from_date = self.current_invoice_start
|
||||
@@ -338,6 +338,16 @@ class Subscription(Document):
|
||||
|
||||
# Check invoice dates and make sure it doesn't have outstanding invoices
|
||||
return getdate(nowdate()) >= getdate(self.current_invoice_start) and not self.has_outstanding_invoice()
|
||||
|
||||
def is_current_invoice_paid(self):
|
||||
if self.is_new_subscription():
|
||||
return False
|
||||
|
||||
last_invoice = frappe.get_doc('Sales Invoice', self.invoices[-1].invoice)
|
||||
if getdate(last_invoice.posting_date) == getdate(self.current_invoice_start) and last_invoice.status == 'Paid':
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def process_for_active(self):
|
||||
"""
|
||||
@@ -348,7 +358,7 @@ class Subscription(Document):
|
||||
2. Change the `Subscription` status to 'Past Due Date'
|
||||
3. Change the `Subscription` status to 'Cancelled'
|
||||
"""
|
||||
if self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice():
|
||||
if not self.is_current_invoice_paid() and (self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice()):
|
||||
self.generate_invoice()
|
||||
if self.current_invoice_is_past_due():
|
||||
self.status = 'Past Due Date'
|
||||
|
||||
@@ -1,134 +1,134 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:title",
|
||||
"beta": 0,
|
||||
"creation": "2018-11-22 23:38:39.668804",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:title",
|
||||
"beta": 0,
|
||||
"creation": "2018-11-22 23:38:39.668804",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "title",
|
||||
"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": "Title",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "title",
|
||||
"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": "Title",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 1
|
||||
}
|
||||
],
|
||||
"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": "2018-11-22 23:38:39.668804",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Tax Category",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"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": "2020-01-15 17:14:28.951793",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Tax Category",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 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,
|
||||
"amend": 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
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 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": "Accounts Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"amend": 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": "Accounts Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
}
|
||||
],
|
||||
"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,
|
||||
],
|
||||
"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,
|
||||
"track_views": 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,8 +90,12 @@ def merge_similar_entries(gl_map):
|
||||
else:
|
||||
merged_gl_map.append(entry)
|
||||
|
||||
company = gl_map[0].company if gl_map else erpnext.get_default_company()
|
||||
company_currency = erpnext.get_company_currency(company)
|
||||
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), company_currency)
|
||||
|
||||
# filter zero debit and credit entries
|
||||
merged_gl_map = filter(lambda x: flt(x.debit, 9)!=0 or flt(x.credit, 9)!=0, merged_gl_map)
|
||||
merged_gl_map = filter(lambda x: flt(x.debit, precision)!=0 or flt(x.credit, precision)!=0, merged_gl_map)
|
||||
merged_gl_map = list(merged_gl_map)
|
||||
|
||||
return merged_gl_map
|
||||
@@ -132,12 +136,14 @@ def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
|
||||
|
||||
|
||||
def make_entry(args, adv_adj, update_outstanding, from_repost=False):
|
||||
args.update({"doctype": "GL Entry"})
|
||||
gle = frappe.get_doc(args)
|
||||
gle = frappe.new_doc("GL Entry")
|
||||
gle.update(args)
|
||||
gle.flags.ignore_permissions = 1
|
||||
gle.flags.from_repost = from_repost
|
||||
gle.insert()
|
||||
gle.validate()
|
||||
gle.db_insert()
|
||||
gle.run_method("on_update_with_args", adv_adj, update_outstanding, from_repost)
|
||||
gle.flags.ignore_validate = True
|
||||
gle.submit()
|
||||
|
||||
def validate_account_for_perpetual_inventory(gl_map):
|
||||
@@ -162,33 +168,34 @@ def validate_account_for_perpetual_inventory(gl_map):
|
||||
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
|
||||
.format(account), StockAccountInvalidTransaction)
|
||||
|
||||
elif account_bal != stock_bal:
|
||||
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
|
||||
currency=frappe.get_cached_value('Company', gl_map[0].company, "default_currency"))
|
||||
# This has been comment for a temporary, will add this code again on release of immutable ledger
|
||||
# elif account_bal != stock_bal:
|
||||
# precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
|
||||
# currency=frappe.get_cached_value('Company', gl_map[0].company, "default_currency"))
|
||||
|
||||
diff = flt(stock_bal - account_bal, precision)
|
||||
error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses.").format(
|
||||
stock_bal, account_bal, frappe.bold(account))
|
||||
error_resolution = _("Please create adjustment Journal Entry for amount {0} ").format(frappe.bold(diff))
|
||||
stock_adjustment_account = frappe.db.get_value("Company",gl_map[0].company,"stock_adjustment_account")
|
||||
# diff = flt(stock_bal - account_bal, precision)
|
||||
# error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses.").format(
|
||||
# stock_bal, account_bal, frappe.bold(account))
|
||||
# error_resolution = _("Please create adjustment Journal Entry for amount {0} ").format(frappe.bold(diff))
|
||||
# stock_adjustment_account = frappe.db.get_value("Company",gl_map[0].company,"stock_adjustment_account")
|
||||
|
||||
db_or_cr_warehouse_account =('credit_in_account_currency' if diff < 0 else 'debit_in_account_currency')
|
||||
db_or_cr_stock_adjustment_account = ('debit_in_account_currency' if diff < 0 else 'credit_in_account_currency')
|
||||
# db_or_cr_warehouse_account =('credit_in_account_currency' if diff < 0 else 'debit_in_account_currency')
|
||||
# db_or_cr_stock_adjustment_account = ('debit_in_account_currency' if diff < 0 else 'credit_in_account_currency')
|
||||
|
||||
journal_entry_args = {
|
||||
'accounts':[
|
||||
{'account': account, db_or_cr_warehouse_account : abs(diff)},
|
||||
{'account': stock_adjustment_account, db_or_cr_stock_adjustment_account : abs(diff) }]
|
||||
}
|
||||
# journal_entry_args = {
|
||||
# 'accounts':[
|
||||
# {'account': account, db_or_cr_warehouse_account : abs(diff)},
|
||||
# {'account': stock_adjustment_account, db_or_cr_stock_adjustment_account : abs(diff) }]
|
||||
# }
|
||||
|
||||
frappe.msgprint(msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
|
||||
raise_exception=StockValueAndAccountBalanceOutOfSync,
|
||||
title=_('Values Out Of Sync'),
|
||||
primary_action={
|
||||
'label': _('Make Journal Entry'),
|
||||
'client_action': 'erpnext.route_to_adjustment_jv',
|
||||
'args': journal_entry_args
|
||||
})
|
||||
# frappe.msgprint(msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
|
||||
# raise_exception=StockValueAndAccountBalanceOutOfSync,
|
||||
# title=_('Values Out Of Sync'),
|
||||
# primary_action={
|
||||
# 'label': _('Make Journal Entry'),
|
||||
# 'client_action': 'erpnext.route_to_adjustment_jv',
|
||||
# 'args': journal_entry_args
|
||||
# })
|
||||
|
||||
def validate_cwip_accounts(gl_map):
|
||||
cwip_enabled = any([cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category","enable_cwip_accounting")])
|
||||
|
||||
@@ -1769,6 +1769,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
method: "erpnext.accounts.doctype.sales_invoice.pos.make_invoice",
|
||||
freeze: true,
|
||||
args: {
|
||||
pos_profile: me.pos_profile_data,
|
||||
doc_list: me.si_docs,
|
||||
email_queue_list: me.email_queue_list,
|
||||
customers_list: me.customers_list
|
||||
|
||||
@@ -23,7 +23,7 @@ class DuplicatePartyAccountError(frappe.ValidationError): pass
|
||||
@frappe.whitelist()
|
||||
def get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None,
|
||||
bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False, fetch_payment_terms_template=True,
|
||||
party_address=None, shipping_address=None, pos_profile=None):
|
||||
party_address=None, company_address=None, shipping_address=None, pos_profile=None):
|
||||
|
||||
if not party:
|
||||
return {}
|
||||
@@ -31,14 +31,14 @@ def get_party_details(party=None, account=None, party_type="Customer", company=N
|
||||
frappe.throw(_("{0}: {1} does not exists").format(party_type, party))
|
||||
return _get_party_details(party, account, party_type,
|
||||
company, posting_date, bill_date, price_list, currency, doctype, ignore_permissions,
|
||||
fetch_payment_terms_template, party_address, shipping_address, pos_profile)
|
||||
fetch_payment_terms_template, party_address, company_address, shipping_address, pos_profile)
|
||||
|
||||
def _get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None,
|
||||
bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False,
|
||||
fetch_payment_terms_template=True, party_address=None, shipping_address=None, pos_profile=None):
|
||||
fetch_payment_terms_template=True, party_address=None, company_address=None,shipping_address=None, pos_profile=None):
|
||||
|
||||
out = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype))
|
||||
party = out[party_type.lower()]
|
||||
party_details = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype))
|
||||
party = party_details[party_type.lower()]
|
||||
|
||||
if not ignore_permissions and not frappe.has_permission(party_type, "read", party):
|
||||
frappe.throw(_("Not permitted for {0}").format(party), frappe.PermissionError)
|
||||
@@ -46,76 +46,81 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
|
||||
party = frappe.get_doc(party_type, party)
|
||||
currency = party.default_currency if party.get("default_currency") else get_company_currency(company)
|
||||
|
||||
party_address, shipping_address = set_address_details(out, party, party_type, doctype, company, party_address, shipping_address)
|
||||
set_contact_details(out, party, party_type)
|
||||
set_other_values(out, party, party_type)
|
||||
set_price_list(out, party, party_type, price_list, pos_profile)
|
||||
party_address, shipping_address = set_address_details(party_details, party, party_type, doctype, company, party_address, company_address, shipping_address)
|
||||
set_contact_details(party_details, party, party_type)
|
||||
set_other_values(party_details, party, party_type)
|
||||
set_price_list(party_details, party, party_type, price_list, pos_profile)
|
||||
|
||||
out["tax_category"] = get_address_tax_category(party.get("tax_category"),
|
||||
party_details["tax_category"] = get_address_tax_category(party.get("tax_category"),
|
||||
party_address, shipping_address if party_type != "Supplier" else party_address)
|
||||
out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company,
|
||||
customer_group=out.customer_group, supplier_group=out.supplier_group, tax_category=out.tax_category,
|
||||
billing_address=party_address, shipping_address=shipping_address)
|
||||
|
||||
if not party_details.get("taxes_and_charges"):
|
||||
party_details["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company,
|
||||
customer_group=party_details.customer_group, supplier_group=party_details.supplier_group, tax_category=party_details.tax_category,
|
||||
billing_address=party_address, shipping_address=shipping_address)
|
||||
|
||||
if fetch_payment_terms_template:
|
||||
out["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
|
||||
party_details["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
|
||||
|
||||
if not out.get("currency"):
|
||||
out["currency"] = currency
|
||||
if not party_details.get("currency"):
|
||||
party_details["currency"] = currency
|
||||
|
||||
# sales team
|
||||
if party_type=="Customer":
|
||||
out["sales_team"] = [{
|
||||
party_details["sales_team"] = [{
|
||||
"sales_person": d.sales_person,
|
||||
"allocated_percentage": d.allocated_percentage or None
|
||||
} for d in party.get("sales_team")]
|
||||
|
||||
# supplier tax withholding category
|
||||
if party_type == "Supplier" and party:
|
||||
out["supplier_tds"] = frappe.get_value(party_type, party.name, "tax_withholding_category")
|
||||
party_details["supplier_tds"] = frappe.get_value(party_type, party.name, "tax_withholding_category")
|
||||
|
||||
return out
|
||||
return party_details
|
||||
|
||||
def set_address_details(out, party, party_type, doctype=None, company=None, party_address=None, shipping_address=None):
|
||||
def set_address_details(party_details, party, party_type, doctype=None, company=None, party_address=None, company_address=None, shipping_address=None):
|
||||
billing_address_field = "customer_address" if party_type == "Lead" \
|
||||
else party_type.lower() + "_address"
|
||||
out[billing_address_field] = party_address or get_default_address(party_type, party.name)
|
||||
party_details[billing_address_field] = party_address or get_default_address(party_type, party.name)
|
||||
if doctype:
|
||||
out.update(get_fetch_values(doctype, billing_address_field, out[billing_address_field]))
|
||||
party_details.update(get_fetch_values(doctype, billing_address_field, party_details[billing_address_field]))
|
||||
# address display
|
||||
out.address_display = get_address_display(out[billing_address_field])
|
||||
party_details.address_display = get_address_display(party_details[billing_address_field])
|
||||
# shipping address
|
||||
if party_type in ["Customer", "Lead"]:
|
||||
out.shipping_address_name = shipping_address or get_party_shipping_address(party_type, party.name)
|
||||
out.shipping_address = get_address_display(out["shipping_address_name"])
|
||||
party_details.shipping_address_name = shipping_address or get_party_shipping_address(party_type, party.name)
|
||||
party_details.shipping_address = get_address_display(party_details["shipping_address_name"])
|
||||
if doctype:
|
||||
out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name))
|
||||
party_details.update(get_fetch_values(doctype, 'shipping_address_name', party_details.shipping_address_name))
|
||||
|
||||
if doctype and doctype in ['Delivery Note', 'Sales Invoice']:
|
||||
out.update(get_company_address(company))
|
||||
if out.company_address:
|
||||
out.update(get_fetch_values(doctype, 'company_address', out.company_address))
|
||||
get_regional_address_details(out, doctype, company)
|
||||
if company_address:
|
||||
party_details.update({'company_address': company_address})
|
||||
else:
|
||||
party_details.update(get_company_address(company))
|
||||
|
||||
elif doctype and doctype == "Purchase Invoice":
|
||||
out.update(get_company_address(company))
|
||||
if out.company_address:
|
||||
out["shipping_address"] = shipping_address or out["company_address"]
|
||||
out.shipping_address_display = get_address_display(out["shipping_address"])
|
||||
out.update(get_fetch_values(doctype, 'shipping_address', out.shipping_address))
|
||||
get_regional_address_details(out, doctype, company)
|
||||
if doctype and doctype in ['Delivery Note', 'Sales Invoice', 'Sales Order']:
|
||||
if party_details.company_address:
|
||||
party_details.update(get_fetch_values(doctype, 'company_address', party_details.company_address))
|
||||
get_regional_address_details(party_details, doctype, company)
|
||||
|
||||
return out.get(billing_address_field), out.shipping_address_name
|
||||
elif doctype and doctype in ["Purchase Invoice", "Purchase Order", "Purchase Receipt"]:
|
||||
if party_details.company_address:
|
||||
party_details["shipping_address"] = shipping_address or party_details["company_address"]
|
||||
party_details.shipping_address_display = get_address_display(party_details["shipping_address"])
|
||||
party_details.update(get_fetch_values(doctype, 'shipping_address', party_details.shipping_address))
|
||||
get_regional_address_details(party_details, doctype, company)
|
||||
|
||||
return party_details.get(billing_address_field), party_details.shipping_address_name
|
||||
|
||||
@erpnext.allow_regional
|
||||
def get_regional_address_details(out, doctype, company):
|
||||
def get_regional_address_details(party_details, doctype, company):
|
||||
pass
|
||||
|
||||
def set_contact_details(out, party, party_type):
|
||||
out.contact_person = get_default_contact(party_type, party.name)
|
||||
def set_contact_details(party_details, party, party_type):
|
||||
party_details.contact_person = get_default_contact(party_type, party.name)
|
||||
|
||||
if not out.contact_person:
|
||||
out.update({
|
||||
if not party_details.contact_person:
|
||||
party_details.update({
|
||||
"contact_person": None,
|
||||
"contact_display": None,
|
||||
"contact_email": None,
|
||||
@@ -125,22 +130,22 @@ def set_contact_details(out, party, party_type):
|
||||
"contact_department": None
|
||||
})
|
||||
else:
|
||||
out.update(get_contact_details(out.contact_person))
|
||||
party_details.update(get_contact_details(party_details.contact_person))
|
||||
|
||||
def set_other_values(out, party, party_type):
|
||||
def set_other_values(party_details, party, party_type):
|
||||
# copy
|
||||
if party_type=="Customer":
|
||||
to_copy = ["customer_name", "customer_group", "territory", "language"]
|
||||
else:
|
||||
to_copy = ["supplier_name", "supplier_group", "language"]
|
||||
for f in to_copy:
|
||||
out[f] = party.get(f)
|
||||
party_details[f] = party.get(f)
|
||||
|
||||
# fields prepended with default in Customer doctype
|
||||
for f in ['currency'] \
|
||||
+ (['sales_partner', 'commission_rate'] if party_type=="Customer" else []):
|
||||
if party.get("default_" + f):
|
||||
out[f] = party.get("default_" + f)
|
||||
party_details[f] = party.get("default_" + f)
|
||||
|
||||
def get_default_price_list(party):
|
||||
"""Return default price list for party (Document object)"""
|
||||
@@ -155,7 +160,7 @@ def get_default_price_list(party):
|
||||
|
||||
return None
|
||||
|
||||
def set_price_list(out, party, party_type, given_price_list, pos=None):
|
||||
def set_price_list(party_details, party, party_type, given_price_list, pos=None):
|
||||
# price list
|
||||
price_list = get_permitted_documents('Price List')
|
||||
|
||||
@@ -173,9 +178,9 @@ def set_price_list(out, party, party_type, given_price_list, pos=None):
|
||||
price_list = get_default_price_list(party) or given_price_list
|
||||
|
||||
if price_list:
|
||||
out.price_list_currency = frappe.db.get_value("Price List", price_list, "currency", cache=True)
|
||||
party_details.price_list_currency = frappe.db.get_value("Price List", price_list, "currency", cache=True)
|
||||
|
||||
out["selling_price_list" if party.doctype=="Customer" else "buying_price_list"] = price_list
|
||||
party_details["selling_price_list" if party.doctype=="Customer" else "buying_price_list"] = price_list
|
||||
|
||||
|
||||
def set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype):
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
|
||||
<td class="left" >{{ gl | sum(attribute='debit') }}</td>
|
||||
<td class="left" >{{ frappe.format((gl | sum(attribute="debit")), {fieldtype: "Currency"}) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="5"><strong>Credit</strong></td>
|
||||
@@ -69,7 +69,7 @@
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
|
||||
<td class="left" >{{ gl | sum(attribute='credit') }}</td>
|
||||
<td class="left" >{{ frappe.format((gl | sum(attribute="credit")), {fieldtype: "Currency"}) }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div>
|
||||
|
||||
@@ -100,6 +100,16 @@ frappe.query_reports["Accounts Payable"] = {
|
||||
"fieldtype": "Link",
|
||||
"options": "Supplier Group"
|
||||
},
|
||||
{
|
||||
"fieldname": "group_by_party",
|
||||
"label": __("Group By Supplier"),
|
||||
"fieldtype": "Check"
|
||||
},
|
||||
{
|
||||
"fieldname":"based_on_payment_terms",
|
||||
"label": __("Based On Payment Terms"),
|
||||
"fieldtype": "Check",
|
||||
},
|
||||
{
|
||||
"fieldname":"tax_id",
|
||||
"label": __("Tax Id"),
|
||||
@@ -107,6 +117,16 @@ frappe.query_reports["Accounts Payable"] = {
|
||||
"hidden": 1
|
||||
}
|
||||
],
|
||||
|
||||
"formatter": function(value, row, column, data, default_formatter) {
|
||||
value = default_formatter(value, row, column, data);
|
||||
if (data && data.bold) {
|
||||
value = value.bold();
|
||||
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
onload: function(report) {
|
||||
report.page.add_inner_button(__("Accounts Payable Summary"), function() {
|
||||
var filters = report.get_values();
|
||||
|
||||
@@ -88,6 +88,11 @@ frappe.query_reports["Accounts Payable Summary"] = {
|
||||
"label": __("Supplier Group"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Supplier Group"
|
||||
},
|
||||
{
|
||||
"fieldname":"based_on_payment_terms",
|
||||
"label": __("Based On Payment Terms"),
|
||||
"fieldtype": "Check",
|
||||
}
|
||||
],
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ frappe.query_reports["Accounts Receivable"] = {
|
||||
frappe.query_report.set_filter_value('payment_terms', value["payment_terms"]);
|
||||
});
|
||||
|
||||
frappe.db.get_value('Customer Credit Limit', {'parent': customer, 'company': company},
|
||||
frappe.db.get_value('Customer Credit Limit', {'parent': customer, 'company': company},
|
||||
["credit_limit"], function(value) {
|
||||
if (value) {
|
||||
frappe.query_report.set_filter_value('credit_limit', value["credit_limit"]);
|
||||
@@ -131,6 +131,11 @@ frappe.query_reports["Accounts Receivable"] = {
|
||||
"fieldtype": "Link",
|
||||
"options": "Sales Person"
|
||||
},
|
||||
{
|
||||
"fieldname": "group_by_party",
|
||||
"label": __("Group By Customer"),
|
||||
"fieldtype": "Check"
|
||||
},
|
||||
{
|
||||
"fieldname":"based_on_payment_terms",
|
||||
"label": __("Based On Payment Terms"),
|
||||
@@ -177,6 +182,15 @@ frappe.query_reports["Accounts Receivable"] = {
|
||||
}
|
||||
],
|
||||
|
||||
"formatter": function(value, row, column, data, default_formatter) {
|
||||
value = default_formatter(value, row, column, data);
|
||||
if (data && data.bold) {
|
||||
value = value.bold();
|
||||
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
onload: function(report) {
|
||||
report.page.add_inner_button(__("Accounts Receivable Summary"), function() {
|
||||
var filters = report.get_values();
|
||||
|
||||
@@ -7,7 +7,7 @@ from frappe import _, scrub
|
||||
from frappe.utils import getdate, nowdate, flt, cint, formatdate, cstr, now, time_diff_in_seconds
|
||||
from collections import OrderedDict
|
||||
from erpnext.accounts.utils import get_currency_precision
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children
|
||||
|
||||
# This report gives a summary of all Outstanding Invoices considering the following
|
||||
|
||||
@@ -46,7 +46,7 @@ class ReceivablePayableReport(object):
|
||||
self.get_columns()
|
||||
self.get_data()
|
||||
self.get_chart_data()
|
||||
return self.columns, self.data, None, self.chart
|
||||
return self.columns, self.data, None, self.chart, None, self.skip_total_row
|
||||
|
||||
def set_defaults(self):
|
||||
if not self.filters.get("company"):
|
||||
@@ -57,9 +57,16 @@ class ReceivablePayableReport(object):
|
||||
self.party_type = self.filters.party_type
|
||||
self.party_details = {}
|
||||
self.invoices = set()
|
||||
self.skip_total_row = 0
|
||||
|
||||
if self.filters.get('group_by_party'):
|
||||
self.previous_party=''
|
||||
self.total_row_map = {}
|
||||
self.skip_total_row = 1
|
||||
|
||||
def get_data(self):
|
||||
self.get_gl_entries()
|
||||
self.get_sales_invoices_or_customers_based_on_sales_person()
|
||||
self.voucher_balance = OrderedDict()
|
||||
self.init_voucher_balance() # invoiced, paid, credit_note, outstanding
|
||||
|
||||
@@ -101,14 +108,40 @@ class ReceivablePayableReport(object):
|
||||
)
|
||||
self.get_invoices(gle)
|
||||
|
||||
if self.filters.get('group_by_party'):
|
||||
self.init_subtotal_row(gle.party)
|
||||
|
||||
if self.filters.get('group_by_party'):
|
||||
self.init_subtotal_row('Total')
|
||||
|
||||
def get_invoices(self, gle):
|
||||
if gle.voucher_type in ('Sales Invoice', 'Purchase Invoice'):
|
||||
self.invoices.add(gle.voucher_no)
|
||||
if self.filters.get("sales_person"):
|
||||
if gle.voucher_no in self.sales_person_records.get("Sales Invoice", []) \
|
||||
or gle.party in self.sales_person_records.get("Customer", []):
|
||||
self.invoices.add(gle.voucher_no)
|
||||
else:
|
||||
self.invoices.add(gle.voucher_no)
|
||||
|
||||
def init_subtotal_row(self, party):
|
||||
if not self.total_row_map.get(party):
|
||||
self.total_row_map.setdefault(party, {
|
||||
'party': party,
|
||||
'bold': 1
|
||||
})
|
||||
|
||||
for field in self.get_currency_fields():
|
||||
self.total_row_map[party][field] = 0.0
|
||||
|
||||
def get_currency_fields(self):
|
||||
return ['invoiced', 'paid', 'credit_note', 'outstanding', 'range1',
|
||||
'range2', 'range3', 'range4', 'range5']
|
||||
|
||||
def update_voucher_balance(self, gle):
|
||||
# get the row where this balance needs to be updated
|
||||
# if its a payment, it will return the linked invoice or will be considered as advance
|
||||
row = self.get_voucher_balance(gle)
|
||||
if not row: return
|
||||
# gle_balance will be the total "debit - credit" for receivable type reports and
|
||||
# and vice-versa for payable type reports
|
||||
gle_balance = self.get_gle_balance(gle)
|
||||
@@ -128,9 +161,26 @@ class ReceivablePayableReport(object):
|
||||
# advance / unlinked payment or other adjustment
|
||||
row.paid -= gle_balance
|
||||
|
||||
def get_voucher_balance(self, gle):
|
||||
voucher_balance = None
|
||||
def update_sub_total_row(self, row, party):
|
||||
total_row = self.total_row_map.get(party)
|
||||
|
||||
for field in self.get_currency_fields():
|
||||
total_row[field] += row.get(field, 0.0)
|
||||
|
||||
def append_subtotal_row(self, party):
|
||||
sub_total_row = self.total_row_map.get(party)
|
||||
self.data.append(sub_total_row)
|
||||
self.data.append({})
|
||||
self.update_sub_total_row(sub_total_row, 'Total')
|
||||
|
||||
def get_voucher_balance(self, gle):
|
||||
if self.filters.get("sales_person"):
|
||||
against_voucher = gle.against_voucher or gle.voucher_no
|
||||
if not (gle.party in self.sales_person_records.get("Customer", []) or \
|
||||
against_voucher in self.sales_person_records.get("Sales Invoice", [])):
|
||||
return
|
||||
|
||||
voucher_balance = None
|
||||
if gle.against_voucher:
|
||||
# find invoice
|
||||
against_voucher = gle.against_voucher
|
||||
@@ -159,7 +209,7 @@ class ReceivablePayableReport(object):
|
||||
row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
|
||||
row.invoice_grand_total = row.invoiced
|
||||
|
||||
if abs(row.outstanding) > 0.1/10 ** self.currency_precision:
|
||||
if abs(row.outstanding) > 1.0/10 ** self.currency_precision:
|
||||
# non-zero oustanding, we must consider this row
|
||||
|
||||
if self.is_invoice(row) and self.filters.based_on_payment_terms:
|
||||
@@ -180,11 +230,22 @@ class ReceivablePayableReport(object):
|
||||
else:
|
||||
self.append_row(row)
|
||||
|
||||
if self.filters.get('group_by_party'):
|
||||
self.append_subtotal_row(self.previous_party)
|
||||
self.data.append(self.total_row_map.get('Total'))
|
||||
|
||||
def append_row(self, row):
|
||||
self.allocate_future_payments(row)
|
||||
self.set_invoice_details(row)
|
||||
self.set_party_details(row)
|
||||
self.set_ageing(row)
|
||||
|
||||
if self.filters.get('group_by_party'):
|
||||
self.update_sub_total_row(row, row.party)
|
||||
if self.previous_party and (self.previous_party != row.party):
|
||||
self.append_subtotal_row(self.previous_party)
|
||||
self.previous_party = row.party
|
||||
|
||||
self.data.append(row)
|
||||
|
||||
def set_invoice_details(self, row):
|
||||
@@ -273,7 +334,7 @@ class ReceivablePayableReport(object):
|
||||
|
||||
def set_party_details(self, row):
|
||||
# customer / supplier name
|
||||
party_details = self.get_party_details(row.party)
|
||||
party_details = self.get_party_details(row.party) or {}
|
||||
row.update(party_details)
|
||||
if self.filters.get(scrub(self.filters.party_type)):
|
||||
row.currency = row.account_currency
|
||||
@@ -318,7 +379,7 @@ class ReceivablePayableReport(object):
|
||||
self.append_payment_term(row, d, term)
|
||||
|
||||
def append_payment_term(self, row, d, term):
|
||||
if self.filters.get("customer") and d.currency == d.party_account_currency:
|
||||
if (self.filters.get("customer") or self.filters.get("supplier")) and d.currency == d.party_account_currency:
|
||||
invoiced = d.payment_amount
|
||||
else:
|
||||
invoiced = flt(flt(d.payment_amount) * flt(d.conversion_rate), self.currency_precision)
|
||||
@@ -491,6 +552,7 @@ class ReceivablePayableReport(object):
|
||||
# get all the GL entries filtered by the given filters
|
||||
|
||||
conditions, values = self.prepare_conditions()
|
||||
order_by = self.get_order_by_condition()
|
||||
|
||||
if self.filters.get(scrub(self.party_type)):
|
||||
select_fields = "debit_in_account_currency as debit, credit_in_account_currency as credit"
|
||||
@@ -508,9 +570,24 @@ class ReceivablePayableReport(object):
|
||||
and party_type=%s
|
||||
and (party is not null and party != '')
|
||||
and posting_date <= %s
|
||||
{1}
|
||||
order by posting_date, party"""
|
||||
.format(select_fields, conditions), values, as_dict=True)
|
||||
{1} {2}"""
|
||||
.format(select_fields, conditions, order_by), values, as_dict=True)
|
||||
|
||||
def get_sales_invoices_or_customers_based_on_sales_person(self):
|
||||
if self.filters.get("sales_person"):
|
||||
lft, rgt = frappe.db.get_value("Sales Person",
|
||||
self.filters.get("sales_person"), ["lft", "rgt"])
|
||||
|
||||
records = frappe.db.sql("""
|
||||
select distinct parent, parenttype
|
||||
from `tabSales Team` steam
|
||||
where parenttype in ('Customer', 'Sales Invoice')
|
||||
and exists(select name from `tabSales Person` where lft >= %s and rgt <= %s and name = steam.sales_person)
|
||||
""", (lft, rgt), as_dict=1)
|
||||
|
||||
self.sales_person_records = frappe._dict()
|
||||
for d in records:
|
||||
self.sales_person_records.setdefault(d.parenttype, set()).add(d.parent)
|
||||
|
||||
def prepare_conditions(self):
|
||||
conditions = [""]
|
||||
@@ -526,9 +603,14 @@ class ReceivablePayableReport(object):
|
||||
self.add_supplier_filters(conditions, values)
|
||||
|
||||
self.add_accounting_dimensions_filters(conditions, values)
|
||||
|
||||
return " and ".join(conditions), values
|
||||
|
||||
def get_order_by_condition(self):
|
||||
if self.filters.get('group_by_party'):
|
||||
return "order by party, posting_date"
|
||||
else:
|
||||
return "order by posting_date, party"
|
||||
|
||||
def add_common_filters(self, conditions, values, party_type_field):
|
||||
if self.filters.company:
|
||||
conditions.append("company=%s")
|
||||
@@ -564,16 +646,6 @@ class ReceivablePayableReport(object):
|
||||
conditions.append("party in (select name from tabCustomer where default_sales_partner=%s)")
|
||||
values.append(self.filters.get("sales_partner"))
|
||||
|
||||
if self.filters.get("sales_person"):
|
||||
lft, rgt = frappe.db.get_value("Sales Person",
|
||||
self.filters.get("sales_person"), ["lft", "rgt"])
|
||||
|
||||
conditions.append("""exists(select name from `tabSales Team` steam where
|
||||
steam.sales_person in (select name from `tabSales Person` where lft >= {0} and rgt <= {1})
|
||||
and ((steam.parent = voucher_no and steam.parenttype = voucher_type)
|
||||
or (steam.parent = against_voucher and steam.parenttype = against_voucher_type)
|
||||
or (steam.parent = party and steam.parenttype = 'Customer')))""".format(lft, rgt))
|
||||
|
||||
def add_supplier_filters(self, conditions, values):
|
||||
if self.filters.get("supplier_group"):
|
||||
conditions.append("""party in (select name from tabSupplier
|
||||
@@ -593,13 +665,16 @@ class ReceivablePayableReport(object):
|
||||
doctype=doctype, lft=lft, rgt=rgt, key=key)
|
||||
|
||||
def add_accounting_dimensions_filters(self, conditions, values):
|
||||
accounting_dimensions = get_accounting_dimensions()
|
||||
accounting_dimensions = get_accounting_dimensions(as_list=False)
|
||||
|
||||
if accounting_dimensions:
|
||||
for dimension in accounting_dimensions:
|
||||
if self.filters.get(dimension):
|
||||
conditions.append("{0} = %s".format(dimension))
|
||||
values.append(self.filters.get(dimension))
|
||||
if self.filters.get(dimension.fieldname):
|
||||
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
||||
self.filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
||||
self.filters.get(dimension.fieldname))
|
||||
conditions.append("{0} in %s".format(dimension.fieldname))
|
||||
values.append(tuple(self.filters.get(dimension.fieldname)))
|
||||
|
||||
def get_gle_balance(self, gle):
|
||||
# get the balance of the GL (debit - credit) or reverse balance based on report type
|
||||
@@ -718,11 +793,13 @@ class ReceivablePayableReport(object):
|
||||
def get_chart_data(self):
|
||||
rows = []
|
||||
for row in self.data:
|
||||
values = [row.range1, row.range2, row.range3, row.range4, row.range5]
|
||||
precision = cint(frappe.db.get_default("float_precision")) or 2
|
||||
rows.append({
|
||||
'values': [flt(val, precision) for val in values]
|
||||
})
|
||||
row = frappe._dict(row)
|
||||
if not cint(row.bold):
|
||||
values = [row.range1, row.range2, row.range3, row.range4, row.range5]
|
||||
precision = cint(frappe.db.get_default("float_precision")) or 2
|
||||
rows.append({
|
||||
'values': [flt(val, precision) for val in values]
|
||||
})
|
||||
|
||||
self.chart = {
|
||||
"data": {
|
||||
|
||||
@@ -106,6 +106,11 @@ frappe.query_reports["Accounts Receivable Summary"] = {
|
||||
"label": __("Sales Person"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Sales Person"
|
||||
},
|
||||
{
|
||||
"fieldname":"based_on_payment_terms",
|
||||
"label": __("Based On Payment Terms"),
|
||||
"fieldtype": "Check",
|
||||
}
|
||||
],
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
self.filters.report_date) or {}
|
||||
|
||||
for party, party_dict in iteritems(self.party_total):
|
||||
if party_dict.outstanding <= 0:
|
||||
if party_dict.outstanding == 0:
|
||||
continue
|
||||
|
||||
row = frappe._dict()
|
||||
|
||||
@@ -14,6 +14,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
frappe.query_reports["Balance Sheet"]["filters"].push({
|
||||
"fieldname": "include_default_book_entries",
|
||||
"label": __("Include Default Book Entries"),
|
||||
"fieldtype": "Check"
|
||||
"fieldtype": "Check",
|
||||
"default": 1
|
||||
});
|
||||
});
|
||||
|
||||
@@ -46,13 +46,24 @@ frappe.query_reports["Budget Variance Report"] = {
|
||||
fieldtype: "Select",
|
||||
options: ["Cost Center", "Project"],
|
||||
default: "Cost Center",
|
||||
reqd: 1
|
||||
reqd: 1,
|
||||
on_change: function() {
|
||||
frappe.query_report.set_filter_value("budget_against_filter", []);
|
||||
frappe.query_report.refresh();
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldname: "cost_center",
|
||||
label: __("Cost Center"),
|
||||
fieldtype: "Link",
|
||||
options: "Cost Center"
|
||||
fieldname:"budget_against_filter",
|
||||
label: __('Dimension Filter'),
|
||||
fieldtype: "MultiSelectList",
|
||||
get_data: function(txt) {
|
||||
if (!frappe.query_report.filters) return;
|
||||
|
||||
let budget_against = frappe.query_report.get_filter_value('budget_against');
|
||||
if (!budget_against) return;
|
||||
|
||||
return frappe.db.get_link_options(budget_against, txt);
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldname:"show_cumulative",
|
||||
|
||||
@@ -12,22 +12,22 @@ from six import iteritems
|
||||
from pprint import pprint
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
validate_filters(filters)
|
||||
|
||||
columns = get_columns(filters)
|
||||
if filters.get("cost_center"):
|
||||
cost_centers = [filters.get("cost_center")]
|
||||
if filters.get("budget_against_filter"):
|
||||
dimensions = filters.get("budget_against_filter")
|
||||
else:
|
||||
cost_centers = get_cost_centers(filters)
|
||||
dimensions = get_cost_centers(filters)
|
||||
|
||||
period_month_ranges = get_period_month_ranges(filters["period"], filters["from_fiscal_year"])
|
||||
cam_map = get_cost_center_account_month_map(filters)
|
||||
cam_map = get_dimension_account_month_map(filters)
|
||||
|
||||
data = []
|
||||
for cost_center in cost_centers:
|
||||
cost_center_items = cam_map.get(cost_center)
|
||||
if cost_center_items:
|
||||
for account, monthwise_data in iteritems(cost_center_items):
|
||||
row = [cost_center, account]
|
||||
for dimension in dimensions:
|
||||
dimension_items = cam_map.get(dimension)
|
||||
if dimension_items:
|
||||
for account, monthwise_data in iteritems(dimension_items):
|
||||
row = [dimension, account]
|
||||
totals = [0, 0, 0]
|
||||
for year in get_fiscal_years(filters):
|
||||
last_total = 0
|
||||
@@ -55,10 +55,6 @@ def execute(filters=None):
|
||||
|
||||
return columns, data
|
||||
|
||||
def validate_filters(filters):
|
||||
if filters.get("budget_against") != "Cost Center" and filters.get("cost_center"):
|
||||
frappe.throw(_("Filter based on Cost Center is only applicable if Budget Against is selected as Cost Center"))
|
||||
|
||||
def get_columns(filters):
|
||||
columns = [_(filters.get("budget_against")) + ":Link/%s:150"%(filters.get("budget_against")), _("Account") + ":Link/Account:150"]
|
||||
|
||||
@@ -98,11 +94,12 @@ def get_cost_centers(filters):
|
||||
else:
|
||||
return frappe.db.sql_list("""select name from `tab{tab}`""".format(tab=filters.get("budget_against"))) #nosec
|
||||
|
||||
#Get cost center & target details
|
||||
def get_cost_center_target_details(filters):
|
||||
#Get dimension & target details
|
||||
def get_dimension_target_details(filters):
|
||||
cond = ""
|
||||
if filters.get("cost_center"):
|
||||
cond += " and b.cost_center=%s" % frappe.db.escape(filters.get("cost_center"))
|
||||
if filters.get("budget_against_filter"):
|
||||
cond += " and b.{budget_against} in (%s)".format(budget_against = \
|
||||
frappe.scrub(filters.get('budget_against'))) % ', '.join(['%s']* len(filters.get('budget_against_filter')))
|
||||
|
||||
return frappe.db.sql("""
|
||||
select b.{budget_against} as budget_against, b.monthly_distribution, ba.account, ba.budget_amount,b.fiscal_year
|
||||
@@ -110,8 +107,8 @@ def get_cost_center_target_details(filters):
|
||||
where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year between %s and %s
|
||||
and b.budget_against = %s and b.company=%s {cond} order by b.fiscal_year
|
||||
""".format(budget_against=filters.get("budget_against").replace(" ", "_").lower(), cond=cond),
|
||||
(filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company), as_dict=True)
|
||||
|
||||
tuple([filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company] + filters.get('budget_against_filter')),
|
||||
as_dict=True)
|
||||
|
||||
|
||||
#Get target distribution details of accounts of cost center
|
||||
@@ -153,14 +150,14 @@ def get_actual_details(name, filters):
|
||||
|
||||
return cc_actual_details
|
||||
|
||||
def get_cost_center_account_month_map(filters):
|
||||
def get_dimension_account_month_map(filters):
|
||||
import datetime
|
||||
cost_center_target_details = get_cost_center_target_details(filters)
|
||||
dimension_target_details = get_dimension_target_details(filters)
|
||||
tdd = get_target_distribution_details(filters)
|
||||
|
||||
cam_map = {}
|
||||
|
||||
for ccd in cost_center_target_details:
|
||||
for ccd in dimension_target_details:
|
||||
actual_details = get_actual_details(ccd.budget_against, filters)
|
||||
|
||||
for month_id in range(1, 13):
|
||||
|
||||
@@ -20,7 +20,8 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
{
|
||||
"fieldname": "include_default_book_entries",
|
||||
"label": __("Include Default Book Entries"),
|
||||
"fieldtype": "Check"
|
||||
"fieldtype": "Check",
|
||||
"default": 1
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import cint
|
||||
from frappe.utils import cint, cstr
|
||||
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
|
||||
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
@@ -129,13 +129,13 @@ def get_account_type_based_gl_data(company, start_date, end_date, account_type,
|
||||
cond = ""
|
||||
filters = frappe._dict(filters)
|
||||
|
||||
if filters.finance_book:
|
||||
cond = " and finance_book = %s" %(frappe.db.escape(filters.finance_book))
|
||||
if filters.include_default_book_entries:
|
||||
company_fb = frappe.db.get_value("Company", company, 'default_finance_book')
|
||||
if filters.include_default_book_entries:
|
||||
company_fb = frappe.db.get_value("Company", company, 'default_finance_book')
|
||||
cond = """ AND (finance_book in (%s, %s, '') OR finance_book IS NULL)
|
||||
""" %(frappe.db.escape(filters.finance_book), frappe.db.escape(company_fb))
|
||||
else:
|
||||
cond = " AND (finance_book in (%s, '') OR finance_book IS NULL)" %(frappe.db.escape(cstr(filters.finance_book)))
|
||||
|
||||
cond = """ and finance_book in (%s, %s)
|
||||
""" %(frappe.db.escape(filters.finance_book), frappe.db.escape(company_fb))
|
||||
|
||||
gl_sum = frappe.db.sql_list("""
|
||||
select sum(credit) - sum(debit)
|
||||
|
||||
@@ -58,7 +58,8 @@ frappe.query_reports["Consolidated Financial Statement"] = {
|
||||
{
|
||||
"fieldname": "include_default_book_entries",
|
||||
"label": __("Include Default Book Entries"),
|
||||
"fieldtype": "Check"
|
||||
"fieldtype": "Check",
|
||||
"default": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -387,11 +387,10 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
||||
if from_date:
|
||||
additional_conditions.append("gl.posting_date >= %(from_date)s")
|
||||
|
||||
if filters.get("finance_book"):
|
||||
if filters.get("include_default_book_entries"):
|
||||
additional_conditions.append("finance_book in (%(finance_book)s, %(company_fb)s)")
|
||||
else:
|
||||
additional_conditions.append("finance_book in (%(finance_book)s)")
|
||||
if filters.get("include_default_book_entries"):
|
||||
additional_conditions.append("(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)")
|
||||
else:
|
||||
additional_conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)")
|
||||
|
||||
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{%
|
||||
var report_columns = report.get_columns_for_print();
|
||||
report_columns = report_columns.filter(col => !col.hidden);
|
||||
|
||||
if (report_columns.length > 8) {
|
||||
frappe.throw(__("Too many columns. Export the report and print it using a spreadsheet application."));
|
||||
@@ -15,34 +16,35 @@
|
||||
height: 37px;
|
||||
}
|
||||
</style>
|
||||
{% var letterhead= filters.letter_head || (frappe.get_doc(":Company", filters.company) && frappe.get_doc(":Company", filters.company).default_letter_head) %}
|
||||
{% if(letterhead) { %}
|
||||
<div style="margin-bottom: 7px;" class="text-center">
|
||||
{%= frappe.boot.letter_heads[letterhead].header %}
|
||||
</div>
|
||||
{% } %}
|
||||
|
||||
<h2 class="text-center">{%= __(report.report_name) %}</h2>
|
||||
<h3 class="text-center">{%= filters.company %}</h3>
|
||||
|
||||
{% if 'cost_center' in filters %}
|
||||
<h3 class="text-center">{%= filters.cost_center %}</h3>
|
||||
{% endif %}
|
||||
|
||||
<h3 class="text-center">{%= filters.fiscal_year %}</h3>
|
||||
<h5 class="text-center">{%= __("Currency") %} : {%= filters.presentation_currency || erpnext.get_currency(filters.company) %} </h4>
|
||||
<h5 class="text-center">
|
||||
{%= __("Currency") %} : {%= filters.presentation_currency || erpnext.get_currency(filters.company) %}
|
||||
</h5>
|
||||
{% if (filters.from_date) { %}
|
||||
<h4 class="text-center">{%= frappe.datetime.str_to_user(filters.from_date) %} - {%= frappe.datetime.str_to_user(filters.to_date) %}</h3>
|
||||
<h5 class="text-center">
|
||||
{%= frappe.datetime.str_to_user(filters.from_date) %} - {%= frappe.datetime.str_to_user(filters.to_date) %}
|
||||
</h5>
|
||||
{% } %}
|
||||
<hr>
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: {%= 100 - (report_columns.length - 2) * 13 %}%"></th>
|
||||
{% for(var i=2, l=report_columns.length; i<l; i++) { %}
|
||||
<th style="width: {%= 100 - (report_columns.length - 1) * 13 %}%"></th>
|
||||
{% for (let i=1, l=report_columns.length; i<l; i++) { %}
|
||||
<th class="text-right">{%= report_columns[i].label %}</th>
|
||||
{% } %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for(var j=0, k=data.length-1; j<k; j++) { %}
|
||||
{% for(let j=0, k=data.length-1; j<k; j++) { %}
|
||||
{%
|
||||
var row = data[j];
|
||||
var row_class = data[j].parent_account ? "" : "financial-statements-important";
|
||||
@@ -52,11 +54,11 @@
|
||||
<td>
|
||||
<span style="padding-left: {%= cint(data[j].indent) * 2 %}em">{%= row.account_name %}</span>
|
||||
</td>
|
||||
{% for(var i=2, l=report_columns.length; i<l; i++) { %}
|
||||
{% for(let i=1, l=report_columns.length; i<l; i++) { %}
|
||||
<td class="text-right">
|
||||
{% var fieldname = report_columns[i].fieldname; %}
|
||||
{% const fieldname = report_columns[i].fieldname; %}
|
||||
{% if (!is_null(row[fieldname])) { %}
|
||||
{%= format_currency(row[fieldname], filters.presentation_currency) %}
|
||||
{%= frappe.format(row[fieldname], report_columns[i], {}, row) %}
|
||||
{% } %}
|
||||
</td>
|
||||
{% } %}
|
||||
@@ -64,4 +66,6 @@
|
||||
{% } %}
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="text-right text-muted">Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}</p>
|
||||
<p class="text-right text-muted">
|
||||
Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}
|
||||
</p>
|
||||
|
||||
@@ -13,10 +13,10 @@ import frappe, erpnext
|
||||
from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from frappe import _
|
||||
from frappe.utils import (flt, getdate, get_first_day, add_months, add_days, formatdate)
|
||||
from frappe.utils import (flt, getdate, get_first_day, add_months, add_days, formatdate, cstr)
|
||||
|
||||
from six import itervalues
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children
|
||||
|
||||
def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_values=False,
|
||||
company=None, reset_period_on_fy_change=True):
|
||||
@@ -264,8 +264,8 @@ def filter_out_zero_value_rows(data, parent_children_map, show_zero_values=False
|
||||
|
||||
def add_total_row(out, root_type, balance_must_be, period_list, company_currency):
|
||||
total_row = {
|
||||
"account_name": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'",
|
||||
"account": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'",
|
||||
"account_name": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)),
|
||||
"account": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)),
|
||||
"currency": company_currency
|
||||
}
|
||||
|
||||
@@ -348,46 +348,48 @@ def set_gl_entries_by_account(
|
||||
additional_conditions = get_additional_conditions(from_date, ignore_closing_entries, filters)
|
||||
|
||||
accounts = frappe.db.sql_list("""select name from `tabAccount`
|
||||
where lft >= %s and rgt <= %s""", (root_lft, root_rgt))
|
||||
additional_conditions += " and account in ({})"\
|
||||
.format(", ".join([frappe.db.escape(d) for d in accounts]))
|
||||
where lft >= %s and rgt <= %s and company = %s""", (root_lft, root_rgt, company))
|
||||
|
||||
gl_filters = {
|
||||
"company": company,
|
||||
"from_date": from_date,
|
||||
"to_date": to_date,
|
||||
"finance_book": filters.get("finance_book")
|
||||
}
|
||||
if accounts:
|
||||
additional_conditions += " and account in ({})"\
|
||||
.format(", ".join([frappe.db.escape(d) for d in accounts]))
|
||||
|
||||
if filters.get("include_default_book_entries"):
|
||||
gl_filters["company_fb"] = frappe.db.get_value("Company",
|
||||
company, 'default_finance_book')
|
||||
gl_filters = {
|
||||
"company": company,
|
||||
"from_date": from_date,
|
||||
"to_date": to_date,
|
||||
"finance_book": cstr(filters.get("finance_book"))
|
||||
}
|
||||
|
||||
for key, value in filters.items():
|
||||
if value:
|
||||
gl_filters.update({
|
||||
key: value
|
||||
})
|
||||
if filters.get("include_default_book_entries"):
|
||||
gl_filters["company_fb"] = frappe.db.get_value("Company",
|
||||
company, 'default_finance_book')
|
||||
|
||||
gl_entries = frappe.db.sql("""select posting_date, account, debit, credit, is_opening, fiscal_year, debit_in_account_currency, credit_in_account_currency, account_currency from `tabGL Entry`
|
||||
where company=%(company)s
|
||||
{additional_conditions}
|
||||
and posting_date <= %(to_date)s
|
||||
order by account, posting_date""".format(additional_conditions=additional_conditions), gl_filters, as_dict=True) #nosec
|
||||
for key, value in filters.items():
|
||||
if value:
|
||||
gl_filters.update({
|
||||
key: value
|
||||
})
|
||||
|
||||
if filters and filters.get('presentation_currency'):
|
||||
convert_to_presentation_currency(gl_entries, get_currency(filters))
|
||||
gl_entries = frappe.db.sql("""select posting_date, account, debit, credit, is_opening, fiscal_year, debit_in_account_currency, credit_in_account_currency, account_currency from `tabGL Entry`
|
||||
where company=%(company)s
|
||||
{additional_conditions}
|
||||
and posting_date <= %(to_date)s
|
||||
order by account, posting_date""".format(additional_conditions=additional_conditions), gl_filters, as_dict=True) #nosec
|
||||
|
||||
for entry in gl_entries:
|
||||
gl_entries_by_account.setdefault(entry.account, []).append(entry)
|
||||
if filters and filters.get('presentation_currency'):
|
||||
convert_to_presentation_currency(gl_entries, get_currency(filters))
|
||||
|
||||
return gl_entries_by_account
|
||||
for entry in gl_entries:
|
||||
gl_entries_by_account.setdefault(entry.account, []).append(entry)
|
||||
|
||||
return gl_entries_by_account
|
||||
|
||||
|
||||
def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
||||
additional_conditions = []
|
||||
|
||||
accounting_dimensions = get_accounting_dimensions()
|
||||
accounting_dimensions = get_accounting_dimensions(as_list=False)
|
||||
|
||||
if ignore_closing_entries:
|
||||
additional_conditions.append("ifnull(voucher_type, '')!='Period Closing Voucher'")
|
||||
@@ -406,16 +408,18 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
||||
filters.cost_center = get_cost_centers_with_children(filters.cost_center)
|
||||
additional_conditions.append("cost_center in %(cost_center)s")
|
||||
|
||||
if filters.get("finance_book"):
|
||||
if filters.get("include_default_book_entries"):
|
||||
additional_conditions.append("finance_book in (%(finance_book)s, %(company_fb)s)")
|
||||
else:
|
||||
additional_conditions.append("finance_book in (%(finance_book)s)")
|
||||
if filters.get("include_default_book_entries"):
|
||||
additional_conditions.append("(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)")
|
||||
else:
|
||||
additional_conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)")
|
||||
|
||||
if accounting_dimensions:
|
||||
for dimension in accounting_dimensions:
|
||||
if filters.get(dimension):
|
||||
additional_conditions.append("{0} in (%({0})s)".format(dimension))
|
||||
if filters.get(dimension.fieldname):
|
||||
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
||||
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
||||
filters.get(dimension.fieldname))
|
||||
additional_conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
||||
|
||||
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<h4 class="text-center">
|
||||
{% if (filters.party_name) { %}
|
||||
{%= filters.party_name %}
|
||||
{% } else if (filters.party && filters.show_name) { %}
|
||||
{% } else if (filters.party) { %}
|
||||
{%= filters.party %}
|
||||
{% } else if (filters.account) { %}
|
||||
{%= filters.account %}
|
||||
@@ -33,7 +33,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for(var i=0, l=data.length-1; i<l; i++) { %}
|
||||
{% for(var i=0, l=data.length; i<l; i++) { %}
|
||||
<tr>
|
||||
{% if(data[i].posting_date) { %}
|
||||
<td>{%= frappe.datetime.str_to_user(data[i].posting_date) %}</td>
|
||||
|
||||
@@ -154,7 +154,8 @@ frappe.query_reports["General Ledger"] = {
|
||||
{
|
||||
"fieldname": "include_default_book_entries",
|
||||
"label": __("Include Default Book Entries"),
|
||||
"fieldtype": "Check"
|
||||
"fieldtype": "Check",
|
||||
"default": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ from frappe import _, _dict
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from erpnext.accounts.report.financial_statements import get_cost_centers_with_children
|
||||
from six import iteritems
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children
|
||||
from collections import OrderedDict
|
||||
|
||||
def execute(filters=None):
|
||||
@@ -119,7 +119,7 @@ def get_gl_entries(filters):
|
||||
select_fields = """, debit, credit, debit_in_account_currency,
|
||||
credit_in_account_currency """
|
||||
|
||||
order_by_statement = "order by posting_date, account"
|
||||
order_by_statement = "order by posting_date, account, creation"
|
||||
|
||||
if filters.get("group_by") == _("Group by Voucher"):
|
||||
order_by_statement = "order by posting_date, voucher_type, voucher_no"
|
||||
@@ -184,7 +184,7 @@ def get_conditions(filters):
|
||||
|
||||
if filters.get("finance_book"):
|
||||
if filters.get("include_default_book_entries"):
|
||||
conditions.append("finance_book in (%(finance_book)s, %(company_fb)s)")
|
||||
conditions.append("(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)")
|
||||
else:
|
||||
conditions.append("finance_book in (%(finance_book)s)")
|
||||
|
||||
@@ -194,12 +194,15 @@ def get_conditions(filters):
|
||||
if match_conditions:
|
||||
conditions.append(match_conditions)
|
||||
|
||||
accounting_dimensions = get_accounting_dimensions()
|
||||
accounting_dimensions = get_accounting_dimensions(as_list=False)
|
||||
|
||||
if accounting_dimensions:
|
||||
for dimension in accounting_dimensions:
|
||||
if filters.get(dimension):
|
||||
conditions.append("{0} in (%({0})s)".format(dimension))
|
||||
if filters.get(dimension.fieldname):
|
||||
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
||||
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
||||
filters.get(dimension.fieldname))
|
||||
conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
||||
|
||||
return "and {}".format(" and ".join(conditions)) if conditions else ""
|
||||
|
||||
|
||||
@@ -34,6 +34,20 @@ frappe.query_reports["Item-wise Purchase Register"] = {
|
||||
"label": __("Mode of Payment"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Mode of Payment"
|
||||
},
|
||||
{
|
||||
"label": __("Group By"),
|
||||
"fieldname": "group_by",
|
||||
"fieldtype": "Select",
|
||||
"options": ["Supplier", "Item Group", "Item", "Invoice"]
|
||||
}
|
||||
]
|
||||
],
|
||||
"formatter": function(value, row, column, data, default_formatter) {
|
||||
value = default_formatter(value, row, column, data);
|
||||
if (data && data.bold) {
|
||||
value = value.bold();
|
||||
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ from __future__ import unicode_literals
|
||||
import frappe, erpnext
|
||||
from frappe import _
|
||||
from frappe.utils import flt
|
||||
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import get_tax_accounts
|
||||
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import (get_tax_accounts,
|
||||
get_grand_total, add_total_row, get_display_value, get_group_by_and_display_fields, add_sub_total_row,
|
||||
get_group_by_conditions)
|
||||
|
||||
def execute(filters=None):
|
||||
return _execute(filters)
|
||||
@@ -13,7 +15,7 @@ def execute(filters=None):
|
||||
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
|
||||
if not filters: filters = {}
|
||||
filters.update({"from_date": filters.get("date_range")[0], "to_date": filters.get("date_range")[1]})
|
||||
columns = get_columns(additional_table_columns)
|
||||
columns = get_columns(additional_table_columns, filters)
|
||||
|
||||
company_currency = erpnext.get_company_currency(filters.company)
|
||||
|
||||
@@ -23,16 +25,16 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
||||
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency,
|
||||
doctype="Purchase Invoice", tax_doctype="Purchase Taxes and Charges")
|
||||
|
||||
columns.append({
|
||||
"fieldname": "currency",
|
||||
"label": _("Currency"),
|
||||
"fieldtype": "Data",
|
||||
"width": 80
|
||||
})
|
||||
|
||||
po_pr_map = get_purchase_receipts_against_purchase_order(item_list)
|
||||
|
||||
data = []
|
||||
total_row_map = {}
|
||||
skip_total_row = 0
|
||||
prev_group_by_value = ''
|
||||
|
||||
if filters.get('group_by'):
|
||||
grand_total = get_grand_total(filters, 'Purchase Invoice')
|
||||
|
||||
for d in item_list:
|
||||
if not d.stock_qty:
|
||||
continue
|
||||
@@ -44,51 +46,244 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
||||
purchase_receipt = ", ".join(po_pr_map.get(d.po_detail, []))
|
||||
|
||||
expense_account = d.expense_account or aii_account_map.get(d.company)
|
||||
row = [d.item_code, d.item_name, d.item_group, d.description, d.parent, d.posting_date, d.supplier,
|
||||
d.supplier_name]
|
||||
|
||||
row = {
|
||||
'item_code': d.item_code,
|
||||
'item_name': d.item_name,
|
||||
'item_group': d.item_group,
|
||||
'description': d.description,
|
||||
'invoice': d.parent,
|
||||
'posting_date': d.posting_date,
|
||||
'supplier': d.supplier,
|
||||
'supplier_name': d.supplier_name
|
||||
}
|
||||
|
||||
if additional_query_columns:
|
||||
for col in additional_query_columns:
|
||||
row.append(d.get(col))
|
||||
row.update({
|
||||
col: d.get(col)
|
||||
})
|
||||
|
||||
row += [
|
||||
d.credit_to, d.mode_of_payment, d.project, d.company, d.purchase_order,
|
||||
purchase_receipt, expense_account, d.stock_qty, d.stock_uom, d.base_net_amount / d.stock_qty, d.base_net_amount
|
||||
]
|
||||
row.update({
|
||||
'credit_to': d.credit_to,
|
||||
'mode_of_payment': d.mode_of_payment,
|
||||
'project': d.project,
|
||||
'company': d.company,
|
||||
'purchase_order': d.purchase_order,
|
||||
'purchase_receipt': d.purchase_receipt,
|
||||
'expense_account': expense_account,
|
||||
'stock_qty': d.stock_qty,
|
||||
'stock_uom': d.stock_uom,
|
||||
'rate': d.base_net_amount / d.stock_qty,
|
||||
'amount': d.base_net_amount
|
||||
})
|
||||
|
||||
total_tax = 0
|
||||
for tax in tax_columns:
|
||||
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
||||
row += [item_tax.get("tax_rate", 0), item_tax.get("tax_amount", 0)]
|
||||
row.update({
|
||||
frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0),
|
||||
frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0),
|
||||
})
|
||||
total_tax += flt(item_tax.get("tax_amount"))
|
||||
|
||||
row += [total_tax, d.base_net_amount + total_tax, company_currency]
|
||||
row.update({
|
||||
'total_tax': total_tax,
|
||||
'total': d.base_net_amount + total_tax,
|
||||
'currency': company_currency
|
||||
})
|
||||
|
||||
if filters.get('group_by'):
|
||||
row.update({'percent_gt': flt(row['total']/grand_total) * 100})
|
||||
group_by_field, subtotal_display_field = get_group_by_and_display_fields(filters)
|
||||
data, prev_group_by_value = add_total_row(data, filters, prev_group_by_value, d, total_row_map,
|
||||
group_by_field, subtotal_display_field, grand_total, tax_columns)
|
||||
add_sub_total_row(row, total_row_map, d.get(group_by_field, ''), tax_columns)
|
||||
|
||||
data.append(row)
|
||||
|
||||
return columns, data
|
||||
if filters.get('group_by'):
|
||||
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
|
||||
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
|
||||
data.append(total_row)
|
||||
data.append({})
|
||||
add_sub_total_row(total_row, total_row_map, 'total_row', tax_columns)
|
||||
data.append(total_row_map.get('total_row'))
|
||||
skip_total_row = 1
|
||||
|
||||
return columns, data, None, None, None, skip_total_row
|
||||
|
||||
|
||||
def get_columns(additional_table_columns):
|
||||
columns = [
|
||||
_("Item Code") + ":Link/Item:120", _("Item Name") + "::120",
|
||||
_("Item Group") + ":Link/Item Group:100", "Description::150", _("Invoice") + ":Link/Purchase Invoice:120",
|
||||
_("Posting Date") + ":Date:80", _("Supplier") + ":Link/Supplier:120",
|
||||
"Supplier Name::120"
|
||||
]
|
||||
def get_columns(additional_table_columns, filters):
|
||||
|
||||
columns = []
|
||||
|
||||
if filters.get('group_by') != ('Item'):
|
||||
columns.extend(
|
||||
[
|
||||
{
|
||||
'label': _('Item Code'),
|
||||
'fieldname': 'item_code',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Item',
|
||||
'width': 120
|
||||
},
|
||||
{
|
||||
'label': _('Item Name'),
|
||||
'fieldname': 'item_name',
|
||||
'fieldtype': 'Data',
|
||||
'width': 120
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
if filters.get('group_by') not in ('Item', 'Item Group'):
|
||||
columns.extend([
|
||||
{
|
||||
'label': _('Item Group'),
|
||||
'fieldname': 'item_group',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Item Group',
|
||||
'width': 120
|
||||
}
|
||||
])
|
||||
|
||||
columns.extend([
|
||||
{
|
||||
'label': _('Description'),
|
||||
'fieldname': 'description',
|
||||
'fieldtype': 'Data',
|
||||
'width': 150
|
||||
},
|
||||
{
|
||||
'label': _('Invoice'),
|
||||
'fieldname': 'invoice',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Purchase Invoice',
|
||||
'width': 120
|
||||
},
|
||||
{
|
||||
'label': _('Posting Date'),
|
||||
'fieldname': 'posting_date',
|
||||
'fieldtype': 'Date',
|
||||
'width': 120
|
||||
}
|
||||
])
|
||||
|
||||
if filters.get('group_by') != 'Supplier':
|
||||
columns.extend([
|
||||
{
|
||||
'label': _('Supplier'),
|
||||
'fieldname': 'supplier',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Supplier',
|
||||
'width': 120
|
||||
},
|
||||
{
|
||||
'label': _('Supplier Name'),
|
||||
'fieldname': 'supplier_name',
|
||||
'fieldtype': 'Data',
|
||||
'width': 120
|
||||
}
|
||||
])
|
||||
|
||||
if additional_table_columns:
|
||||
columns += additional_table_columns
|
||||
|
||||
columns += [
|
||||
"Payable Account:Link/Account:120",
|
||||
_("Mode of Payment") + ":Link/Mode of Payment:80", _("Project") + ":Link/Project:80",
|
||||
_("Company") + ":Link/Company:100", _("Purchase Order") + ":Link/Purchase Order:100",
|
||||
_("Purchase Receipt") + ":Link/Purchase Receipt:100", _("Expense Account") + ":Link/Account:140",
|
||||
_("Stock Qty") + ":Float:120", _("Stock UOM") + "::100",
|
||||
_("Rate") + ":Currency/currency:120", _("Amount") + ":Currency/currency:120"
|
||||
{
|
||||
'label': _('Payable Account'),
|
||||
'fieldname': 'credit_to',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Account',
|
||||
'width': 80
|
||||
},
|
||||
{
|
||||
'label': _('Mode Of Payment'),
|
||||
'fieldname': 'mode_of_payment',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Mode of Payment',
|
||||
'width': 120
|
||||
},
|
||||
{
|
||||
'label': _('Project'),
|
||||
'fieldname': 'project',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Project',
|
||||
'width': 80
|
||||
},
|
||||
{
|
||||
'label': _('Company'),
|
||||
'fieldname': 'company',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Company',
|
||||
'width': 80
|
||||
},
|
||||
{
|
||||
'label': _('Purchase Order'),
|
||||
'fieldname': 'purchase_order',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Purchase Order',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _("Purchase Receipt"),
|
||||
'fieldname': 'Purchase Receipt',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Purchase Receipt',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _('Expense Account'),
|
||||
'fieldname': 'expense_account',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Account',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _('Stock Qty'),
|
||||
'fieldname': 'stock_qty',
|
||||
'fieldtype': 'Float',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _('Stock UOM'),
|
||||
'fieldname': 'stock_uom',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'UOM',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _('Rate'),
|
||||
'fieldname': 'rate',
|
||||
'fieldtype': 'Float',
|
||||
'options': 'currency',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _('Amount'),
|
||||
'fieldname': 'amount',
|
||||
'fieldtype': 'Currency',
|
||||
'options': 'currency',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'fieldname': 'currency',
|
||||
'label': _('Currency'),
|
||||
'fieldtype': 'Currency',
|
||||
'width': 80,
|
||||
'hidden': 1
|
||||
}
|
||||
]
|
||||
|
||||
if filters.get('group_by'):
|
||||
columns.append({
|
||||
'label': _('% Of Grand Total'),
|
||||
'fieldname': 'percent_gt',
|
||||
'fieldtype': 'Float',
|
||||
'width': 80
|
||||
})
|
||||
|
||||
return columns
|
||||
|
||||
def get_conditions(filters):
|
||||
@@ -103,17 +298,20 @@ def get_conditions(filters):
|
||||
if filters.get(opts[0]):
|
||||
conditions += opts[1]
|
||||
|
||||
if not filters.get("group_by"):
|
||||
conditions += "ORDER BY `tabPurchase Invoice`.posting_date desc, `tabPurchase Invoice Item`.item_code desc"
|
||||
else:
|
||||
conditions += get_group_by_conditions(filters, 'Purchase Invoice')
|
||||
|
||||
return conditions
|
||||
|
||||
def get_items(filters, additional_query_columns):
|
||||
conditions = get_conditions(filters)
|
||||
match_conditions = frappe.build_match_conditions("Purchase Invoice")
|
||||
|
||||
if match_conditions:
|
||||
match_conditions = " and {0} ".format(match_conditions)
|
||||
|
||||
if additional_query_columns:
|
||||
additional_query_columns = ', ' + ', '.join(additional_query_columns)
|
||||
else:
|
||||
additional_query_columns = ''
|
||||
|
||||
return frappe.db.sql("""
|
||||
select
|
||||
@@ -125,12 +323,11 @@ def get_items(filters, additional_query_columns):
|
||||
`tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`,
|
||||
`tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`,
|
||||
`tabPurchase Invoice Item`.`stock_uom`, `tabPurchase Invoice Item`.`base_net_amount`,
|
||||
`tabPurchase Invoice`.supplier_name, `tabPurchase Invoice`.mode_of_payment {0}
|
||||
`tabPurchase Invoice`.`supplier_name`, `tabPurchase Invoice`.`mode_of_payment` {0}
|
||||
from `tabPurchase Invoice`, `tabPurchase Invoice Item`
|
||||
where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.`parent` and
|
||||
`tabPurchase Invoice`.docstatus = 1 %s %s
|
||||
order by `tabPurchase Invoice`.posting_date desc, `tabPurchase Invoice Item`.item_code desc
|
||||
""".format(additional_query_columns) % (conditions, match_conditions), filters, as_dict=1)
|
||||
`tabPurchase Invoice`.docstatus = 1 %s
|
||||
""".format(additional_query_columns) % (conditions), filters, as_dict=1)
|
||||
|
||||
def get_aii_accounts():
|
||||
return dict(frappe.db.sql("select name, stock_received_but_not_billed from tabCompany"))
|
||||
|
||||
@@ -4,48 +4,62 @@
|
||||
frappe.query_reports["Item-wise Sales Register"] = {
|
||||
"filters": [
|
||||
{
|
||||
"fieldname":"date_range",
|
||||
"fieldname": "date_range",
|
||||
"label": __("Date Range"),
|
||||
"fieldtype": "DateRange",
|
||||
"default": [frappe.datetime.add_months(frappe.datetime.get_today(),-1), frappe.datetime.get_today()],
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"customer",
|
||||
"fieldname": "customer",
|
||||
"label": __("Customer"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Customer"
|
||||
},
|
||||
{
|
||||
"fieldname":"company",
|
||||
"fieldname": "company",
|
||||
"label": __("Company"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Company",
|
||||
"default": frappe.defaults.get_user_default("Company")
|
||||
},
|
||||
{
|
||||
"fieldname":"mode_of_payment",
|
||||
"fieldname": "mode_of_payment",
|
||||
"label": __("Mode of Payment"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Mode of Payment"
|
||||
},
|
||||
{
|
||||
"fieldname":"warehouse",
|
||||
"fieldname": "warehouse",
|
||||
"label": __("Warehouse"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Warehouse"
|
||||
},
|
||||
{
|
||||
"fieldname":"brand",
|
||||
"fieldname": "brand",
|
||||
"label": __("Brand"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Brand"
|
||||
},
|
||||
{
|
||||
"fieldname":"item_group",
|
||||
"fieldname": "item_group",
|
||||
"label": __("Item Group"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Item Group"
|
||||
},
|
||||
{
|
||||
"label": __("Group By"),
|
||||
"fieldname": "group_by",
|
||||
"fieldtype": "Select",
|
||||
"options": ["Customer Group", "Customer", "Item Group", "Item", "Territory", "Invoice"]
|
||||
}
|
||||
]
|
||||
],
|
||||
"formatter": function(value, row, column, data, default_formatter) {
|
||||
value = default_formatter(value, row, column, data);
|
||||
if (data && data.bold) {
|
||||
value = value.bold();
|
||||
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe, erpnext
|
||||
from frappe import _
|
||||
from frappe.utils import flt
|
||||
from frappe.utils import flt, cstr
|
||||
from frappe.model.meta import get_field_precision
|
||||
from frappe.utils.xlsxutils import handle_html
|
||||
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
|
||||
@@ -15,23 +15,25 @@ def execute(filters=None):
|
||||
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
|
||||
if not filters: filters = {}
|
||||
filters.update({"from_date": filters.get("date_range") and filters.get("date_range")[0], "to_date": filters.get("date_range") and filters.get("date_range")[1]})
|
||||
columns = get_columns(additional_table_columns)
|
||||
columns = get_columns(additional_table_columns, filters)
|
||||
|
||||
company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency")
|
||||
|
||||
item_list = get_items(filters, additional_query_columns)
|
||||
if item_list:
|
||||
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency)
|
||||
columns.append({
|
||||
"fieldname": "currency",
|
||||
"label": _("Currency"),
|
||||
"fieldtype": "Data",
|
||||
"width": 80
|
||||
})
|
||||
|
||||
mode_of_payments = get_mode_of_payments(set([d.parent for d in item_list]))
|
||||
so_dn_map = get_delivery_notes_against_sales_order(item_list)
|
||||
|
||||
data = []
|
||||
total_row_map = {}
|
||||
skip_total_row = 0
|
||||
prev_group_by_value = ''
|
||||
|
||||
if filters.get('group_by'):
|
||||
grand_total = get_grand_total(filters, 'Sales Invoice')
|
||||
|
||||
for d in item_list:
|
||||
delivery_note = None
|
||||
if d.delivery_note:
|
||||
@@ -42,57 +44,285 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
||||
if not delivery_note and d.update_stock:
|
||||
delivery_note = d.parent
|
||||
|
||||
row = [d.item_code, d.item_name, d.item_group, d.description, d.parent, d.posting_date, d.customer, d.customer_name]
|
||||
row = {
|
||||
'item_code': d.item_code,
|
||||
'item_name': d.item_name,
|
||||
'item_group': d.item_group,
|
||||
'description': d.description,
|
||||
'invoice': d.parent,
|
||||
'posting_date': d.posting_date,
|
||||
'customer': d.customer,
|
||||
'customer_name': d.customer_name,
|
||||
'customer_group': d.customer_group,
|
||||
}
|
||||
|
||||
if additional_query_columns:
|
||||
for col in additional_query_columns:
|
||||
row.append(d.get(col))
|
||||
row.update({
|
||||
col: d.get(col)
|
||||
})
|
||||
|
||||
row += [
|
||||
d.customer_group, d.debit_to, ", ".join(mode_of_payments.get(d.parent, [])),
|
||||
d.territory, d.project, d.company, d.sales_order,
|
||||
delivery_note, d.income_account, d.cost_center, d.stock_qty, d.stock_uom
|
||||
]
|
||||
row.update({
|
||||
'debit_to': d.debit_to,
|
||||
'mode_of_payment': ", ".join(mode_of_payments.get(d.parent, [])),
|
||||
'territory': d.territory,
|
||||
'project': d.project,
|
||||
'company': d.company,
|
||||
'sales_order': d.sales_order,
|
||||
'delivery_note': d.delivery_note,
|
||||
'income_account': d.income_account,
|
||||
'cost_center': d.cost_center,
|
||||
'stock_qty': d.stock_qty,
|
||||
'stock_uom': d.stock_uom
|
||||
})
|
||||
|
||||
if d.stock_uom != d.uom and d.stock_qty:
|
||||
row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount]
|
||||
row.update({
|
||||
'rate': (d.base_net_rate * d.qty)/d.stock_qty,
|
||||
'amount': d.base_net_amount
|
||||
})
|
||||
else:
|
||||
row += [d.base_net_rate, d.base_net_amount]
|
||||
row.update({
|
||||
'rate': d.base_net_rate,
|
||||
'amount': d.base_net_amount
|
||||
})
|
||||
|
||||
total_tax = 0
|
||||
for tax in tax_columns:
|
||||
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
||||
row += [item_tax.get("tax_rate", 0), item_tax.get("tax_amount", 0)]
|
||||
row.update({
|
||||
frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0),
|
||||
frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0),
|
||||
})
|
||||
total_tax += flt(item_tax.get("tax_amount"))
|
||||
|
||||
row += [total_tax, d.base_net_amount + total_tax, company_currency]
|
||||
row.update({
|
||||
'total_tax': total_tax,
|
||||
'total': d.base_net_amount + total_tax,
|
||||
'currency': company_currency
|
||||
})
|
||||
|
||||
if filters.get('group_by'):
|
||||
row.update({'percent_gt': flt(row['total']/grand_total) * 100})
|
||||
group_by_field, subtotal_display_field = get_group_by_and_display_fields(filters)
|
||||
data, prev_group_by_value = add_total_row(data, filters, prev_group_by_value, d, total_row_map,
|
||||
group_by_field, subtotal_display_field, grand_total, tax_columns)
|
||||
add_sub_total_row(row, total_row_map, d.get(group_by_field, ''), tax_columns)
|
||||
|
||||
data.append(row)
|
||||
|
||||
return columns, data
|
||||
if filters.get('group_by'):
|
||||
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
|
||||
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
|
||||
data.append(total_row)
|
||||
data.append({})
|
||||
add_sub_total_row(total_row, total_row_map, 'total_row', tax_columns)
|
||||
data.append(total_row_map.get('total_row'))
|
||||
skip_total_row = 1
|
||||
|
||||
def get_columns(additional_table_columns):
|
||||
columns = [
|
||||
_("Item Code") + ":Link/Item:120", _("Item Name") + "::120",
|
||||
_("Item Group") + ":Link/Item Group:100", "Description::150", _("Invoice") + ":Link/Sales Invoice:120",
|
||||
_("Posting Date") + ":Date:80", _("Customer") + ":Link/Customer:120",
|
||||
_("Customer Name") + "::120"]
|
||||
return columns, data, None, None, None, skip_total_row
|
||||
|
||||
def get_columns(additional_table_columns, filters):
|
||||
columns = []
|
||||
|
||||
if filters.get('group_by') != ('Item'):
|
||||
columns.extend(
|
||||
[
|
||||
{
|
||||
'label': _('Item Code'),
|
||||
'fieldname': 'item_code',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Item',
|
||||
'width': 120
|
||||
},
|
||||
{
|
||||
'label': _('Item Name'),
|
||||
'fieldname': 'item_name',
|
||||
'fieldtype': 'Data',
|
||||
'width': 120
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
if filters.get('group_by') not in ('Item', 'Item Group'):
|
||||
columns.extend([
|
||||
{
|
||||
'label': _('Item Group'),
|
||||
'fieldname': 'item_group',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Item Group',
|
||||
'width': 120
|
||||
}
|
||||
])
|
||||
|
||||
columns.extend([
|
||||
{
|
||||
'label': _('Description'),
|
||||
'fieldname': 'description',
|
||||
'fieldtype': 'Data',
|
||||
'width': 150
|
||||
},
|
||||
{
|
||||
'label': _('Invoice'),
|
||||
'fieldname': 'invoice',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Sales Invoice',
|
||||
'width': 120
|
||||
},
|
||||
{
|
||||
'label': _('Posting Date'),
|
||||
'fieldname': 'posting_date',
|
||||
'fieldtype': 'Date',
|
||||
'width': 120
|
||||
}
|
||||
])
|
||||
|
||||
if filters.get('group_by') != 'Customer':
|
||||
columns.extend([
|
||||
{
|
||||
'label': _('Customer Group'),
|
||||
'fieldname': 'customer_group',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Customer Group',
|
||||
'width': 120
|
||||
}
|
||||
])
|
||||
|
||||
if filters.get('group_by') not in ('Customer', 'Customer Group'):
|
||||
columns.extend([
|
||||
{
|
||||
'label': _('Customer'),
|
||||
'fieldname': 'customer',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Customer',
|
||||
'width': 120
|
||||
},
|
||||
{
|
||||
'label': _('Customer Name'),
|
||||
'fieldname': 'customer_name',
|
||||
'fieldtype': 'Data',
|
||||
'width': 120
|
||||
}
|
||||
])
|
||||
|
||||
if additional_table_columns:
|
||||
columns += additional_table_columns
|
||||
|
||||
columns += [
|
||||
_("Customer Group") + ":Link/Customer Group:120",
|
||||
_("Receivable Account") + ":Link/Account:120",
|
||||
_("Mode of Payment") + "::120", _("Territory") + ":Link/Territory:80",
|
||||
_("Project") + ":Link/Project:80", _("Company") + ":Link/Company:100",
|
||||
_("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100",
|
||||
_("Income Account") + ":Link/Account:140", _("Cost Center") + ":Link/Cost Center:140",
|
||||
_("Stock Qty") + ":Float:120", _("Stock UOM") + "::100",
|
||||
_("Rate") + ":Currency/currency:120",
|
||||
_("Amount") + ":Currency/currency:120"
|
||||
{
|
||||
'label': _('Receivable Account'),
|
||||
'fieldname': 'debit_to',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Account',
|
||||
'width': 80
|
||||
},
|
||||
{
|
||||
'label': _('Mode Of Payment'),
|
||||
'fieldname': 'mode_of_payment',
|
||||
'fieldtype': 'Data',
|
||||
'width': 120
|
||||
}
|
||||
]
|
||||
|
||||
if filters.get('group_by') != 'Terriotory':
|
||||
columns.extend([
|
||||
{
|
||||
'label': _("Territory"),
|
||||
'fieldname': 'territory',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Territory',
|
||||
'width': 80
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
columns += [
|
||||
{
|
||||
'label': _('Project'),
|
||||
'fieldname': 'project',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Project',
|
||||
'width': 80
|
||||
},
|
||||
{
|
||||
'label': _('Company'),
|
||||
'fieldname': 'company',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Company',
|
||||
'width': 80
|
||||
},
|
||||
{
|
||||
'label': _('Sales Order'),
|
||||
'fieldname': 'sales_order',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Sales Order',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _("Delivery Note"),
|
||||
'fieldname': 'delivery_note',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Delivery Note',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _('Income Account'),
|
||||
'fieldname': 'income_account',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Account',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _("Cost Center"),
|
||||
'fieldname': 'cost_center',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Cost Center',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _('Stock Qty'),
|
||||
'fieldname': 'stock_qty',
|
||||
'fieldtype': 'Float',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _('Stock UOM'),
|
||||
'fieldname': 'stock_uom',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'UOM',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _('Rate'),
|
||||
'fieldname': 'rate',
|
||||
'fieldtype': 'Float',
|
||||
'options': 'currency',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _('Amount'),
|
||||
'fieldname': 'amount',
|
||||
'fieldtype': 'Currency',
|
||||
'options': 'currency',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'fieldname': 'currency',
|
||||
'label': _('Currency'),
|
||||
'fieldtype': 'Currency',
|
||||
'width': 80,
|
||||
'hidden': 1
|
||||
}
|
||||
]
|
||||
|
||||
if filters.get('group_by'):
|
||||
columns.append({
|
||||
'label': _('% Of Grand Total'),
|
||||
'fieldname': 'percent_gt',
|
||||
'fieldtype': 'Float',
|
||||
'width': 80
|
||||
})
|
||||
|
||||
return columns
|
||||
|
||||
def get_conditions(filters):
|
||||
@@ -112,33 +342,39 @@ def get_conditions(filters):
|
||||
and ifnull(`tabSales Invoice Payment`.mode_of_payment, '') = %(mode_of_payment)s)"""
|
||||
|
||||
if filters.get("warehouse"):
|
||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
||||
where parent=`tabSales Invoice`.name
|
||||
and ifnull(`tabSales Invoice Item`.warehouse, '') = %(warehouse)s)"""
|
||||
conditions += """and ifnull(`tabSales Invoice Item`.warehouse, '') = %(warehouse)s"""
|
||||
|
||||
|
||||
if filters.get("brand"):
|
||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
||||
where parent=`tabSales Invoice`.name
|
||||
and ifnull(`tabSales Invoice Item`.brand, '') = %(brand)s)"""
|
||||
conditions += """and ifnull(`tabSales Invoice Item`.brand, '') = %(brand)s"""
|
||||
|
||||
if filters.get("item_group"):
|
||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
||||
where parent=`tabSales Invoice`.name
|
||||
and ifnull(`tabSales Invoice Item`.item_group, '') = %(item_group)s)"""
|
||||
conditions += """and ifnull(`tabSales Invoice Item`.item_group, '') = %(item_group)s"""
|
||||
|
||||
if not filters.get("group_by"):
|
||||
conditions += "ORDER BY `tabSales Invoice`.posting_date desc, `tabSales Invoice Item`.item_group desc"
|
||||
else:
|
||||
conditions += get_group_by_conditions(filters, 'Sales Invoice')
|
||||
|
||||
return conditions
|
||||
|
||||
def get_group_by_conditions(filters, doctype):
|
||||
if filters.get("group_by") == 'Invoice':
|
||||
return "ORDER BY `tab{0} Item`.parent desc".format(doctype)
|
||||
elif filters.get("group_by") == 'Item':
|
||||
return "ORDER BY `tab{0} Item`.`item_code`".format(doctype)
|
||||
elif filters.get("group_by") == 'Item Group':
|
||||
return "ORDER BY `tab{0} Item`.{1}".format(doctype, frappe.scrub(filters.get('group_by')))
|
||||
elif filters.get("group_by") in ('Customer', 'Customer Group', 'Territory', 'Supplier'):
|
||||
return "ORDER BY `tab{0}`.{1}".format(doctype, frappe.scrub(filters.get('group_by')))
|
||||
|
||||
def get_items(filters, additional_query_columns):
|
||||
conditions = get_conditions(filters)
|
||||
match_conditions = frappe.build_match_conditions("Sales Invoice")
|
||||
|
||||
if match_conditions:
|
||||
match_conditions = " and {0} ".format(match_conditions)
|
||||
|
||||
if additional_query_columns:
|
||||
additional_query_columns = ', ' + ', '.join(additional_query_columns)
|
||||
else:
|
||||
additional_query_columns = ''
|
||||
|
||||
return frappe.db.sql("""
|
||||
select
|
||||
@@ -156,9 +392,8 @@ def get_items(filters, additional_query_columns):
|
||||
`tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0}
|
||||
from `tabSales Invoice`, `tabSales Invoice Item`
|
||||
where `tabSales Invoice`.name = `tabSales Invoice Item`.parent
|
||||
and `tabSales Invoice`.docstatus = 1 %s %s
|
||||
order by `tabSales Invoice`.posting_date desc, `tabSales Invoice Item`.item_code desc
|
||||
""".format(additional_query_columns or '') % (conditions, match_conditions), filters, as_dict=1)
|
||||
and `tabSales Invoice`.docstatus = 1 {1}
|
||||
""".format(additional_query_columns or '', conditions), filters, as_dict=1) #nosec
|
||||
|
||||
def get_delivery_notes_against_sales_order(item_list):
|
||||
so_dn_map = frappe._dict()
|
||||
@@ -177,6 +412,15 @@ def get_delivery_notes_against_sales_order(item_list):
|
||||
|
||||
return so_dn_map
|
||||
|
||||
def get_grand_total(filters, doctype):
|
||||
|
||||
return frappe.db.sql(""" SELECT
|
||||
SUM(`tab{0}`.base_grand_total)
|
||||
FROM `tab{0}`
|
||||
WHERE `tab{0}`.docstatus = 1
|
||||
and posting_date between %s and %s
|
||||
""".format(doctype), (filters.get('from_date'), filters.get('to_date')))[0][0] #nosec
|
||||
|
||||
def get_deducted_taxes():
|
||||
return frappe.db.sql_list("select name from `tabPurchase Taxes and Charges` where add_deduct_tax = 'Deduct'")
|
||||
|
||||
@@ -264,9 +508,117 @@ def get_tax_accounts(item_list, columns, company_currency,
|
||||
|
||||
tax_columns.sort()
|
||||
for desc in tax_columns:
|
||||
columns.append(desc + " Rate:Data:80")
|
||||
columns.append(desc + " Amount:Currency/currency:100")
|
||||
columns.append({
|
||||
'label': _(desc + ' Rate'),
|
||||
'fieldname': frappe.scrub(desc + ' Rate'),
|
||||
'fieldtype': 'Float',
|
||||
'width': 100
|
||||
})
|
||||
|
||||
columns += ["Total Tax:Currency/currency:80", "Total:Currency/currency:100"]
|
||||
columns.append({
|
||||
'label': _(desc + ' Amount'),
|
||||
'fieldname': frappe.scrub(desc + ' Amount'),
|
||||
'fieldtype': 'Currency',
|
||||
'options': 'currency',
|
||||
'width': 100
|
||||
})
|
||||
|
||||
columns += [
|
||||
{
|
||||
'label': _('Total Tax'),
|
||||
'fieldname': 'total_tax',
|
||||
'fieldtype': 'Currency',
|
||||
'options': 'currency',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _('Total'),
|
||||
'fieldname': 'total',
|
||||
'fieldtype': 'Currency',
|
||||
'options': 'currency',
|
||||
'width': 100
|
||||
}
|
||||
]
|
||||
|
||||
return itemised_tax, tax_columns
|
||||
|
||||
def add_total_row(data, filters, prev_group_by_value, item, total_row_map,
|
||||
group_by_field, subtotal_display_field, grand_total, tax_columns):
|
||||
if prev_group_by_value != item.get(group_by_field, ''):
|
||||
if prev_group_by_value:
|
||||
total_row = total_row_map.get(prev_group_by_value)
|
||||
data.append(total_row)
|
||||
data.append({})
|
||||
add_sub_total_row(total_row, total_row_map, 'total_row', tax_columns)
|
||||
|
||||
prev_group_by_value = item.get(group_by_field, '')
|
||||
|
||||
total_row_map.setdefault(item.get(group_by_field, ''), {
|
||||
subtotal_display_field: get_display_value(filters, group_by_field, item),
|
||||
'stock_qty': 0.0,
|
||||
'amount': 0.0,
|
||||
'bold': 1,
|
||||
'total_tax': 0.0,
|
||||
'total': 0.0,
|
||||
'percent_gt': 0.0
|
||||
})
|
||||
|
||||
total_row_map.setdefault('total_row', {
|
||||
subtotal_display_field: "Total",
|
||||
'stock_qty': 0.0,
|
||||
'amount': 0.0,
|
||||
'bold': 1,
|
||||
'total_tax': 0.0,
|
||||
'total': 0.0,
|
||||
'percent_gt': 0.0
|
||||
})
|
||||
|
||||
return data, prev_group_by_value
|
||||
|
||||
def get_display_value(filters, group_by_field, item):
|
||||
if filters.get('group_by') == 'Item':
|
||||
if item.get('item_code') != item.get('item_name'):
|
||||
value = cstr(item.get('item_code')) + "<br><br>" + \
|
||||
"<span style='font-weight: normal'>" + cstr(item.get('item_name')) + "</span>"
|
||||
else:
|
||||
value = item.get('item_code', '')
|
||||
elif filters.get('group_by') in ('Customer', 'Supplier'):
|
||||
party = frappe.scrub(filters.get('group_by'))
|
||||
if item.get(party) != item.get(party+'_name'):
|
||||
value = item.get(party) + "<br><br>" + \
|
||||
"<span style='font-weight: normal'>" + item.get(party+'_name') + "</span>"
|
||||
else:
|
||||
value = item.get(party)
|
||||
else:
|
||||
value = item.get(group_by_field)
|
||||
|
||||
return value
|
||||
|
||||
def get_group_by_and_display_fields(filters):
|
||||
if filters.get('group_by') == 'Item':
|
||||
group_by_field = 'item_code'
|
||||
subtotal_display_field = 'invoice'
|
||||
elif filters.get('group_by') == 'Invoice':
|
||||
group_by_field = 'parent'
|
||||
subtotal_display_field = 'item_code'
|
||||
else:
|
||||
group_by_field = frappe.scrub(filters.get('group_by'))
|
||||
subtotal_display_field = 'item_code'
|
||||
|
||||
return group_by_field, subtotal_display_field
|
||||
|
||||
def add_sub_total_row(item, total_row_map, group_by_value, tax_columns):
|
||||
total_row = total_row_map.get(group_by_value)
|
||||
total_row['stock_qty'] += item['stock_qty']
|
||||
total_row['amount'] += item['amount']
|
||||
total_row['total_tax'] += item['total_tax']
|
||||
total_row['total'] += item['total']
|
||||
total_row['percent_gt'] += item['percent_gt']
|
||||
|
||||
for tax in tax_columns:
|
||||
total_row.setdefault(frappe.scrub(tax + ' Amount'), 0.0)
|
||||
total_row[frappe.scrub(tax + ' Amount')] += flt(item[frappe.scrub(tax + ' Amount')])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
{
|
||||
"fieldname": "include_default_book_entries",
|
||||
"label": __("Include Default Book Entries"),
|
||||
"fieldtype": "Check"
|
||||
"fieldtype": "Check",
|
||||
"default": 1
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import frappe
|
||||
from frappe.utils import flt
|
||||
from frappe import msgprint, _
|
||||
from frappe.model.meta import get_field_precision
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children
|
||||
|
||||
def execute(filters=None):
|
||||
return _execute(filters)
|
||||
@@ -38,32 +38,46 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
|
||||
cost_center = list(set(invoice_cc_wh_map.get(inv.name, {}).get("cost_center", [])))
|
||||
warehouse = list(set(invoice_cc_wh_map.get(inv.name, {}).get("warehouse", [])))
|
||||
|
||||
row = [
|
||||
inv.name, inv.posting_date, inv.customer, inv.customer_name
|
||||
]
|
||||
row = {
|
||||
'invoice': inv.name,
|
||||
'posting_date': inv.posting_date,
|
||||
'customer': inv.customer,
|
||||
'customer_name': inv.customer_name
|
||||
}
|
||||
|
||||
if additional_query_columns:
|
||||
for col in additional_query_columns:
|
||||
row.append(inv.get(col))
|
||||
row.update({
|
||||
col: inv.get(col)
|
||||
})
|
||||
|
||||
row.update({
|
||||
'customer_group': inv.get("customer_group"),
|
||||
'territory': inv.get("territory"),
|
||||
'tax_id': inv.get("tax_id"),
|
||||
'receivable_account': inv.debit_to,
|
||||
'mode_of_payment': ", ".join(mode_of_payments.get(inv.name, [])),
|
||||
'project': inv.project,
|
||||
'owner': inv.owner,
|
||||
'remarks': inv.remarks,
|
||||
'sales_order': ", ".join(sales_order),
|
||||
'delivery_note': ", ".join(delivery_note),
|
||||
'cost_center': ", ".join(cost_center),
|
||||
'warehouse': ", ".join(warehouse),
|
||||
'currency': company_currency
|
||||
})
|
||||
|
||||
row +=[
|
||||
inv.get("customer_group"),
|
||||
inv.get("territory"),
|
||||
inv.get("tax_id"),
|
||||
inv.debit_to, ", ".join(mode_of_payments.get(inv.name, [])),
|
||||
inv.project, inv.owner, inv.remarks,
|
||||
", ".join(sales_order), ", ".join(delivery_note),", ".join(cost_center),
|
||||
", ".join(warehouse), company_currency
|
||||
]
|
||||
# map income values
|
||||
base_net_total = 0
|
||||
for income_acc in income_accounts:
|
||||
income_amount = flt(invoice_income_map.get(inv.name, {}).get(income_acc))
|
||||
base_net_total += income_amount
|
||||
row.append(income_amount)
|
||||
row.update({
|
||||
frappe.scrub(income_acc): income_amount
|
||||
})
|
||||
|
||||
# net total
|
||||
row.append(base_net_total or inv.base_net_total)
|
||||
row.update({'net_total': base_net_total or inv.base_net_total})
|
||||
|
||||
# tax account
|
||||
total_tax = 0
|
||||
@@ -72,10 +86,18 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
|
||||
tax_amount_precision = get_field_precision(frappe.get_meta("Sales Taxes and Charges").get_field("tax_amount"), currency=company_currency) or 2
|
||||
tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision)
|
||||
total_tax += tax_amount
|
||||
row.append(tax_amount)
|
||||
row.update({
|
||||
frappe.scrub(tax_acc): tax_amount
|
||||
})
|
||||
|
||||
# total tax, grand total, outstanding amount & rounded total
|
||||
row += [total_tax, inv.base_grand_total, inv.base_rounded_total, inv.outstanding_amount]
|
||||
|
||||
row.update({
|
||||
'tax_total': total_tax,
|
||||
'grand_total': inv.base_grand_total,
|
||||
'rounded_total': inv.base_rounded_total,
|
||||
'outstanding_amount': inv.outstanding_amount
|
||||
})
|
||||
|
||||
data.append(row)
|
||||
|
||||
@@ -84,19 +106,118 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
|
||||
def get_columns(invoice_list, additional_table_columns):
|
||||
"""return columns based on filters"""
|
||||
columns = [
|
||||
_("Invoice") + ":Link/Sales Invoice:120", _("Posting Date") + ":Date:80",
|
||||
_("Customer") + ":Link/Customer:120", _("Customer Name") + "::120"
|
||||
{
|
||||
'label': _("Invoice"),
|
||||
'fieldname': 'invoice',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Sales Invoice',
|
||||
'width': 120
|
||||
},
|
||||
{
|
||||
'label': _("Posting Date"),
|
||||
'fieldname': 'posting_date',
|
||||
'fieldtype': 'Date',
|
||||
'width': 80
|
||||
},
|
||||
{
|
||||
'label': _("Customer"),
|
||||
'fieldname': 'customer',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Customer',
|
||||
'width': 120
|
||||
},
|
||||
{
|
||||
'label': _("Customer Name"),
|
||||
'fieldname': 'customer_name',
|
||||
'fieldtype': 'Data',
|
||||
'width': 120
|
||||
},
|
||||
]
|
||||
|
||||
if additional_table_columns:
|
||||
columns += additional_table_columns
|
||||
|
||||
columns +=[
|
||||
_("Customer Group") + ":Link/Customer Group:120", _("Territory") + ":Link/Territory:80",
|
||||
_("Tax Id") + "::80", _("Receivable Account") + ":Link/Account:120", _("Mode of Payment") + "::120",
|
||||
_("Project") +":Link/Project:80", _("Owner") + "::150", _("Remarks") + "::150",
|
||||
_("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100",
|
||||
_("Cost Center") + ":Link/Cost Center:100", _("Warehouse") + ":Link/Warehouse:100",
|
||||
{
|
||||
'label': _("Customer Group"),
|
||||
'fieldname': 'customer_group',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Customer Group',
|
||||
'width': 120
|
||||
},
|
||||
{
|
||||
'label': _("Territory"),
|
||||
'fieldname': 'territory',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Territory',
|
||||
'width': 80
|
||||
},
|
||||
{
|
||||
'label': _("Tax Id"),
|
||||
'fieldname': 'tax_id',
|
||||
'fieldtype': 'Data',
|
||||
'width': 120
|
||||
},
|
||||
{
|
||||
'label': _("Receivable Account"),
|
||||
'fieldname': 'receivable_account',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Account',
|
||||
'width': 80
|
||||
},
|
||||
{
|
||||
'label': _("Mode Of Payment"),
|
||||
'fieldname': 'mode_of_payment',
|
||||
'fieldtype': 'Data',
|
||||
'width': 120
|
||||
},
|
||||
{
|
||||
'label': _("Project"),
|
||||
'fieldname': 'project',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Project',
|
||||
'width': 80
|
||||
},
|
||||
{
|
||||
'label': _("Owner"),
|
||||
'fieldname': 'owner',
|
||||
'fieldtype': 'Data',
|
||||
'width': 150
|
||||
},
|
||||
{
|
||||
'label': _("Remarks"),
|
||||
'fieldname': 'remarks',
|
||||
'fieldtype': 'Data',
|
||||
'width': 150
|
||||
},
|
||||
{
|
||||
'label': _("Sales Order"),
|
||||
'fieldname': 'sales_order',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Sales Order',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _("Delivery Note"),
|
||||
'fieldname': 'delivery_note',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Delivery Note',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _("Cost Center"),
|
||||
'fieldname': 'cost_center',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Cost Center',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'label': _("Warehouse"),
|
||||
'fieldname': 'warehouse',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Warehouse',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
"fieldname": "currency",
|
||||
"label": _("Currency"),
|
||||
@@ -105,7 +226,10 @@ def get_columns(invoice_list, additional_table_columns):
|
||||
}
|
||||
]
|
||||
|
||||
income_accounts = tax_accounts = income_columns = tax_columns = []
|
||||
income_accounts = []
|
||||
tax_accounts = []
|
||||
income_columns = []
|
||||
tax_columns = []
|
||||
|
||||
if invoice_list:
|
||||
income_accounts = frappe.db.sql_list("""select distinct income_account
|
||||
@@ -119,14 +243,65 @@ def get_columns(invoice_list, additional_table_columns):
|
||||
and parent in (%s) order by account_head""" %
|
||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
|
||||
|
||||
income_columns = [(account + ":Currency/currency:120") for account in income_accounts]
|
||||
for account in income_accounts:
|
||||
income_columns.append({
|
||||
"label": account,
|
||||
"fieldname": frappe.scrub(account),
|
||||
"fieldtype": "Currency",
|
||||
"options": 'currency',
|
||||
"width": 120
|
||||
})
|
||||
|
||||
for account in tax_accounts:
|
||||
if account not in income_accounts:
|
||||
tax_columns.append(account + ":Currency/currency:120")
|
||||
tax_columns.append({
|
||||
"label": account,
|
||||
"fieldname": frappe.scrub(account),
|
||||
"fieldtype": "Currency",
|
||||
"options": 'currency',
|
||||
"width": 120
|
||||
})
|
||||
|
||||
columns = columns + income_columns + [_("Net Total") + ":Currency/currency:120"] + tax_columns + \
|
||||
[_("Total Tax") + ":Currency/currency:120", _("Grand Total") + ":Currency/currency:120",
|
||||
_("Rounded Total") + ":Currency/currency:120", _("Outstanding Amount") + ":Currency/currency:120"]
|
||||
net_total_column = [{
|
||||
"label": _("Net Total"),
|
||||
"fieldname": "net_total",
|
||||
"fieldtype": "Currency",
|
||||
"options": 'currency',
|
||||
"width": 120
|
||||
}]
|
||||
|
||||
total_columns = [
|
||||
{
|
||||
"label": _("Tax Total"),
|
||||
"fieldname": "tax_total",
|
||||
"fieldtype": "Currency",
|
||||
"options": 'currency',
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"label": _("Grand Total"),
|
||||
"fieldname": "grand_total",
|
||||
"fieldtype": "Currency",
|
||||
"options": 'currency',
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"label": _("Rounded Total"),
|
||||
"fieldname": "rounded_total",
|
||||
"fieldtype": "Currency",
|
||||
"options": 'currency',
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"label": _("Outstanding Amount"),
|
||||
"fieldname": "outstanding_amount",
|
||||
"fieldtype": "Currency",
|
||||
"options": 'currency',
|
||||
"width": 120
|
||||
}
|
||||
]
|
||||
|
||||
columns = columns + income_columns + net_total_column + tax_columns + total_columns
|
||||
|
||||
return columns, income_accounts, tax_accounts
|
||||
|
||||
@@ -166,14 +341,18 @@ def get_conditions(filters):
|
||||
where parent=`tabSales Invoice`.name
|
||||
and ifnull(`tabSales Invoice Item`.item_group, '') = %(item_group)s)"""
|
||||
|
||||
accounting_dimensions = get_accounting_dimensions()
|
||||
accounting_dimensions = get_accounting_dimensions(as_list=False)
|
||||
|
||||
if accounting_dimensions:
|
||||
for dimension in accounting_dimensions:
|
||||
if filters.get(dimension):
|
||||
if filters.get(dimension.fieldname):
|
||||
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
||||
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
||||
filters.get(dimension.fieldname))
|
||||
|
||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
||||
where parent=`tabSales Invoice`.name
|
||||
and ifnull(`tabSales Invoice Item`.{0}, '') = %({0})s)""".format(dimension)
|
||||
and ifnull(`tabSales Invoice Item`.{0}, '') in %({0})s)""".format(dimension.fieldname)
|
||||
|
||||
|
||||
return conditions
|
||||
|
||||
@@ -85,7 +85,8 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
{
|
||||
"fieldname": "include_default_book_entries",
|
||||
"label": __("Include Default Book Entries"),
|
||||
"fieldtype": "Check"
|
||||
"fieldtype": "Check",
|
||||
"default": 1
|
||||
}
|
||||
],
|
||||
"formatter": erpnext.financial_statements.formatter,
|
||||
|
||||
@@ -7,7 +7,7 @@ from frappe import _
|
||||
from frappe.utils import flt, getdate, formatdate, cstr
|
||||
from erpnext.accounts.report.financial_statements \
|
||||
import filter_accounts, set_gl_entries_by_account, filter_out_zero_value_rows
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children
|
||||
|
||||
value_fields = ("opening_debit", "opening_credit", "debit", "credit", "closing_debit", "closing_credit")
|
||||
|
||||
@@ -103,13 +103,13 @@ def get_rootwise_opening_balances(filters, report_type):
|
||||
where lft >= %s and rgt <= %s)""" % (lft, rgt)
|
||||
|
||||
if filters.finance_book:
|
||||
fb_conditions = " and finance_book = %(finance_book)s"
|
||||
fb_conditions = " AND finance_book = %(finance_book)s"
|
||||
if filters.include_default_book_entries:
|
||||
fb_conditions = " and (finance_book in (%(finance_book)s, %(company_fb)s))"
|
||||
fb_conditions = " AND (finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)"
|
||||
|
||||
additional_conditions += fb_conditions
|
||||
|
||||
accounting_dimensions = get_accounting_dimensions()
|
||||
accounting_dimensions = get_accounting_dimensions(as_list=False)
|
||||
|
||||
query_filters = {
|
||||
"company": filters.company,
|
||||
@@ -122,11 +122,14 @@ def get_rootwise_opening_balances(filters, report_type):
|
||||
|
||||
if accounting_dimensions:
|
||||
for dimension in accounting_dimensions:
|
||||
if filters.get(dimension):
|
||||
additional_conditions += """ and {0} in (%({0})s) """.format(dimension)
|
||||
if filters.get(dimension.fieldname):
|
||||
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
||||
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
||||
filters.get(dimension.fieldname))
|
||||
additional_conditions += "and {0} in %({0})s".format(dimension.fieldname)
|
||||
|
||||
query_filters.update({
|
||||
dimension: filters.get(dimension)
|
||||
dimension.fieldname: filters.get(dimension.fieldname)
|
||||
})
|
||||
|
||||
gle = frappe.db.sql("""
|
||||
|
||||
@@ -65,6 +65,21 @@ frappe.query_reports["Trial Balance for Party"] = {
|
||||
return party_type;
|
||||
}
|
||||
},
|
||||
{
|
||||
"fieldname": "account",
|
||||
"label": __("Account"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Account",
|
||||
"get_query": function() {
|
||||
var company = frappe.query_report.get_filter_value('company');
|
||||
return {
|
||||
"doctype": "Account",
|
||||
"filters": {
|
||||
"company": company,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"fieldname": "show_zero_values",
|
||||
"label": __("Show zero values"),
|
||||
|
||||
@@ -18,14 +18,17 @@ def execute(filters=None):
|
||||
return columns, data
|
||||
|
||||
def get_data(filters, show_party_name):
|
||||
party_name_field = "{0}_name".format(frappe.scrub(filters.get('party_type')))
|
||||
if filters.get('party_type') == 'Student':
|
||||
if filters.get('party_type') in ('Customer', 'Supplier', 'Employee', 'Member'):
|
||||
party_name_field = "{0}_name".format(frappe.scrub(filters.get('party_type')))
|
||||
elif filters.get('party_type') == 'Student':
|
||||
party_name_field = 'first_name'
|
||||
elif filters.get('party_type') == 'Shareholder':
|
||||
party_name_field = 'title'
|
||||
else:
|
||||
party_name_field = 'name'
|
||||
|
||||
party_filters = {"name": filters.get("party")} if filters.get("party") else {}
|
||||
parties = frappe.get_all(filters.get("party_type"), fields = ["name", party_name_field],
|
||||
parties = frappe.get_all(filters.get("party_type"), fields = ["name", party_name_field],
|
||||
filters = party_filters, order_by="name")
|
||||
company_currency = frappe.get_cached_value('Company', filters.company, "default_currency")
|
||||
opening_balances = get_opening_balances(filters)
|
||||
@@ -70,7 +73,7 @@ def get_data(filters, show_party_name):
|
||||
# totals
|
||||
for col in total_row:
|
||||
total_row[col] += row.get(col)
|
||||
|
||||
|
||||
row.update({
|
||||
"currency": company_currency
|
||||
})
|
||||
@@ -78,7 +81,7 @@ def get_data(filters, show_party_name):
|
||||
has_value = False
|
||||
if (opening_debit or opening_credit or debit or credit or closing_debit or closing_credit):
|
||||
has_value =True
|
||||
|
||||
|
||||
if cint(filters.show_zero_values) or has_value:
|
||||
data.append(row)
|
||||
|
||||
@@ -93,13 +96,19 @@ def get_data(filters, show_party_name):
|
||||
return data
|
||||
|
||||
def get_opening_balances(filters):
|
||||
|
||||
account_filter = ''
|
||||
if filters.get('account'):
|
||||
account_filter = "and account = %s" % (frappe.db.escape(filters.get('account')))
|
||||
|
||||
gle = frappe.db.sql("""
|
||||
select party, sum(debit) as opening_debit, sum(credit) as opening_credit
|
||||
select party, sum(debit) as opening_debit, sum(credit) as opening_credit
|
||||
from `tabGL Entry`
|
||||
where company=%(company)s
|
||||
where company=%(company)s
|
||||
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
|
||||
and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes')
|
||||
group by party""", {
|
||||
{account_filter}
|
||||
group by party""".format(account_filter=account_filter), {
|
||||
"company": filters.company,
|
||||
"from_date": filters.from_date,
|
||||
"party_type": filters.party_type
|
||||
@@ -113,14 +122,20 @@ def get_opening_balances(filters):
|
||||
return opening
|
||||
|
||||
def get_balances_within_period(filters):
|
||||
|
||||
account_filter = ''
|
||||
if filters.get('account'):
|
||||
account_filter = "and account = %s" % (frappe.db.escape(filters.get('account')))
|
||||
|
||||
gle = frappe.db.sql("""
|
||||
select party, sum(debit) as debit, sum(credit) as credit
|
||||
select party, sum(debit) as debit, sum(credit) as credit
|
||||
from `tabGL Entry`
|
||||
where company=%(company)s
|
||||
where company=%(company)s
|
||||
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
|
||||
and posting_date >= %(from_date)s and posting_date <= %(to_date)s
|
||||
and posting_date >= %(from_date)s and posting_date <= %(to_date)s
|
||||
and ifnull(is_opening, 'No') = 'No'
|
||||
group by party""", {
|
||||
{account_filter}
|
||||
group by party""".format(account_filter=account_filter), {
|
||||
"company": filters.company,
|
||||
"from_date": filters.from_date,
|
||||
"to_date": filters.to_date,
|
||||
|
||||
@@ -569,7 +569,7 @@ def get_stock_and_account_balance(account=None, posting_date=None, company=None)
|
||||
|
||||
warehouse_account = get_warehouse_account_map(company)
|
||||
|
||||
account_balance = get_balance_on(account, posting_date, in_account_currency=False)
|
||||
account_balance = get_balance_on(account, posting_date, in_account_currency=False, ignore_account_permission=True)
|
||||
|
||||
related_warehouses = [wh for wh, wh_details in warehouse_account.items()
|
||||
if wh_details.account == account and not wh_details.is_group]
|
||||
@@ -640,8 +640,9 @@ def get_outstanding_invoices(party_type, party, account, condition=None, filters
|
||||
precision = frappe.get_precision("Sales Invoice", "outstanding_amount") or 2
|
||||
|
||||
if account:
|
||||
root_type = frappe.get_cached_value("Account", account, "root_type")
|
||||
root_type, account_type = frappe.get_cached_value("Account", account, ["root_type", "account_type"])
|
||||
party_account_type = "Receivable" if root_type == "Asset" else "Payable"
|
||||
party_account_type = account_type or party_account_type
|
||||
else:
|
||||
party_account_type = erpnext.get_party_account_type(party_type)
|
||||
|
||||
@@ -891,3 +892,9 @@ def get_allow_cost_center_in_entry_of_bs_account():
|
||||
def generator():
|
||||
return cint(frappe.db.get_value('Accounts Settings', None, 'allow_cost_center_in_entry_of_bs_account'))
|
||||
return frappe.local_cache("get_allow_cost_center_in_entry_of_bs_account", (), generator, regenerate_if_none=True)
|
||||
|
||||
def get_stock_accounts(company):
|
||||
return frappe.get_all("Account", filters = {
|
||||
"account_type": "Stock",
|
||||
"company": company
|
||||
})
|
||||
@@ -144,6 +144,10 @@ frappe.ui.form.on('Asset', {
|
||||
frm.set_df_property('purchase_invoice', 'read_only', 1);
|
||||
frm.set_df_property('purchase_receipt', 'read_only', 1);
|
||||
}
|
||||
else if (frm.doc.is_existing_asset) {
|
||||
frm.toggle_reqd('purchase_receipt', 0);
|
||||
frm.toggle_reqd('purchase_invoice', 0);
|
||||
}
|
||||
else if (frm.doc.purchase_receipt) {
|
||||
// if purchase receipt link is set then set PI disabled
|
||||
frm.toggle_reqd('purchase_invoice', 0);
|
||||
@@ -256,6 +260,7 @@ frappe.ui.form.on('Asset', {
|
||||
},
|
||||
|
||||
is_existing_asset: function(frm) {
|
||||
frm.trigger("toggle_reference_doc");
|
||||
// frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation));
|
||||
},
|
||||
|
||||
@@ -333,25 +338,12 @@ frappe.ui.form.on('Asset', {
|
||||
})
|
||||
},
|
||||
|
||||
purchase_receipt: function(frm) {
|
||||
purchase_receipt: (frm) => {
|
||||
frm.trigger('toggle_reference_doc');
|
||||
|
||||
if (frm.doc.purchase_receipt) {
|
||||
if (frm.doc.item_code) {
|
||||
frappe.db.get_doc('Purchase Receipt', frm.doc.purchase_receipt).then(pr_doc => {
|
||||
frm.set_value('company', pr_doc.company);
|
||||
frm.set_value('purchase_date', pr_doc.posting_date);
|
||||
const item = pr_doc.items.find(item => item.item_code === frm.doc.item_code);
|
||||
if (!item) {
|
||||
frm.set_value('purchase_receipt', '');
|
||||
frappe.msgprint({
|
||||
title: __('Invalid Purchase Receipt'),
|
||||
message: __("The selected Purchase Receipt doesn't contains selected Asset Item."),
|
||||
indicator: 'red'
|
||||
});
|
||||
}
|
||||
frm.set_value('gross_purchase_amount', item.base_net_rate);
|
||||
frm.set_value('location', item.asset_location);
|
||||
frm.events.set_values_from_purchase_doc(frm, 'Purchase Receipt', pr_doc)
|
||||
});
|
||||
} else {
|
||||
frm.set_value('purchase_receipt', '');
|
||||
@@ -363,24 +355,12 @@ frappe.ui.form.on('Asset', {
|
||||
}
|
||||
},
|
||||
|
||||
purchase_invoice: function(frm) {
|
||||
purchase_invoice: (frm) => {
|
||||
frm.trigger('toggle_reference_doc');
|
||||
if (frm.doc.purchase_invoice) {
|
||||
if (frm.doc.item_code) {
|
||||
frappe.db.get_doc('Purchase Invoice', frm.doc.purchase_invoice).then(pi_doc => {
|
||||
frm.set_value('company', pi_doc.company);
|
||||
frm.set_value('purchase_date', pi_doc.posting_date);
|
||||
const item = pi_doc.items.find(item => item.item_code === frm.doc.item_code);
|
||||
if (!item) {
|
||||
frm.set_value('purchase_invoice', '');
|
||||
frappe.msgprint({
|
||||
title: __('Invalid Purchase Invoice'),
|
||||
message: __("The selected Purchase Invoice doesn't contains selected Asset Item."),
|
||||
indicator: 'red'
|
||||
});
|
||||
}
|
||||
frm.set_value('gross_purchase_amount', item.base_net_rate);
|
||||
frm.set_value('location', item.asset_location);
|
||||
frm.events.set_values_from_purchase_doc(frm, 'Purchase Invoice', pi_doc)
|
||||
});
|
||||
} else {
|
||||
frm.set_value('purchase_invoice', '');
|
||||
@@ -392,6 +372,24 @@ frappe.ui.form.on('Asset', {
|
||||
}
|
||||
},
|
||||
|
||||
set_values_from_purchase_doc: function(frm, doctype, purchase_doc) {
|
||||
frm.set_value('company', purchase_doc.company);
|
||||
frm.set_value('purchase_date', purchase_doc.posting_date);
|
||||
const item = purchase_doc.items.find(item => item.item_code === frm.doc.item_code);
|
||||
if (!item) {
|
||||
doctype_field = frappe.scrub(doctype)
|
||||
frm.set_value(doctype_field, '');
|
||||
frappe.msgprint({
|
||||
title: __(`Invalid ${doctype}`),
|
||||
message: __(`The selected ${doctype} doesn't contains selected Asset Item.`),
|
||||
indicator: 'red'
|
||||
});
|
||||
}
|
||||
frm.set_value('gross_purchase_amount', item.base_net_rate + item.item_tax_amount);
|
||||
frm.set_value('purchase_receipt_amount', item.base_net_rate + item.item_tax_amount);
|
||||
frm.set_value('location', item.asset_location);
|
||||
},
|
||||
|
||||
set_depreciation_rate: function(frm, row) {
|
||||
if (row.total_number_of_depreciations && row.frequency_of_depreciation
|
||||
&& row.expected_value_after_useful_life) {
|
||||
|
||||
@@ -132,9 +132,10 @@ class Asset(AccountsController):
|
||||
if len(movements) > 1:
|
||||
frappe.throw(_('Asset has multiple Asset Movement Entries which has to be \
|
||||
cancelled manually to cancel this asset.'))
|
||||
movement = frappe.get_doc('Asset Movement', movements[0].get('name'))
|
||||
movement.flags.ignore_validate = True
|
||||
movement.cancel()
|
||||
if movements:
|
||||
movement = frappe.get_doc('Asset Movement', movements[0].get('name'))
|
||||
movement.flags.ignore_validate = True
|
||||
movement.cancel()
|
||||
|
||||
def make_asset_movement(self):
|
||||
reference_doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice'
|
||||
@@ -517,15 +518,18 @@ def update_maintenance_status():
|
||||
asset.set_status('Out of Order')
|
||||
|
||||
def make_post_gl_entry():
|
||||
if not is_cwip_accounting_enabled(self.asset_category):
|
||||
return
|
||||
|
||||
assets = frappe.db.sql_list(""" select name from `tabAsset`
|
||||
where ifnull(booked_fixed_asset, 0) = 0 and available_for_use_date = %s""", nowdate())
|
||||
asset_categories = frappe.db.get_all('Asset Category', fields = ['name', 'enable_cwip_accounting'])
|
||||
|
||||
for asset in assets:
|
||||
doc = frappe.get_doc('Asset', asset)
|
||||
doc.make_gl_entries()
|
||||
for asset_category in asset_categories:
|
||||
if cint(asset_category.enable_cwip_accounting):
|
||||
assets = frappe.db.sql_list(""" select name from `tabAsset`
|
||||
where asset_category = %s and ifnull(booked_fixed_asset, 0) = 0
|
||||
and available_for_use_date = %s""", (asset_category.name, nowdate()))
|
||||
|
||||
for asset in assets:
|
||||
doc = frappe.get_doc('Asset', asset)
|
||||
doc.make_gl_entries()
|
||||
|
||||
def get_asset_naming_series():
|
||||
meta = frappe.get_meta('Asset')
|
||||
@@ -607,13 +611,19 @@ def get_asset_account(account_name, asset=None, asset_category=None, company=Non
|
||||
if asset:
|
||||
account = get_asset_category_account(account_name, asset=asset,
|
||||
asset_category = asset_category, company = company)
|
||||
|
||||
if not asset and not account:
|
||||
account = get_asset_category_account(account_name, asset_category = asset_category, company = company)
|
||||
|
||||
if not account:
|
||||
account = frappe.get_cached_value('Company', company, account_name)
|
||||
|
||||
if not account:
|
||||
frappe.throw(_("Set {0} in asset category {1} or company {2}")
|
||||
.format(account_name.replace('_', ' ').title(), asset_category, company))
|
||||
if not asset_category:
|
||||
frappe.throw(_("Set {0} in company {1}").format(account_name.replace('_', ' ').title(), company))
|
||||
else:
|
||||
frappe.throw(_("Set {0} in asset category {1} or company {2}")
|
||||
.format(account_name.replace('_', ' ').title(), asset_category, company))
|
||||
|
||||
return account
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user