mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-27 21:08:33 +00:00
Compare commits
1849 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd5b37dbb7 | ||
|
|
7e93e87244 | ||
|
|
02f4aa6db6 | ||
|
|
5fb4027375 | ||
|
|
3a67daa1fd | ||
|
|
7cd6022a0b | ||
|
|
67274d01e8 | ||
|
|
19d7e43b90 | ||
|
|
c8884257b9 | ||
|
|
4674fec320 | ||
|
|
c7f0ab8ed6 | ||
|
|
8b943af911 | ||
|
|
863eb86a1d | ||
|
|
e5fbebe126 | ||
|
|
d5676a87a8 | ||
|
|
73dff8993a | ||
|
|
0ef799dff8 | ||
|
|
e8476ef42a | ||
|
|
9fef6e1b68 | ||
|
|
37c51f5913 | ||
|
|
7e33d875e0 | ||
|
|
ab2e52ca07 | ||
|
|
dc0ea3fdb0 | ||
|
|
b65b525c44 | ||
|
|
4872417f86 | ||
|
|
c50f08a23a | ||
|
|
2d37bbedaa | ||
|
|
00f6f114e7 | ||
|
|
ca4789c9f7 | ||
|
|
d56bc81daf | ||
|
|
a14f72590d | ||
|
|
4b401f0573 | ||
|
|
5beee8af58 | ||
|
|
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 | ||
|
|
a791170f29 | ||
|
|
b5991e9264 | ||
|
|
fb1e87710b | ||
|
|
8d2b0d800c | ||
|
|
2515022377 | ||
|
|
5558ee8597 | ||
|
|
31a4fa5dd3 | ||
|
|
53a66ee386 | ||
|
|
0881557c7d | ||
|
|
9326fb78f2 | ||
|
|
ecc6b1917b | ||
|
|
a7d168c05f | ||
|
|
fc5d8fcd9f | ||
|
|
b84e56ebb5 | ||
|
|
565d3efcdf | ||
|
|
d63ad3bb5f | ||
|
|
f9dec5201f | ||
|
|
cf3a2f6579 | ||
|
|
032baeac5b | ||
|
|
e0912e4fcc | ||
|
|
4d12f8acab | ||
|
|
c856cb85d9 | ||
|
|
754c43f6c3 | ||
|
|
e0c9f3c282 | ||
|
|
3ec5eabaf6 | ||
|
|
f2752bf38c | ||
|
|
35e8d1e1d7 | ||
|
|
a9ff7df2e6 | ||
|
|
2fd6814cbf | ||
|
|
1ed1c4e6a4 | ||
|
|
cd3976f7d2 | ||
|
|
04e3a506e4 | ||
|
|
a077795581 | ||
|
|
eefc492ff4 | ||
|
|
c9203a1bee | ||
|
|
f37a46edea | ||
|
|
1919af2ff1 | ||
|
|
aff4a67954 | ||
|
|
b5c296da9e | ||
|
|
7ca472780b | ||
|
|
763660b2e4 | ||
|
|
6c368e2dfb | ||
|
|
b3354198f1 | ||
|
|
b10526dd86 | ||
|
|
fa42999314 | ||
|
|
290253fdd0 | ||
|
|
24cde55e28 | ||
|
|
49cd19d917 | ||
|
|
7af153da50 | ||
|
|
046137caa2 | ||
|
|
150c44b350 | ||
|
|
1a92eb14ed | ||
|
|
f5112905dc | ||
|
|
c4e6c42950 | ||
|
|
225d38e797 | ||
|
|
a831848074 | ||
|
|
eed30c6d8c | ||
|
|
6a743be1de | ||
|
|
4a28144941 | ||
|
|
5717a265b7 | ||
|
|
ae90ea9547 | ||
|
|
682956543e | ||
|
|
45e9dd9c51 | ||
|
|
fe2147a496 | ||
|
|
dbde140e46 | ||
|
|
c8e66a0f71 | ||
|
|
26c46282e8 | ||
|
|
95270ad14b | ||
|
|
616254d2a0 | ||
|
|
248585b5a1 | ||
|
|
c42312ea12 | ||
|
|
a85ddf2fb4 | ||
|
|
9db9edca2c | ||
|
|
238521c2bd | ||
|
|
353f73a153 | ||
|
|
c436d93303 | ||
|
|
e13b769813 | ||
|
|
3f854fce2e | ||
|
|
a998978415 | ||
|
|
2578d49b84 | ||
|
|
776ff2f75d | ||
|
|
f3ecfd8e58 | ||
|
|
539ea2cefb | ||
|
|
b9460ed22c | ||
|
|
ee69f707a9 | ||
|
|
0debcf9f2f | ||
|
|
9c1c4ef3dd | ||
|
|
8131f7657e | ||
|
|
6ef057a2a3 | ||
|
|
39eeac265b | ||
|
|
466702200f | ||
|
|
87c6718d90 | ||
|
|
d995609ffa | ||
|
|
f69b9a8c47 | ||
|
|
53b65ab8ed | ||
|
|
6424416886 | ||
|
|
28a7ce9a50 | ||
|
|
18fda5a571 | ||
|
|
16f6ca12a7 | ||
|
|
c74c5d5644 | ||
|
|
57bd1308eb | ||
|
|
0a23e1aea5 | ||
|
|
74bbcb539f | ||
|
|
f1e6387fab | ||
|
|
d545f6fb6b | ||
|
|
cf55c9c6da | ||
|
|
c9e8a1bf96 | ||
|
|
e942f99897 | ||
|
|
ec082754b4 | ||
|
|
d69d0e3046 | ||
|
|
511780a4d4 | ||
|
|
fc3b924d4d | ||
|
|
793ba8fc06 | ||
|
|
5503b6cff5 | ||
|
|
73616d6b33 | ||
|
|
95a6320459 | ||
|
|
1ad2d4a962 | ||
|
|
9ffa9d4a64 | ||
|
|
af7fe1937e | ||
|
|
3e515e704d | ||
|
|
94565d69d1 | ||
|
|
732d6afad5 | ||
|
|
d064505ebe | ||
|
|
ba8fc21594 | ||
|
|
3a72cb46bc | ||
|
|
082bfb8cb3 | ||
|
|
4006eb5277 | ||
|
|
ccd9b38463 | ||
|
|
c31808f5b2 | ||
|
|
6e6954cab8 | ||
|
|
b1e9fb9e14 | ||
|
|
67f191df4e | ||
|
|
5ea4328359 | ||
|
|
4d27b50437 | ||
|
|
c72e1f812d | ||
|
|
a92f060740 | ||
|
|
f25e2a29f7 | ||
|
|
cce000a6d0 | ||
|
|
db64c69dac | ||
|
|
f75ea952e3 | ||
|
|
ffbfaf7099 | ||
|
|
06c8129574 | ||
|
|
d00c59830e | ||
|
|
010714757c | ||
|
|
4fa6194009 | ||
|
|
29a2e16f62 | ||
|
|
3cc3b57926 | ||
|
|
929676fceb | ||
|
|
2689acfc8e | ||
|
|
39152f935c | ||
|
|
001ee5ee1b | ||
|
|
a227b9a9a6 | ||
|
|
8b2223ae5f | ||
|
|
f997b443e1 | ||
|
|
4c7ac65db1 | ||
|
|
88de00fb94 | ||
|
|
06c6f7cfd3 | ||
|
|
d3ed499854 | ||
|
|
32936024a0 | ||
|
|
8bd2d4d35e | ||
|
|
df75b7693a | ||
|
|
2f44480d69 | ||
|
|
090f9a3dc9 | ||
|
|
b81942404d | ||
|
|
d36c6068b2 | ||
|
|
e93dc9f1cd | ||
|
|
7a23057eab | ||
|
|
7aef9f3b43 | ||
|
|
a839510b33 | ||
|
|
62fbf37eb4 | ||
|
|
4a6c723310 | ||
|
|
015285c42f | ||
|
|
b455318f01 | ||
|
|
628701f1a5 | ||
|
|
bac50bc295 | ||
|
|
28c6a0aeb1 | ||
|
|
83100c9c84 | ||
|
|
0671ea8137 | ||
|
|
76b20a5fa4 | ||
|
|
15382a6f71 | ||
|
|
52d888de42 | ||
|
|
151853b887 | ||
|
|
51208b3f0b | ||
|
|
e37a67245e | ||
|
|
75db6f7073 | ||
|
|
1c44bb0982 | ||
|
|
fce8f36bb2 | ||
|
|
36520ef951 | ||
|
|
edba06038e | ||
|
|
a5776d16b4 | ||
|
|
7508896bfb | ||
|
|
a709ae894c | ||
|
|
02b9472152 | ||
|
|
1beed7db72 | ||
|
|
d743583bf4 | ||
|
|
0c12eded05 | ||
|
|
f67833f249 | ||
|
|
6a50c92087 | ||
|
|
e123ec6b45 | ||
|
|
01c19d3b93 | ||
|
|
dec5bead9c | ||
|
|
6f1d2eeffd | ||
|
|
f527713b89 | ||
|
|
57f2dce682 | ||
|
|
d1ee962d4b | ||
|
|
730c8a145d | ||
|
|
4d3dc87a1a | ||
|
|
167aa7655d | ||
|
|
05710804cf | ||
|
|
50b6976c67 | ||
|
|
7e2b030052 | ||
|
|
7091a2102c | ||
|
|
af18b2cdc5 | ||
|
|
b565e9ba64 | ||
|
|
e3bc213262 | ||
|
|
475d8e3cdc | ||
|
|
0bcf8b64f6 | ||
|
|
1bb5d01192 | ||
|
|
ebf46120ba | ||
|
|
e573bd9074 | ||
|
|
53ec8c6322 | ||
|
|
c82aed0718 | ||
|
|
97f6576213 | ||
|
|
54f33f4e5d | ||
|
|
3609872760 | ||
|
|
9378aacbe5 | ||
|
|
6de68c8671 | ||
|
|
957c9f5ff0 | ||
|
|
4701bc8bfc | ||
|
|
3cbd70a1d9 | ||
|
|
2ec7acb592 | ||
|
|
28710cdf99 | ||
|
|
45c18b3184 | ||
|
|
519ca54f53 | ||
|
|
77e4cf89f8 | ||
|
|
4a1d000c33 | ||
|
|
81c217584a | ||
|
|
a11e738801 | ||
|
|
e494144c96 | ||
|
|
60093d98b0 | ||
|
|
d1c530c564 | ||
|
|
7e9b90ad06 | ||
|
|
450da16dc2 | ||
|
|
139c20a736 | ||
|
|
1e754b161c | ||
|
|
8ed6772727 | ||
|
|
ad04d442a1 | ||
|
|
99c8245512 | ||
|
|
6bd6039496 | ||
|
|
c02cb6ca94 | ||
|
|
1545ee914a | ||
|
|
7b6ab9738d | ||
|
|
d8b64cd199 | ||
|
|
2e01573a40 | ||
|
|
fac4eb919b | ||
|
|
e0348c9ec8 | ||
|
|
66e5e16a2e | ||
|
|
d38f5374cb | ||
|
|
83c7b5b44b | ||
|
|
7638788c2f | ||
|
|
486a8f67a4 | ||
|
|
5c9d92eabf | ||
|
|
afa03fd654 | ||
|
|
d8abac3278 | ||
|
|
c8333d4b41 | ||
|
|
07b74533fe | ||
|
|
e127d937f7 | ||
|
|
da5bf5a7c4 | ||
|
|
be5c6e7aec | ||
|
|
0f0d6ce25c | ||
|
|
d0003408c4 | ||
|
|
846c03889e | ||
|
|
d2d0100c9a | ||
|
|
abbc08cb48 | ||
|
|
2a72d1fee4 | ||
|
|
b051fa37df | ||
|
|
bcf107b9f7 | ||
|
|
118f2c7d64 | ||
|
|
702f9f929b | ||
|
|
4f7885f1aa | ||
|
|
3270ba6d8c | ||
|
|
8728e94dbd | ||
|
|
379f38e1cd | ||
|
|
fba7cae2c9 | ||
|
|
88d2c97391 | ||
|
|
07b908c0c5 | ||
|
|
3dbef9de74 | ||
|
|
8916916a03 | ||
|
|
9942fcc8cb | ||
|
|
83b58352ce | ||
|
|
a8358f0342 | ||
|
|
8e7bb002e2 | ||
|
|
5e14660dda | ||
|
|
53794a9029 | ||
|
|
0c0604b7ee | ||
|
|
e6f86c934d | ||
|
|
07ae3abf34 | ||
|
|
970788c64e | ||
|
|
ce5200d700 | ||
|
|
9f483c1fa9 | ||
|
|
213785e6d5 | ||
|
|
8f67ef8a75 | ||
|
|
09a6868ccd | ||
|
|
e1f95c0529 | ||
|
|
8c1b88f156 | ||
|
|
7bdc612013 | ||
|
|
6d9a300a85 | ||
|
|
758635ab91 | ||
|
|
233c0bc779 | ||
|
|
5d0362669d | ||
|
|
1da236fdd2 | ||
|
|
962f4eb96c | ||
|
|
d5166861de | ||
|
|
d9e27b727f | ||
|
|
275f3f8b91 | ||
|
|
3f96306986 | ||
|
|
5ff377e2bb | ||
|
|
799f8d4f93 | ||
|
|
36c97c3128 | ||
|
|
453ad3c155 | ||
|
|
85c028b60d | ||
|
|
ee5f0f7c30 | ||
|
|
8522fdc99c | ||
|
|
2f63529029 | ||
|
|
e89d4e2b7f | ||
|
|
bd6b1806cd | ||
|
|
d8ddd1e2ec | ||
|
|
b5bd3f3abf | ||
|
|
ce77c4ac4c | ||
|
|
22bc0a929b | ||
|
|
bebbc6371b | ||
|
|
d583e412c9 | ||
|
|
bdc899857c | ||
|
|
b7e9e2a1a5 | ||
|
|
eaff541349 | ||
|
|
a324be86d2 | ||
|
|
e22ca23b81 | ||
|
|
ed8e3b3786 | ||
|
|
974f04be24 | ||
|
|
ad71307a5e | ||
|
|
ce5c2d8682 | ||
|
|
cdebd400ec | ||
|
|
48eff90d1f | ||
|
|
c58d7d8a98 | ||
|
|
fbae893f07 | ||
|
|
432b03572a | ||
|
|
4f4e490d53 | ||
|
|
dfc10bb5ae | ||
|
|
dd893254be | ||
|
|
f2d37a7280 | ||
|
|
8232bd01d6 | ||
|
|
49a46f08de | ||
|
|
75c5c89909 | ||
|
|
cdf15222e1 | ||
|
|
6208755d54 | ||
|
|
4821f38d25 | ||
|
|
717ad388be | ||
|
|
dc694597f0 | ||
|
|
9474b90fda | ||
|
|
721c381df3 | ||
|
|
305ec78c93 | ||
|
|
737ec6b26e | ||
|
|
871193eb62 | ||
|
|
02279dff31 | ||
|
|
43b22b4473 | ||
|
|
c8d9a5305b | ||
|
|
06ace23a32 | ||
|
|
979b042675 | ||
|
|
0d7359a826 | ||
|
|
55eff16760 | ||
|
|
dcb9c2031b | ||
|
|
d02b026a4d | ||
|
|
8750caa8e3 | ||
|
|
83740de636 | ||
|
|
d389ee457c | ||
|
|
a77f534f7c | ||
|
|
5f4b6d267c | ||
|
|
7084f07dab | ||
|
|
1675181e49 | ||
|
|
01f8a4966a | ||
|
|
c41e44d964 | ||
|
|
a32618dff4 | ||
|
|
8aa0a280b2 | ||
|
|
3db65ef7e8 | ||
|
|
441720df75 | ||
|
|
ad013264eb | ||
|
|
7c27436d21 | ||
|
|
2f9ef85614 | ||
|
|
3d73a4f944 | ||
|
|
29c7d5fc63 | ||
|
|
c269c68727 | ||
|
|
3af9ea8d7d | ||
|
|
e2bb950012 | ||
|
|
a20fb650fe | ||
|
|
f935e37925 | ||
|
|
66072fec5a | ||
|
|
19070621af | ||
|
|
a113861b0c | ||
|
|
cf24191fe5 | ||
|
|
74dc3c99de | ||
|
|
0bb99c15e5 | ||
|
|
adc1529567 | ||
|
|
3f2c5c2319 | ||
|
|
683a89a415 | ||
|
|
4ed9b45fb8 | ||
|
|
86870b0aa6 | ||
|
|
a0c162c2d6 | ||
|
|
8e937e9640 | ||
|
|
66762380ed | ||
|
|
1d781f13b2 | ||
|
|
29a5756f87 | ||
|
|
285344eb0e | ||
|
|
f067447d9c | ||
|
|
39d9cbc43d | ||
|
|
2d064ee67a | ||
|
|
eba3a8e802 | ||
|
|
0fde204074 | ||
|
|
a54b7542f1 | ||
|
|
d8cbbc7d65 | ||
|
|
6c8fe5ae02 | ||
|
|
9cf818d347 | ||
|
|
a1de447662 | ||
|
|
a6e53410b0 | ||
|
|
4494d46020 | ||
|
|
95161a0df4 | ||
|
|
aa918e8528 | ||
|
|
ccad0a4cf9 | ||
|
|
2c99594688 | ||
|
|
9ccc43980b | ||
|
|
50e66d81de | ||
|
|
604febb398 | ||
|
|
e434e8e2e2 | ||
|
|
96930e25f3 | ||
|
|
5e4ec85574 | ||
|
|
c10064ae2c | ||
|
|
38ac7f7350 | ||
|
|
a00c98bea7 | ||
|
|
3cc41634c5 | ||
|
|
d5e9cd72df | ||
|
|
75397b441f | ||
|
|
fe5890b828 | ||
|
|
1f1b7eb7d5 | ||
|
|
817443c5dd | ||
|
|
16b8e7c432 | ||
|
|
01aca675ef | ||
|
|
484e1fb218 | ||
|
|
e18388ade3 | ||
|
|
2caf32d421 | ||
|
|
d5067b4d73 | ||
|
|
41a6548acb | ||
|
|
911e034d1c | ||
|
|
0082b78075 | ||
|
|
bfe18d6085 | ||
|
|
ba2faecdc7 | ||
|
|
c1bc0f9dfb | ||
|
|
25148d0de5 | ||
|
|
9e36a9ee04 | ||
|
|
faf39ecef4 | ||
|
|
22189ec9e8 | ||
|
|
8b741cfefb | ||
|
|
894604201b | ||
|
|
9351313186 | ||
|
|
ea70c6f696 | ||
|
|
a1d39cab21 | ||
|
|
d40c020e0e | ||
|
|
bec88bc52a | ||
|
|
afe52e8e09 | ||
|
|
72aac09d62 | ||
|
|
43331564b4 | ||
|
|
42cf5f279f | ||
|
|
8640a01f85 | ||
|
|
1dccc039b7 | ||
|
|
59c543570a | ||
|
|
4723da0251 | ||
|
|
76cbb9132f | ||
|
|
4856645b6d | ||
|
|
c5420bb453 | ||
|
|
93670fedda | ||
|
|
1dcedb5054 | ||
|
|
c6da5fb38e | ||
|
|
f4245a2d9c | ||
|
|
be8f6f0d65 | ||
|
|
045ca33692 | ||
|
|
91c17a6f14 | ||
|
|
c18b54fc08 | ||
|
|
c5a6e9da15 | ||
|
|
80ed98c87a | ||
|
|
2985cffc52 | ||
|
|
2935751f75 | ||
|
|
23c916c0d6 | ||
|
|
509dcd9ad0 | ||
|
|
039679cad1 | ||
|
|
5dfc74c851 | ||
|
|
9d26c69c4a | ||
|
|
20194c4cc5 | ||
|
|
d463c346fe | ||
|
|
25e043766a | ||
|
|
905573700b | ||
|
|
37f4316df0 | ||
|
|
de15cc1387 | ||
|
|
2ea9b3e6f2 | ||
|
|
8d889ef80e | ||
|
|
b54f0fb388 | ||
|
|
1da81d8755 | ||
|
|
b093ea1f0a | ||
|
|
ed1cc18ab5 | ||
|
|
147af15268 | ||
|
|
1f512b36c5 | ||
|
|
ebc0e1ca8a | ||
|
|
bf09fbe6b9 | ||
|
|
5c036d9aaf | ||
|
|
5aa8743024 | ||
|
|
c6b7695ab5 | ||
|
|
c8ad8bb7aa | ||
|
|
09f4e0b19c | ||
|
|
a9aac02b90 | ||
|
|
e64bdcd12b | ||
|
|
f380b215b2 | ||
|
|
201bcaf2ca | ||
|
|
7d6f52f4ab | ||
|
|
d8763d7d65 | ||
|
|
46831c4c20 | ||
|
|
14a3e64c80 | ||
|
|
7f4bc64d22 | ||
|
|
32b587b3a0 | ||
|
|
21abc3aa50 | ||
|
|
4c3f0b94a4 | ||
|
|
fcb6edf571 | ||
|
|
d23c9987ed | ||
|
|
60b852bb12 | ||
|
|
c86cdd609e | ||
|
|
91aa671a23 | ||
|
|
250bae2603 | ||
|
|
6bd4509923 | ||
|
|
34326470b8 | ||
|
|
38794c0ca1 | ||
|
|
b874922404 | ||
|
|
296bf9ef42 | ||
|
|
7b1b3f0fa8 | ||
|
|
3564ac7c88 | ||
|
|
5ef26b42a8 | ||
|
|
6edce82aef | ||
|
|
e19e16fbf1 | ||
|
|
2a10b02c68 | ||
|
|
25ab1e41df | ||
|
|
77f22635f2 | ||
|
|
119c976ad1 | ||
|
|
8f7ed71e9e | ||
|
|
83b0b2adec | ||
|
|
9a8549a361 | ||
|
|
a01ebe0a54 | ||
|
|
001edb4464 | ||
|
|
a9ff4f6688 | ||
|
|
d095acdad5 | ||
|
|
8781dc8ca3 | ||
|
|
f82ea857a0 | ||
|
|
54becbb33a | ||
|
|
a877115ff4 | ||
|
|
e7f67592a8 | ||
|
|
ed004018d6 | ||
|
|
d138633c5b | ||
|
|
23d7b09389 | ||
|
|
132323462c | ||
|
|
fd46bf2616 | ||
|
|
774167192a | ||
|
|
291e161793 | ||
|
|
2064dfc5a9 | ||
|
|
1e6e1dd451 | ||
|
|
c6b548b5b2 | ||
|
|
fed5788c50 | ||
|
|
824376a045 | ||
|
|
451d1a1744 | ||
|
|
c15cc8fc28 | ||
|
|
6211a5bc3b | ||
|
|
946f68f7f0 | ||
|
|
e9affd97ac | ||
|
|
9f86022c2b | ||
|
|
d45c12b382 | ||
|
|
3f1444e410 | ||
|
|
3bd15d3aaa | ||
|
|
c9cf5aebea | ||
|
|
a51a304cf0 | ||
|
|
7ab861fe95 | ||
|
|
786d7bd3d4 | ||
|
|
d9e9d562f8 | ||
|
|
558d44e519 | ||
|
|
2e7419d78f | ||
|
|
fdad33309b | ||
|
|
5a61880e6a | ||
|
|
5dcf2c669f | ||
|
|
8393ebbbca | ||
|
|
8b744b2d03 | ||
|
|
8dd4699f10 | ||
|
|
e18f7b91c3 | ||
|
|
a35e34b5f0 | ||
|
|
83dee07420 | ||
|
|
3eccb84eaa | ||
|
|
e40b100110 | ||
|
|
b6b27d9256 | ||
|
|
7b7962d28c | ||
|
|
77744766dd | ||
|
|
dcfc849946 | ||
|
|
d9ab09ab2b | ||
|
|
f8cc86bfed | ||
|
|
0800031c0d | ||
|
|
6b0fea16b6 | ||
|
|
2c60f6419e | ||
|
|
462d9cb331 | ||
|
|
a44e8afe71 | ||
|
|
5888efbb4e | ||
|
|
0c665e5638 | ||
|
|
1f9a84f165 | ||
|
|
9c0f462336 | ||
|
|
07bb46e3fb | ||
|
|
aa7d0c0163 | ||
|
|
a9f5a697bb | ||
|
|
73420e462f | ||
|
|
fa4a2a53e8 | ||
|
|
df1a5a9633 | ||
|
|
5324234bd0 | ||
|
|
30f3354a7a | ||
|
|
c16fb9eb9d | ||
|
|
6bbc834f8f | ||
|
|
8590112faa | ||
|
|
6daab3ca89 | ||
|
|
51eabfe352 | ||
|
|
231472bc20 | ||
|
|
68a4c70b72 | ||
|
|
ca2509423a | ||
|
|
4109f88c04 | ||
|
|
5bf52ebed6 | ||
|
|
ba99945359 | ||
|
|
28d182af15 | ||
|
|
8a097c8627 | ||
|
|
1ba83427e5 | ||
|
|
cef75a5987 | ||
|
|
d793e39b6d | ||
|
|
ec1dae023c | ||
|
|
7d476a3e35 | ||
|
|
81449ece54 | ||
|
|
7323bfdad7 | ||
|
|
b9c1dad2e6 | ||
|
|
aeaf416d6d | ||
|
|
3c8bea65ef | ||
|
|
57c311f8e9 | ||
|
|
780fb8a4e5 | ||
|
|
d019d28bc9 | ||
|
|
50e591b815 | ||
|
|
4f96ec1b6c | ||
|
|
0816c0bd5e | ||
|
|
c1930fa64d | ||
|
|
91a564989f | ||
|
|
9e4f674fb9 | ||
|
|
627a3dcd6d | ||
|
|
af2eac4334 | ||
|
|
33daf281bd | ||
|
|
f9069a9873 | ||
|
|
7563bdf6f8 | ||
|
|
ad5fc07652 | ||
|
|
6b9b92afb0 | ||
|
|
094612dc02 | ||
|
|
4fe67236ed | ||
|
|
c5c3860c5c | ||
|
|
6de526ff42 | ||
|
|
5d41e3848d | ||
|
|
a8752db012 | ||
|
|
abd434f656 | ||
|
|
bc001d2d9a | ||
|
|
b50b5095ad | ||
|
|
bac4b93639 | ||
|
|
76df782006 | ||
|
|
dce04b7335 | ||
|
|
7e8e4783a1 | ||
|
|
bb5f99a34d | ||
|
|
40c5bf9e94 | ||
|
|
8beca68948 | ||
|
|
2818b5bbe7 | ||
|
|
8cc2f83bd5 | ||
|
|
57835f0a37 | ||
|
|
72dcb51177 | ||
|
|
a2a9b39794 | ||
|
|
c2a9b14c96 | ||
|
|
4432a874de | ||
|
|
74fdfff5b5 | ||
|
|
87000977d5 | ||
|
|
a9435cc6b0 | ||
|
|
5bd8562b5a | ||
|
|
4a323463f7 | ||
|
|
9c3fd8dbc3 | ||
|
|
018f0d3bbd | ||
|
|
3d433efdfe | ||
|
|
1cd762e9d0 | ||
|
|
d88f850d0f | ||
|
|
cf045d86b0 | ||
|
|
93a9c08116 | ||
|
|
b3c732daf5 | ||
|
|
f8899827e0 | ||
|
|
6996c2d17d | ||
|
|
755020843b | ||
|
|
72949e7f73 | ||
|
|
e4f8bda1ea | ||
|
|
cdce6c746f | ||
|
|
d51f7af9ab | ||
|
|
3b0ec48b0c | ||
|
|
a5dfe0725f | ||
|
|
a3095c987a | ||
|
|
a656151ee9 | ||
|
|
a3b8c77af1 | ||
|
|
1564f1476c | ||
|
|
c9c8e19ec2 | ||
|
|
504e52ff46 | ||
|
|
b1604a24ed | ||
|
|
469247bf73 | ||
|
|
a2dbd391b3 | ||
|
|
8051ca1859 | ||
|
|
e3ef56804c | ||
|
|
cd38ba4833 | ||
|
|
1d1858a8b0 | ||
|
|
249cdd92e0 | ||
|
|
e543fc483f | ||
|
|
a322b159ab | ||
|
|
0cc837eac5 | ||
|
|
ff09b412f4 | ||
|
|
4897897a3a | ||
|
|
7bcb24efbf | ||
|
|
5038d6a6db | ||
|
|
bb736248a2 | ||
|
|
e919388ee6 | ||
|
|
358a01a226 | ||
|
|
2d7370a525 | ||
|
|
bf7e012bde | ||
|
|
c4950a0281 | ||
|
|
a035428d43 | ||
|
|
d2315e5c5c | ||
|
|
a2fd1f22da | ||
|
|
bcda12f4bb | ||
|
|
e851346b4c | ||
|
|
88e8688a4b | ||
|
|
0254217314 | ||
|
|
1853a83453 | ||
|
|
6f486f3719 | ||
|
|
5c008ef023 | ||
|
|
5c211d8abf | ||
|
|
4ac25f28a3 | ||
|
|
d312d11062 | ||
|
|
69aeff15ef | ||
|
|
06facea895 | ||
|
|
110f4ea0c9 | ||
|
|
db21f86b26 | ||
|
|
20c7c290fa | ||
|
|
5945144c08 | ||
|
|
89d3bc0b54 | ||
|
|
10711dd09d | ||
|
|
63dbacd7c0 | ||
|
|
48e43e2421 | ||
|
|
217aadba7e | ||
|
|
cbcede79b1 | ||
|
|
32eccb8fb2 | ||
|
|
632fc6af79 | ||
|
|
f43825e4dd | ||
|
|
5f59c2ae75 | ||
|
|
fd312be79f | ||
|
|
fb7c7b53ba | ||
|
|
d2f22b52a5 | ||
|
|
ffc4f8f2a5 | ||
|
|
cdcff6c26d | ||
|
|
e352fb754b | ||
|
|
5ae40a9500 | ||
|
|
40dbb63042 | ||
|
|
594918bd3a | ||
|
|
5343631708 | ||
|
|
366451fc62 | ||
|
|
a14ee7f1fe | ||
|
|
c5588a9b93 | ||
|
|
21a4f82f69 | ||
|
|
3b366c30a8 | ||
|
|
8e67a3a8a8 | ||
|
|
4726fc4893 | ||
|
|
c69cc13c85 | ||
|
|
ddfbb07c3b | ||
|
|
d30f87bbdf | ||
|
|
4ce38059ac | ||
|
|
bbc1b5cdcf | ||
|
|
ac0c1edd23 | ||
|
|
a93b665427 | ||
|
|
ede7050afe | ||
|
|
0906bc8430 | ||
|
|
ac2b5ed84f | ||
|
|
b847731482 | ||
|
|
b5bd91417d | ||
|
|
6298da4458 | ||
|
|
cffe577028 | ||
|
|
48d1463825 | ||
|
|
c257ce82c5 | ||
|
|
867ac10ffd | ||
|
|
d114c8f88f | ||
|
|
1d1427de60 | ||
|
|
91596f2467 | ||
|
|
eb2ab3bf76 | ||
|
|
a7d448dcba | ||
|
|
77da3b4347 | ||
|
|
9d77e9f719 | ||
|
|
c901d6322c | ||
|
|
7496548c39 | ||
|
|
f1fab871b8 | ||
|
|
5aaf15d145 | ||
|
|
16a7ec95dc | ||
|
|
607a21e02a | ||
|
|
b03fa8a441 | ||
|
|
f4fde51bba | ||
|
|
c78c86663d | ||
|
|
7834a0182b | ||
|
|
1e0b0da7ad | ||
|
|
a2db94761a | ||
|
|
805b8634da | ||
|
|
1635967c4e | ||
|
|
a5907e17d5 | ||
|
|
0252c1478e | ||
|
|
f5bece1afa | ||
|
|
e46c56bfe8 | ||
|
|
561a2e966e | ||
|
|
a9b0c55bcb | ||
|
|
93bad51659 | ||
|
|
1e2dc2c8f1 | ||
|
|
2691991d9a | ||
|
|
e8b1c82531 | ||
|
|
67e4186360 | ||
|
|
3f8f8d36b7 | ||
|
|
a70e2bdbc9 | ||
|
|
1ab75db0ac | ||
|
|
e85c320501 | ||
|
|
cb44f3a7c3 | ||
|
|
c174e4d01a | ||
|
|
d272fd42c9 | ||
|
|
c5b2a58669 | ||
|
|
7fa3f3fe98 | ||
|
|
a3d04cdbca | ||
|
|
2791054327 | ||
|
|
eb4fa966b0 | ||
|
|
ad6151b690 | ||
|
|
64095084e7 | ||
|
|
4bcc221ee3 | ||
|
|
cf901da25d | ||
|
|
496f8e966f | ||
|
|
4dd8895133 | ||
|
|
8666ecc26f | ||
|
|
152360d999 | ||
|
|
e7c7a0e648 | ||
|
|
4d553b7a84 | ||
|
|
fffdb6f575 | ||
|
|
063144c514 | ||
|
|
402d82b4c5 | ||
|
|
711d1acffd | ||
|
|
81472e4c08 | ||
|
|
b8f23c2657 | ||
|
|
f33dfc2121 | ||
|
|
e26b55265f | ||
|
|
26dfd5b314 | ||
|
|
e31c6964f3 | ||
|
|
fd85b1689d | ||
|
|
4a8710ef75 | ||
|
|
58e6b67886 | ||
|
|
f268562256 | ||
|
|
86720deeae | ||
|
|
ae587dbd83 | ||
|
|
72bea0dff4 | ||
|
|
736b5e07cc | ||
|
|
ca58fde552 | ||
|
|
bb3cec1556 | ||
|
|
42d0da8f5a | ||
|
|
dbc69da409 | ||
|
|
e3bb247868 | ||
|
|
f856b3b559 | ||
|
|
89433b4bea | ||
|
|
bcfec77e2c | ||
|
|
744b92d233 | ||
|
|
0eed0a9abe | ||
|
|
b3e5d11e1d | ||
|
|
0df38891a1 | ||
|
|
f75481fa23 | ||
|
|
828fea6d66 | ||
|
|
2cd994977b | ||
|
|
17906d5599 | ||
|
|
5e84ce55ae | ||
|
|
effe53d4ae | ||
|
|
88885184dc | ||
|
|
9641edc562 | ||
|
|
9b42682575 | ||
|
|
dcd5be0d07 | ||
|
|
c059bc3e36 | ||
|
|
52c61904c8 | ||
|
|
a6ab00162e | ||
|
|
9e4282e130 | ||
|
|
13c7e183a6 | ||
|
|
5755d2d32f | ||
|
|
79525327f0 | ||
|
|
3e11338ed5 | ||
|
|
233ee277ef | ||
|
|
36b30911a8 | ||
|
|
acd00df8fb | ||
|
|
ed1ec82d2f | ||
|
|
25052a0ab7 | ||
|
|
dbd72ea89d | ||
|
|
232b5dab81 | ||
|
|
dbe8dab3ce | ||
|
|
f5b2db76cb | ||
|
|
1c29c520bd | ||
|
|
2f322609d7 | ||
|
|
74c7b04b29 | ||
|
|
c20e66e0be | ||
|
|
445a93e5f5 | ||
|
|
66f2bc69a6 | ||
|
|
55a2699f4c | ||
|
|
354d0af44e | ||
|
|
f455c92d02 | ||
|
|
b654dc0e28 | ||
|
|
d03d8204ab | ||
|
|
adba6c833d | ||
|
|
7b9e30914f | ||
|
|
1707c3da95 | ||
|
|
b606d4d2ad | ||
|
|
9fa5dbd6e4 | ||
|
|
1cf7270049 | ||
|
|
be0ae7a430 | ||
|
|
0aeccbf4b2 | ||
|
|
8f32ac0edd | ||
|
|
a5b78f3c0d | ||
|
|
671c20ec56 | ||
|
|
17d3de1821 | ||
|
|
cfec328c74 | ||
|
|
c5e0838890 | ||
|
|
974ac3e6ad | ||
|
|
dc675b1eb0 | ||
|
|
9057239c3c | ||
|
|
d6be8989e4 | ||
|
|
8ac2a2f0c4 | ||
|
|
1c538b9b43 | ||
|
|
ba6fe6cde5 | ||
|
|
7243e774c2 | ||
|
|
db3bb793e9 | ||
|
|
8de8a78235 | ||
|
|
5dd1b50802 | ||
|
|
00f9930fbf | ||
|
|
457da47dba | ||
|
|
2b9e256002 | ||
|
|
a1aa85712b | ||
|
|
05f243590d | ||
|
|
94d7096c8c | ||
|
|
ecc801d3d8 | ||
|
|
be9f4ea487 | ||
|
|
a1dc152695 | ||
|
|
9209570937 | ||
|
|
d8c262fd5c | ||
|
|
fe579c2efd | ||
|
|
d94a389dd3 | ||
|
|
98b86ecbc2 | ||
|
|
dc0fb08ec7 | ||
|
|
a7ab51c5ba | ||
|
|
59432418c6 | ||
|
|
6e7b9b5cb7 | ||
|
|
8b4d604cfd | ||
|
|
4affe4b939 | ||
|
|
c890401fec | ||
|
|
7f94a58bf1 | ||
|
|
f3d78dd29c | ||
|
|
23b5f4ec99 | ||
|
|
bdfd69a2fe | ||
|
|
56d03a456b | ||
|
|
680e098b87 | ||
|
|
db88476f8b | ||
|
|
88ee7d8dbe | ||
|
|
6689ed543a | ||
|
|
f2798eab50 | ||
|
|
210317c0b5 | ||
|
|
362c89ca73 | ||
|
|
687b1a5b1f | ||
|
|
8d55f81baa | ||
|
|
7ff82fccf3 | ||
|
|
cd25d6dc7f | ||
|
|
c1f25ff9e3 | ||
|
|
447134d308 | ||
|
|
224d857928 | ||
|
|
a23fc327df | ||
|
|
ec92486377 | ||
|
|
a6c6e02c49 | ||
|
|
298d38cde3 | ||
|
|
81f20891c1 | ||
|
|
109a07b834 | ||
|
|
5619db28cb | ||
|
|
bcb0f6038e | ||
|
|
e9e0c0e7d4 | ||
|
|
e84de50147 | ||
|
|
c6e02e2a74 | ||
|
|
ea97a6cb5b | ||
|
|
da2a623e38 | ||
|
|
6affeaa9c1 | ||
|
|
d79a16c9f3 | ||
|
|
d36ff39498 | ||
|
|
9f4dc3fcd4 | ||
|
|
128f5dbff1 | ||
|
|
576f51d89e | ||
|
|
eab5be1110 | ||
|
|
c9b6c9bb61 | ||
|
|
6d549b03f1 | ||
|
|
128db172f0 | ||
|
|
dd63b656c7 | ||
|
|
5f2c030ddc | ||
|
|
9e6abc4948 | ||
|
|
bf2b712f4b | ||
|
|
a8403cde16 | ||
|
|
cb38cc96c3 | ||
|
|
79414a8d36 | ||
|
|
5cdda19494 | ||
|
|
16dda1a991 | ||
|
|
d5b4b1fdaf | ||
|
|
b69595904a | ||
|
|
5124b2806d | ||
|
|
060ff62178 | ||
|
|
1a090432d9 | ||
|
|
a251267dd7 | ||
|
|
9ef7d5edaf | ||
|
|
5d3dee206f | ||
|
|
1583925080 | ||
|
|
c97a7fb845 | ||
|
|
becb89213f | ||
|
|
1008e6e450 | ||
|
|
09ddc84c3a | ||
|
|
33b392ac2b | ||
|
|
3965451c7a | ||
|
|
0487ad5515 | ||
|
|
e2acc748c8 | ||
|
|
4645727163 | ||
|
|
7d288437d8 | ||
|
|
c80e5fe7a1 | ||
|
|
5efedd7a60 | ||
|
|
960a1cbd8f | ||
|
|
6450be5e58 | ||
|
|
669cff88d1 | ||
|
|
19c3cb0d5b | ||
|
|
bc5712a1b3 | ||
|
|
0df513434e | ||
|
|
d5e5e22adb | ||
|
|
77ec3cf402 | ||
|
|
0a2ed6da37 | ||
|
|
6e80cbfd1e | ||
|
|
ac3579d2c6 | ||
|
|
8d0b6f9a60 | ||
|
|
42d9298318 | ||
|
|
4b71d9ca9f | ||
|
|
ec1fe9e2ca | ||
|
|
182f4def00 | ||
|
|
2fb6bc9867 | ||
|
|
98a6e5cb6c | ||
|
|
c5d41af10f | ||
|
|
dbb44c8950 | ||
|
|
ae2a0fb4c7 | ||
|
|
2e1d7cbdc2 | ||
|
|
ca55af836b | ||
|
|
3a42631e65 | ||
|
|
107b2768fd | ||
|
|
78690d7b8b | ||
|
|
760b078dc9 | ||
|
|
2c5dcbe819 | ||
|
|
06ce1f5a40 | ||
|
|
4454630549 | ||
|
|
612b0ff9cd | ||
|
|
5a7f26f4d2 | ||
|
|
de20b083a0 | ||
|
|
17166a5662 | ||
|
|
e6013fb02d | ||
|
|
c29f594fc1 | ||
|
|
5fe44f906d | ||
|
|
df4edaa0fd | ||
|
|
02522a0df5 | ||
|
|
e4e7468972 | ||
|
|
904cbef4dc | ||
|
|
81d5265385 | ||
|
|
33d00bfeae | ||
|
|
4d7a0aaee1 | ||
|
|
e14a00b887 | ||
|
|
77ec5cc8d5 | ||
|
|
f841afd48d | ||
|
|
dab5b1f319 | ||
|
|
8b9b77959d | ||
|
|
d2f13fe0a6 | ||
|
|
469e430d38 | ||
|
|
64a962ce97 | ||
|
|
1a2600c9ea | ||
|
|
7df50b6ec7 | ||
|
|
80afee04a4 | ||
|
|
bd2e7c0e53 | ||
|
|
3234f0d299 | ||
|
|
9002a6c195 | ||
|
|
9eda500dbc | ||
|
|
fb23773935 | ||
|
|
037caf096b | ||
|
|
f81b6c7cfb | ||
|
|
1c728a7cf8 | ||
|
|
cfce53103b | ||
|
|
af969d664f | ||
|
|
19199baf29 | ||
|
|
ebf38c5ebd | ||
|
|
c97ffaeac3 | ||
|
|
677c522f01 | ||
|
|
8363a6e585 | ||
|
|
83705af0b3 | ||
|
|
214815eb62 | ||
|
|
a0b9b3cef5 | ||
|
|
cd7a89da32 | ||
|
|
43dc351209 | ||
|
|
9db6471fae | ||
|
|
4b28b3216b | ||
|
|
db01743885 | ||
|
|
b87c5d83de | ||
|
|
8f706399a0 | ||
|
|
c36abbcda3 | ||
|
|
dabcb6b531 | ||
|
|
1fb21cd9e5 | ||
|
|
e6b076cb34 | ||
|
|
7f0f0d0559 | ||
|
|
0b711d1f8a | ||
|
|
3f7a757e80 | ||
|
|
d4edd284e6 | ||
|
|
b282f1f154 | ||
|
|
3fbfac64c2 | ||
|
|
12fbecf48b | ||
|
|
59a6821299 | ||
|
|
9839a9afb0 | ||
|
|
4583100537 | ||
|
|
ca5fdeb9bb | ||
|
|
5790fabd54 | ||
|
|
208eb05519 | ||
|
|
ed6fb66a90 | ||
|
|
7c7e9ecfcd | ||
|
|
8d4b04e719 | ||
|
|
e173d54054 | ||
|
|
24c3b4e00f | ||
|
|
261d132f3a | ||
|
|
fa3af74179 | ||
|
|
0184c981ee | ||
|
|
e047de854b | ||
|
|
ffddcb0526 | ||
|
|
86f3310ac1 | ||
|
|
f94d183297 | ||
|
|
224c2ddaf4 | ||
|
|
3662ed50d2 | ||
|
|
7e818067eb | ||
|
|
44b906a43d | ||
|
|
429bfcfd83 | ||
|
|
10e8073204 | ||
|
|
99c26e068d | ||
|
|
cfd19afabf | ||
|
|
bafc89f439 | ||
|
|
9f9184c908 | ||
|
|
536e6bf57c | ||
|
|
f3a5188bec | ||
|
|
9bc4232af6 | ||
|
|
5cbe6160ca | ||
|
|
f2bf76a2ef | ||
|
|
f729eed035 | ||
|
|
065e8f3650 | ||
|
|
04b42600b0 | ||
|
|
df7644a96d | ||
|
|
afae8a0c46 | ||
|
|
472050bb8a | ||
|
|
f19b7b9122 | ||
|
|
e5c733bdb3 | ||
|
|
c7716f0bbc | ||
|
|
b9f2a6048b | ||
|
|
3623452839 | ||
|
|
2260838933 | ||
|
|
1b48448b7b | ||
|
|
6276f1adc5 | ||
|
|
9335cdd536 | ||
|
|
c5ae3cc120 | ||
|
|
cab8e9be89 | ||
|
|
0c699f0726 | ||
|
|
9f4b270116 | ||
|
|
4ca82f9308 | ||
|
|
207f218db3 | ||
|
|
89d8a0b6fd | ||
|
|
76c6a050af | ||
|
|
235166ec41 | ||
|
|
f6f849226e | ||
|
|
7d3f1fef1c | ||
|
|
314647572c | ||
|
|
6bed870dfa | ||
|
|
f281f00d43 | ||
|
|
e4abaa7cdd | ||
|
|
e8f95a2adf | ||
|
|
d9fa83b196 | ||
|
|
23f30cdb8b | ||
|
|
043f70e9a6 | ||
|
|
9983d90e24 | ||
|
|
7638301d01 | ||
|
|
0957480305 | ||
|
|
9601b6c601 | ||
|
|
833afea3e3 | ||
|
|
08df6bda41 | ||
|
|
31c5c1e562 | ||
|
|
7e1987ed48 | ||
|
|
f9fb92ebb0 | ||
|
|
a3d5200194 | ||
|
|
9accae3ddc | ||
|
|
8b0302bab9 | ||
|
|
cfb899451f | ||
|
|
fb5aa43e77 | ||
|
|
713d4bb1ba | ||
|
|
a7eaa4de14 | ||
|
|
65ad4287b6 | ||
|
|
b4678d3f21 | ||
|
|
580fa48642 | ||
|
|
06a0afa039 | ||
|
|
a813571c17 | ||
|
|
d66396f4e9 | ||
|
|
c92e823651 | ||
|
|
35c4b78e66 | ||
|
|
ed7e074985 | ||
|
|
6f39db6a18 | ||
|
|
7668cd7053 | ||
|
|
b656529818 | ||
|
|
8bf19ce81a | ||
|
|
4d38a5043f | ||
|
|
2f1633bf41 | ||
|
|
a499079250 | ||
|
|
75465775b4 | ||
|
|
b0916a35dc | ||
|
|
93e46310b8 | ||
|
|
4b3b358ac6 | ||
|
|
e45102b913 | ||
|
|
dadd049cbf | ||
|
|
6fd3a86012 | ||
|
|
8426ff726a | ||
|
|
968da1cd21 | ||
|
|
7d7e4534dd | ||
|
|
c7abc025ff | ||
|
|
77313685da | ||
|
|
0313dc0f8c | ||
|
|
dc53e8ebb0 | ||
|
|
117161401a | ||
|
|
c6857e562b | ||
|
|
3f31a56fb3 | ||
|
|
c154e57603 | ||
|
|
b559bf6de6 | ||
|
|
c57328669a | ||
|
|
b35c0410b1 | ||
|
|
fc04d334da | ||
|
|
a7dc3735ae | ||
|
|
4be00502cc | ||
|
|
097cc13072 | ||
|
|
c16ef32b6b | ||
|
|
8704bc6f39 | ||
|
|
31e3dada0e | ||
|
|
e06f486aee | ||
|
|
d9e482759c | ||
|
|
bb7a2dbb6a | ||
|
|
0c1dbb116f | ||
|
|
fbcc56536b | ||
|
|
fa9111ebe2 | ||
|
|
8fb600162e | ||
|
|
5eac8703da | ||
|
|
d301d26fda | ||
|
|
b65c761b16 | ||
|
|
fdb5e6b2e5 | ||
|
|
862363521b | ||
|
|
f9c0ef3eb3 | ||
|
|
548293ad08 | ||
|
|
f650cb8e4b | ||
|
|
a4ada93834 | ||
|
|
66064c7827 | ||
|
|
1214e2d2a4 | ||
|
|
de1ecee3b3 | ||
|
|
403968b2f7 | ||
|
|
72d03464dc | ||
|
|
14fb1600ec | ||
|
|
341f7733d1 | ||
|
|
e260e8239f | ||
|
|
55ab31314c | ||
|
|
2a45eadc28 | ||
|
|
36c724d7b5 | ||
|
|
344df219a4 | ||
|
|
3e4cabfd6c | ||
|
|
40e35048b8 | ||
|
|
9ad10cb425 | ||
|
|
62daa43a4c | ||
|
|
a55e4e2c03 | ||
|
|
107c07e5cb | ||
|
|
4c652396d0 | ||
|
|
b566cc3e79 | ||
|
|
f37fb82069 | ||
|
|
d9f3ba5fda | ||
|
|
724be6eca2 | ||
|
|
82661372f7 | ||
|
|
3d15128b91 | ||
|
|
1c1f6f90bb | ||
|
|
5dfe4df23b | ||
|
|
22a4857a3c | ||
|
|
acc0958ead | ||
|
|
f1f79ff1e1 | ||
|
|
7d270edf79 | ||
|
|
b590f89310 | ||
|
|
8d00ee4f81 | ||
|
|
8c8b1f2da6 | ||
|
|
7e20324776 | ||
|
|
ec421df4e4 | ||
|
|
27bdba49d4 | ||
|
|
d43764c8e5 | ||
|
|
6a43f6718a | ||
|
|
a65ad10c62 | ||
|
|
4fce891241 | ||
|
|
d800f993b0 | ||
|
|
82a9118cb2 | ||
|
|
f0f4dbd5f8 | ||
|
|
e666b882e7 | ||
|
|
e83b0c3599 | ||
|
|
9443e8e85f | ||
|
|
0f3281fe43 | ||
|
|
ce63b1f669 | ||
|
|
809025c746 | ||
|
|
af19347376 | ||
|
|
64968979b2 | ||
|
|
dc4452ffe3 | ||
|
|
2f87fd7951 | ||
|
|
64f174fcaa | ||
|
|
53f5e2e066 | ||
|
|
3844a98c42 | ||
|
|
e87fbcc286 | ||
|
|
941e21092c | ||
|
|
c391d65dc3 | ||
|
|
b4ecd29015 | ||
|
|
0162d0a2ea | ||
|
|
ad89b029c2 | ||
|
|
06f99cae36 | ||
|
|
15154d4bd0 | ||
|
|
7fdab021b6 | ||
|
|
1495c9599a | ||
|
|
e3a2ab184e | ||
|
|
f7733be322 | ||
|
|
4d53992b35 | ||
|
|
dda6b5cd53 | ||
|
|
aa92df4ddc | ||
|
|
0ce2afc9bc | ||
|
|
41a1cd954c | ||
|
|
b124aff0bb | ||
|
|
703fc08467 | ||
|
|
6dd5f74671 | ||
|
|
ada1ac8013 | ||
|
|
efd6307bc4 | ||
|
|
0ec747f57c | ||
|
|
059c568f08 | ||
|
|
641e8fea02 | ||
|
|
cd645de4f9 | ||
|
|
f2fb461e40 | ||
|
|
f4314a25b6 | ||
|
|
bd69f43322 | ||
|
|
d1bb274c22 | ||
|
|
8773d931be | ||
|
|
0d333894c9 | ||
|
|
b6906c58d1 | ||
|
|
0046357b86 | ||
|
|
ac431c8e33 | ||
|
|
7b39aa7f91 | ||
|
|
6076443b6b | ||
|
|
50e2d4aa6a | ||
|
|
e31284189f | ||
|
|
30628b016b | ||
|
|
7c44adad3e | ||
|
|
e4f78a0b6a | ||
|
|
903e87899b | ||
|
|
1e9e471714 | ||
|
|
fb2ec7186d | ||
|
|
185e2a2fd8 | ||
|
|
e2b16e3edb | ||
|
|
23f24d13dd | ||
|
|
3f6ac2d993 | ||
|
|
2fb9e8a94d | ||
|
|
9b24a42017 | ||
|
|
e0e78fb0e2 | ||
|
|
029de1a244 | ||
|
|
96eec7e2cd | ||
|
|
1e82638ae8 | ||
|
|
ff79463e36 | ||
|
|
6bc2988623 | ||
|
|
0f072d7d40 | ||
|
|
0ae786adec | ||
|
|
6a5b7f751c | ||
|
|
a630a24040 | ||
|
|
2d8f42a007 | ||
|
|
fdb395c977 | ||
|
|
dac46ed6e1 | ||
|
|
6002fd7820 | ||
|
|
4b680178be | ||
|
|
5542af9be8 | ||
|
|
1de45877b1 | ||
|
|
13919440a7 | ||
|
|
543996652b | ||
|
|
6f978d2497 | ||
|
|
97ad6352af | ||
|
|
6e2fa02c56 | ||
|
|
6f025e7b4f | ||
|
|
8005022508 | ||
|
|
06ca6f7705 | ||
|
|
ac185989ff | ||
|
|
306a410b77 | ||
|
|
c49d45497c | ||
|
|
828699f26a | ||
|
|
7204bcb932 | ||
|
|
5ca3e83a00 | ||
|
|
f56284b0c1 | ||
|
|
3b31800533 | ||
|
|
b1f3e0224c | ||
|
|
0505135f90 | ||
|
|
14600e6a3e | ||
|
|
0576ad5ef9 | ||
|
|
6d0c6a17d9 | ||
|
|
778b4926bf | ||
|
|
20e1a3e199 | ||
|
|
05425d414c | ||
|
|
bcfbc792b4 | ||
|
|
ed4f8cf65d | ||
|
|
bb1be2e2ee | ||
|
|
48d9cfe304 | ||
|
|
a19d1d6926 | ||
|
|
fd1d4c2927 | ||
|
|
08c02287dd | ||
|
|
d9cc84892b | ||
|
|
f6cf58fa8c | ||
|
|
3877b5407c | ||
|
|
1e9a6e6b7e | ||
|
|
4177ecb6b2 | ||
|
|
cbc22e6369 | ||
|
|
29e9f14f95 | ||
|
|
55ca054cb4 | ||
|
|
4bf65dd0d9 | ||
|
|
06b56adc71 | ||
|
|
6824838ab0 | ||
|
|
9eb091162a | ||
|
|
82cfccab2f | ||
|
|
4a7f370b15 | ||
|
|
2295921821 | ||
|
|
e7d277d51e | ||
|
|
f5dd494716 | ||
|
|
6ecbd97fbe | ||
|
|
581d931031 | ||
|
|
d43d19acfd | ||
|
|
ca872381a1 | ||
|
|
32371c8755 | ||
|
|
1dc124cf75 | ||
|
|
59cee369ce | ||
|
|
80fb0bf520 | ||
|
|
8d19faa598 | ||
|
|
0d4db95d99 | ||
|
|
bd999b0908 | ||
|
|
439313e524 | ||
|
|
12a2b21465 | ||
|
|
0426636a32 | ||
|
|
1db0fc91a5 | ||
|
|
fefdac432c | ||
|
|
24fbe23c8d | ||
|
|
87adaed933 | ||
|
|
4e1b60d401 | ||
|
|
e3a3306b30 | ||
|
|
283d2c5ca2 | ||
|
|
b16d395a8f | ||
|
|
e4d03bf0d0 | ||
|
|
368a974368 | ||
|
|
86e0f4c617 | ||
|
|
c7b9ae9c5e | ||
|
|
b840ba4407 | ||
|
|
00c607116b | ||
|
|
f13243a92e | ||
|
|
3863fc5fb2 | ||
|
|
050f65beb4 | ||
|
|
351f4d53a0 | ||
|
|
62011c9dc4 | ||
|
|
afa1dc4ffa | ||
|
|
c5385e141b | ||
|
|
95e5d812fe | ||
|
|
91e62f575e | ||
|
|
2124d9884b | ||
|
|
aafb5cb6f6 | ||
|
|
ded33a7e2e | ||
|
|
7cc6a67c18 | ||
|
|
8f47bffa0e | ||
|
|
ae4228aed4 | ||
|
|
9d6151d200 | ||
|
|
c6d6adcbf3 | ||
|
|
61bb236cfa | ||
|
|
35786c0067 | ||
|
|
6f69bbe1d7 | ||
|
|
7fbaef5de3 | ||
|
|
c9a4111f4d | ||
|
|
705b7dc9c2 | ||
|
|
71cdcb3593 | ||
|
|
24248f687b | ||
|
|
45197965d7 | ||
|
|
d751281fa7 | ||
|
|
e7d307e6bf | ||
|
|
2417c93d0e | ||
|
|
c99f644ffe | ||
|
|
7a7f4bd822 | ||
|
|
9e3b688333 | ||
|
|
f3926d0fcb | ||
|
|
45cf02308e | ||
|
|
8ef81870bb | ||
|
|
5ba17c87e5 | ||
|
|
afb0c4aa43 | ||
|
|
f8f02c508d | ||
|
|
50037f8609 | ||
|
|
6ba9a128e7 | ||
|
|
964deaca96 | ||
|
|
201aeeb20d | ||
|
|
170b8dded8 | ||
|
|
9bb4b8e8b2 | ||
|
|
cf8f4bda8f | ||
|
|
783bd89413 | ||
|
|
5448edff2c | ||
|
|
01490f1560 | ||
|
|
5ad83c06c2 | ||
|
|
679371e397 | ||
|
|
2b421c39b5 | ||
|
|
1de990b2ac | ||
|
|
5e2b067107 | ||
|
|
0abf5d340c | ||
|
|
d01863707c | ||
|
|
70cf4a6796 | ||
|
|
99c9cfaaed | ||
|
|
4badca54af | ||
|
|
0c0bfb1ef0 | ||
|
|
d6c5b6320f | ||
|
|
e46d3a87ea | ||
|
|
c28d2e4b2a | ||
|
|
bd3b3ea12c | ||
|
|
7c6b6eae5b | ||
|
|
1208ca6a36 | ||
|
|
c182a5687e | ||
|
|
fd53c64d5d |
47
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
47
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Report a bug encountered while using ERPNext
|
||||
labels: bug
|
||||
---
|
||||
|
||||
<!--
|
||||
Welcome to ERPNext issue tracker! Before creating an issue, please heed the following:
|
||||
|
||||
1. This tracker should only be used to report bugs and request features / enhancements to ERPNext
|
||||
- For questions and general support, checkout the manual https://erpnext.com/docs/user/manual/en or use https://discuss.erpnext.com
|
||||
- For documentation issues, refer to https://github.com/frappe/erpnext_com
|
||||
2. Use the search function before creating a new issue. Duplicates will be closed and directed to
|
||||
the original discussion.
|
||||
3. When making a bug report, make sure you provide all required information. The easier it is for
|
||||
maintainers to reproduce, the faster it'll be fixed.
|
||||
4. If you think you know what the reason for the bug is, share it with us. Maybe put in a PR 😉
|
||||
-->
|
||||
|
||||
## Description of the issue
|
||||
|
||||
## Context information (for bug reports)
|
||||
|
||||
**Output of `bench version`**
|
||||
```
|
||||
(paste here)
|
||||
```
|
||||
|
||||
## Steps to reproduce the issue
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### Observed result
|
||||
|
||||
### Expected result
|
||||
|
||||
### Stacktrace / full error message
|
||||
|
||||
```
|
||||
(paste here)
|
||||
```
|
||||
|
||||
## Additional information
|
||||
|
||||
OS version / distribution, `ERPNext` install method, etc.
|
||||
28
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea to improve ERPNext
|
||||
labels: feature-request
|
||||
---
|
||||
|
||||
<!--
|
||||
Welcome to ERPNext issue tracker! Before creating an issue, please heed the following:
|
||||
|
||||
1. This tracker should only be used to report bugs and request features / enhancements to ERPNext
|
||||
- For questions and general support, checkout the manual https://erpnext.com/docs/user/manual/en or use https://discuss.erpnext.com
|
||||
- For documentation issues, refer to https://github.com/frappe/erpnext_com
|
||||
2. Use the search function before creating a new issue. Duplicates will be closed and directed to
|
||||
the original discussion.
|
||||
3. When making a feature request, make sure to be as verbose as possible. The better you convey your message, the greater the drive to make it happen.
|
||||
-->
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
17
.github/ISSUE_TEMPLATE/question-about-using-erpnext.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/question-about-using-erpnext.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Question about using ERPNext
|
||||
about: This is not the appropriate channel
|
||||
labels: invalid
|
||||
---
|
||||
|
||||
Please post on our forums:
|
||||
|
||||
for questions about using `ERPNext`: https://discuss.erpnext.com
|
||||
|
||||
for questions about using the `Frappe Framework`: https://discuss.frappe.io
|
||||
|
||||
for questions about using `bench`, probably the best place to start is the [bench repo](https://github.com/frappe/bench)
|
||||
|
||||
For documentation issues, use the [ERPNext Documentation](https://erpnext.com/docs/) or [Frappe Framework Documentation](https://frappe.io/docs/user/en) or the [developer cheetsheet](https://github.com/frappe/frappe/wiki/Developer-Cheatsheet)
|
||||
|
||||
> **Posts that are not bug reports or feature requests will not be addressed on this issue tracker.**
|
||||
33
.github/PULL_REQUEST_TEMPLATE.md
vendored
33
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,2 +1,33 @@
|
||||
Please read the pull request checklist to make sure your changes are merged: https://github.com/frappe/erpnext/wiki/Pull-Request-Checklist
|
||||
<!--
|
||||
|
||||
Some key notes before you open a PR:
|
||||
|
||||
1. Select which branch should this PR be merged in?
|
||||
2. PR name follows [convention](http://karma-runner.github.io/4.0/dev/git-commit-msg.html)
|
||||
3. All tests pass locally, UI and Unit tests
|
||||
4. All business logic and validations must be on the server-side
|
||||
5. Update necessary Documentation
|
||||
6. Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes
|
||||
|
||||
|
||||
Also, if you're new here
|
||||
|
||||
- Documentation Guidelines => https://github.com/frappe/erpnext/wiki/Updating-Documentation
|
||||
|
||||
- Contribution Guide => https://github.com/frappe/erpnext/blob/develop/.github/CONTRIBUTING.md
|
||||
|
||||
- Pull Request Checklist => https://github.com/frappe/erpnext/wiki/Pull-Request-Checklist
|
||||
|
||||
-->
|
||||
|
||||
> Please provide enough information so that others can review your pull request:
|
||||
|
||||
<!-- You can skip this if you're fixing a typo or updating existing documentation -->
|
||||
|
||||
> Explain the **details** for making this change. What existing problem does the pull request solve?
|
||||
|
||||
<!-- Example: When "Adding a function to do X", explain why it is necessary to have a way to do X. -->
|
||||
|
||||
> Screenshots/GIFs
|
||||
|
||||
<!-- Add images/recordings to better visualize the change: expected/current behviour -->
|
||||
|
||||
101
.travis.yml
101
.travis.yml
@@ -1,51 +1,80 @@
|
||||
language: python
|
||||
dist: trusty
|
||||
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.6"
|
||||
language: python
|
||||
|
||||
env:
|
||||
- TEST_TYPE="Server Side Test"
|
||||
- TEST_TYPE="Patch Test"
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
services:
|
||||
- mysql
|
||||
cache:
|
||||
- pip
|
||||
|
||||
addons:
|
||||
hosts: test_site
|
||||
mariadb: 10.3
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- name: "Python 2.7 Server Side Test"
|
||||
python: 2.7
|
||||
script: bench --site test_site run-tests --app erpnext --coverage
|
||||
|
||||
- name: "Python 3.6 Server Side Test"
|
||||
python: 3.6
|
||||
script: bench --site test_site run-tests --app erpnext --coverage
|
||||
|
||||
- name: "Python 2.7 Patch Test"
|
||||
python: 2.7
|
||||
before_script:
|
||||
- wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
|
||||
- bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz
|
||||
script: bench --site test_site migrate
|
||||
|
||||
- name: "Python 3.6 Patch Test"
|
||||
python: 3.6
|
||||
before_script:
|
||||
- wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
|
||||
- bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz
|
||||
script: bench --site test_site migrate
|
||||
|
||||
install:
|
||||
# fix mongodb travis error
|
||||
- sudo rm /etc/apt/sources.list.d/mongodb*.list
|
||||
- pip install flake8==3.3.0
|
||||
- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
|
||||
- sudo rm /etc/apt/sources.list.d/docker.list
|
||||
- sudo apt-get install hhvm && rm -rf /home/travis/.kiex/
|
||||
- sudo apt-get purge -y mysql-common mysql-server mysql-client
|
||||
- cd ~
|
||||
- nvm install 10
|
||||
- pip install python-coveralls
|
||||
- wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
|
||||
- sudo python install.py --develop --user travis --without-bench-setup
|
||||
- sudo pip install -e ~/bench
|
||||
|
||||
- rm $TRAVIS_BUILD_DIR/.git/shallow
|
||||
- bash $TRAVIS_BUILD_DIR/travis/bench_init.sh
|
||||
- cp -r $TRAVIS_BUILD_DIR/test_sites/test_site ~/frappe-bench/sites/
|
||||
- git clone https://github.com/frappe/bench --depth 1
|
||||
- pip install -e ./bench
|
||||
|
||||
before_script:
|
||||
- mysql -u root -ptravis -e 'create database test_frappe'
|
||||
- echo "USE mysql;\nCREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe';\nFLUSH PRIVILEGES;\n" | mysql -u root -ptravis
|
||||
- echo "USE mysql;\nGRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost';\n" | mysql -u root -ptravis
|
||||
- git clone https://github.com/frappe/frappe --branch $TRAVIS_BRANCH --depth 1
|
||||
- bench init --skip-assets --frappe-path ~/frappe --python $(which python) frappe-bench
|
||||
|
||||
- mkdir ~/frappe-bench/sites/test_site
|
||||
- cp -r $TRAVIS_BUILD_DIR/.travis/site_config.json ~/frappe-bench/sites/test_site/
|
||||
|
||||
- mysql -u root -e "SET GLOBAL character_set_server = 'utf8mb4'"
|
||||
- mysql -u root -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"
|
||||
|
||||
- mysql -u root -e "CREATE DATABASE test_frappe"
|
||||
- mysql -u root -e "CREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe'"
|
||||
- mysql -u root -e "GRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost'"
|
||||
|
||||
- mysql -u root -e "UPDATE mysql.user SET Password=PASSWORD('travis') WHERE User='root'"
|
||||
- mysql -u root -e "FLUSH PRIVILEGES"
|
||||
|
||||
- wget -O /tmp/wkhtmltox.tar.xz https://github.com/frappe/wkhtmltopdf/raw/master/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
|
||||
- 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
|
||||
|
||||
- cd ~/frappe-bench
|
||||
- bench get-app erpnext $TRAVIS_BUILD_DIR
|
||||
- bench use test_site
|
||||
- bench reinstall --mariadb-root-username root --mariadb-root-password travis --yes
|
||||
- bench scheduler disable
|
||||
- sed -i 's/9000/9001/g' sites/common_site_config.json
|
||||
- bench start &
|
||||
- sleep 10
|
||||
|
||||
script:
|
||||
- bash $TRAVIS_BUILD_DIR/travis/run-tests.sh
|
||||
- sed -i 's/watch:/# watch:/g' Procfile
|
||||
- sed -i 's/schedule:/# schedule:/g' Procfile
|
||||
- sed -i 's/socketio:/# socketio:/g' Procfile
|
||||
- sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile
|
||||
|
||||
- bench get-app erpnext $TRAVIS_BUILD_DIR
|
||||
- bench start &
|
||||
- bench --site test_site reinstall --yes
|
||||
|
||||
after_script:
|
||||
- pip install python-coveralls
|
||||
- coveralls -b apps/erpnext -d ../../sites/.coverage
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
"mail_login": "test@example.com",
|
||||
"mail_password": "test",
|
||||
"admin_password": "admin",
|
||||
"run_selenium_tests": 1,
|
||||
"root_login": "root",
|
||||
"root_password": "travis",
|
||||
"host_name": "http://localhost:8000",
|
||||
"host_name": "http://test_site:8000",
|
||||
"install_apps": ["erpnext"]
|
||||
}
|
||||
7
SECURITY.md
Normal file
7
SECURITY.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Security Policy
|
||||
|
||||
The ERPNext team and community take security issues seriously. To report a security issue, fill out the form at [https://erpnext.com/security/report](https://erpnext.com/security/report).
|
||||
|
||||
You can help us make ERPNext and all it's users more secure by following the [Reporting guidelines](https://erpnext.com/security).
|
||||
|
||||
We appreciate your efforts to responsibly disclose your findings. We'll endeavor to respond quickly, and will keep you updated throughout the process.
|
||||
@@ -5,7 +5,7 @@ import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
from frappe.utils import getdate
|
||||
|
||||
__version__ = '12.0.1'
|
||||
__version__ = '12.4.3'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
|
||||
@@ -3,6 +3,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 erpnext.accounts.report.general_ledger.general_ledger import execute
|
||||
from frappe.core.page.dashboard.dashboard import cache_source, get_from_date_from_timespan
|
||||
@@ -12,15 +13,26 @@ from frappe.utils.nestedset import get_descendants_of
|
||||
|
||||
@frappe.whitelist()
|
||||
@cache_source
|
||||
def get(chart_name=None, from_date = None, to_date = None):
|
||||
chart = frappe.get_doc('Dashboard Chart', chart_name)
|
||||
def get(chart_name = None, chart = None, no_cache = None, from_date = None, to_date = None):
|
||||
if chart_name:
|
||||
chart = frappe.get_doc('Dashboard Chart', chart_name)
|
||||
else:
|
||||
chart = frappe._dict(frappe.parse_json(chart))
|
||||
timespan = chart.timespan
|
||||
|
||||
if chart.timespan == 'Select Date Range':
|
||||
from_date = chart.from_date
|
||||
to_date = chart.to_date
|
||||
|
||||
timegrain = chart.time_interval
|
||||
filters = json.loads(chart.filters_json)
|
||||
filters = frappe.parse_json(chart.filters_json)
|
||||
|
||||
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 to_date:
|
||||
to_date = nowdate()
|
||||
if not from_date:
|
||||
@@ -81,7 +93,8 @@ def get_gl_entries(account, to_date):
|
||||
fields = ['posting_date', 'debit', 'credit'],
|
||||
filters = [
|
||||
dict(posting_date = ('<', to_date)),
|
||||
dict(account = ('in', child_accounts))
|
||||
dict(account = ('in', child_accounts)),
|
||||
dict(voucher_type = ('!=', 'Period Closing Voucher'))
|
||||
],
|
||||
order_by = 'posting_date asc')
|
||||
|
||||
|
||||
@@ -174,6 +174,8 @@ def make_gl_entries(doc, credit_account, debit_account, against,
|
||||
# GL Entry for crediting the amount in the deferred expense
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
|
||||
if amount == 0: return
|
||||
|
||||
gl_entries = []
|
||||
gl_entries.append(
|
||||
doc.get_gl_dict({
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -100,37 +100,25 @@ class Account(NestedSet):
|
||||
if ancestors:
|
||||
if frappe.get_value("Company", self.company, "allow_account_creation_against_child_company"):
|
||||
return
|
||||
frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
|
||||
|
||||
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")
|
||||
parent_acc_name, parent_acc_number = frappe.db.get_value('Account', self.parent_account, \
|
||||
["account_name", "account_number"])
|
||||
for d in frappe.db.get_values('Account',
|
||||
{"company": ["in", descendants], "account_name": parent_acc_name},
|
||||
{ "company": ["in", descendants], "account_name": parent_acc_name,
|
||||
"account_number": parent_acc_number },
|
||||
["company", "name"], as_dict=True):
|
||||
parent_acc_name_map[d["company"]] = d["name"]
|
||||
|
||||
if not parent_acc_name_map: return
|
||||
|
||||
for company in descendants:
|
||||
if not parent_acc_name_map.get(company):
|
||||
frappe.throw(_("While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA")
|
||||
.format(company, parent_acc_name))
|
||||
|
||||
doc = frappe.copy_doc(self)
|
||||
doc.flags.ignore_root_company_validation = True
|
||||
doc.update({
|
||||
"company": company,
|
||||
# parent account's currency should be passed down to child account's curreny
|
||||
# if it is None, it picks it up from default company currency, which might be unintended
|
||||
"account_currency": self.account_currency,
|
||||
"parent_account": parent_acc_name_map[company]
|
||||
})
|
||||
doc.save()
|
||||
frappe.msgprint(_("Account {0} is added in the child company {1}")
|
||||
.format(doc.name, company))
|
||||
self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name)
|
||||
|
||||
def validate_group_or_ledger(self):
|
||||
if self.get("__islocal"):
|
||||
@@ -172,6 +160,49 @@ class Account(NestedSet):
|
||||
if frappe.db.get_value("GL Entry", {"account": self.name}):
|
||||
frappe.throw(_("Currency can not be changed after making entries using some other currency"))
|
||||
|
||||
def create_account_for_child_company(self, parent_acc_name_map, descendants, parent_acc_name):
|
||||
for company in descendants:
|
||||
if not parent_acc_name_map.get(company):
|
||||
frappe.throw(_("While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA")
|
||||
.format(company, parent_acc_name))
|
||||
|
||||
filters = {
|
||||
"account_name": self.account_name,
|
||||
"company": company
|
||||
}
|
||||
|
||||
if self.account_number:
|
||||
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
|
||||
doc.update({
|
||||
"company": company,
|
||||
# parent account's currency should be passed down to child account's curreny
|
||||
# if it is None, it picks it up from default company currency, which might be unintended
|
||||
"account_currency": self.account_currency,
|
||||
"parent_account": parent_acc_name_map[company]
|
||||
})
|
||||
|
||||
doc.save()
|
||||
frappe.msgprint(_("Account {0} is added in the child company {1}")
|
||||
.format(doc.name, company))
|
||||
elif child_account:
|
||||
# update the parent company's value in child companies
|
||||
doc = frappe.get_doc("Account", child_account)
|
||||
parent_value_changed = False
|
||||
for field in ['account_type', 'account_currency',
|
||||
'freeze_account', 'balance_must_be']:
|
||||
if doc.get(field) != self.get(field):
|
||||
parent_value_changed = True
|
||||
doc.set(field, self.get(field))
|
||||
|
||||
if parent_value_changed:
|
||||
doc.save()
|
||||
|
||||
def convert_group_to_ledger(self):
|
||||
if self.check_if_child_exists():
|
||||
throw(_("Account with child nodes cannot be converted to ledger"))
|
||||
|
||||
@@ -121,7 +121,11 @@ frappe.treeview_settings["Account"] = {
|
||||
},
|
||||
onrender: function(node) {
|
||||
if(frappe.boot.user.can_read.indexOf("GL Entry") !== -1){
|
||||
var dr_or_cr = in_list(["Liability", "Income", "Equity"], node.data.root_type) ? "Cr" : "Dr";
|
||||
|
||||
// show Dr if positive since balance is calculated as debit - credit else show Cr
|
||||
let balance = node.data.balance_in_account_currency || node.data.balance;
|
||||
let dr_or_cr = balance > 0 ? "Dr": "Cr";
|
||||
|
||||
if (node.data && node.data.balance!==undefined) {
|
||||
$('<span class="balance-area pull-right text-muted small">'
|
||||
+ (node.data.balance_in_account_currency ?
|
||||
|
||||
@@ -406,7 +406,11 @@
|
||||
"is_group": 1,
|
||||
"Bewertungskorrektur zu Forderungen aus Lieferungen und Leistungen": {
|
||||
"account_number": "9960"
|
||||
},
|
||||
},
|
||||
"Debitoren": {
|
||||
"is_group": 1,
|
||||
"account_number": "10000"
|
||||
},
|
||||
"Forderungen aus Lieferungen und Leistungen": {
|
||||
"account_number": "1200",
|
||||
"account_type": "Receivable"
|
||||
@@ -1077,7 +1081,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"C - Verb.": {
|
||||
"C - Verbindlichkeiten": {
|
||||
"account_type": "Payable",
|
||||
"1 - Anleihen": {
|
||||
"is_group": 1,
|
||||
@@ -1193,7 +1197,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"
|
||||
}
|
||||
},
|
||||
"Verb. aus Lieferungen und Leistungen": {
|
||||
"account_number": "3300",
|
||||
"account_type": "Payable"
|
||||
@@ -1682,90 +1694,6 @@
|
||||
"account_type": "Income Account"
|
||||
}
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen (Gruppe)": {
|
||||
"is_group": 1,
|
||||
"Erl\u00f6sschm\u00e4lerungen": {
|
||||
"account_number": "4700"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen aus steuerfreien Ums\u00e4tzen \u00a7 4 Nr. 1a UStG": {
|
||||
"account_number": "4705"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen 7 % USt": {
|
||||
"account_number": "4710"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen 19 % USt": {
|
||||
"account_number": "4720"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen 16 % USt": {
|
||||
"account_number": "4723"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen aus steuerfreien innergem. Lieferungen": {
|
||||
"account_number": "4724"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 7 % USt": {
|
||||
"account_number": "4725"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 19 % USt": {
|
||||
"account_number": "4726"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen aus im anderen EU-Land steuerpfl. Lieferungen": {
|
||||
"account_number": "4727"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 16 % USt": {
|
||||
"account_number": "4729"
|
||||
},
|
||||
"Gew\u00e4hrte Skonti (Gruppe)": {
|
||||
"is_group": 1,
|
||||
"Gew. Skonti": {
|
||||
"account_number": "4730"
|
||||
},
|
||||
"Gew. Skonti 7 % USt": {
|
||||
"account_number": "4731"
|
||||
},
|
||||
"Gew. Skonti 19 % USt": {
|
||||
"account_number": "4736"
|
||||
},
|
||||
"Gew. Skonti aus Lieferungen von Mobilfunkger./Schaltkr., f. die der Leistungsempf. die Ust. schuldet": {
|
||||
"account_number": "4738"
|
||||
},
|
||||
"Gew. Skonti aus Leistungen, f. die der Leistungsempf. die Umsatzsteuer nach \u00a7 13b UStG schuldet": {
|
||||
"account_number": "4741"
|
||||
},
|
||||
"Gew. Skonti aus Erl\u00f6sen aus im anderen EU-Land steuerpfl. Leistungen, f. die der Leistungsempf. die Ust. schuldet": {
|
||||
"account_number": "4742"
|
||||
},
|
||||
"Gew. Skonti aus steuerfreien innergem. Lieferungen \u00a7 4 Nr. 1b UStG": {
|
||||
"account_number": "4743"
|
||||
},
|
||||
"Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen": {
|
||||
"account_number": "4745"
|
||||
},
|
||||
"Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 7% USt": {
|
||||
"account_number": "4746"
|
||||
},
|
||||
"Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 19% USt": {
|
||||
"account_number": "4748"
|
||||
}
|
||||
},
|
||||
"Gew\u00e4hrte Boni 7 % USt": {
|
||||
"account_number": "4750"
|
||||
},
|
||||
"Gew\u00e4hrte Boni 19 % USt": {
|
||||
"account_number": "4760"
|
||||
},
|
||||
"Gew\u00e4hrte Boni": {
|
||||
"account_number": "4769"
|
||||
},
|
||||
"Gew\u00e4hrte Rabatte": {
|
||||
"account_number": "4770"
|
||||
},
|
||||
"Gew\u00e4hrte Rabatte 7 % USt": {
|
||||
"account_number": "4780"
|
||||
},
|
||||
"Gew\u00e4hrte Rabatte 19 % USt": {
|
||||
"account_number": "4790"
|
||||
}
|
||||
},
|
||||
"Grundst\u00fccksertr\u00e4ge (Gruppe)": {
|
||||
"is_group": 1,
|
||||
"Grundst\u00fccksertr\u00e4ge": {
|
||||
@@ -2049,48 +1977,6 @@
|
||||
"Erh. Skonti aus Erwerb Waren als letzter Abnehmer innerh. Dreiecksgesch. 19% Vorst. u. 19% Ust.": {
|
||||
"account_number": "5793"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Bezugsnebenkosten (Gruppe)": {
|
||||
@@ -2409,7 +2295,49 @@
|
||||
},
|
||||
"6 - sonstige betriebliche Ertr\u00e4ge": {
|
||||
"root_type": "Income",
|
||||
"is_group": 1,
|
||||
"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"
|
||||
},
|
||||
@@ -2732,7 +2660,91 @@
|
||||
},
|
||||
"7 - sonstige betriebliche Aufwendungen": {
|
||||
"root_type": "Expense",
|
||||
"is_group": 1,
|
||||
"is_group": 1,
|
||||
"Erl\u00f6sschm\u00e4lerungen (Gruppe)": {
|
||||
"is_group": 1,
|
||||
"Erl\u00f6sschm\u00e4lerungen": {
|
||||
"account_number": "4700"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen aus steuerfreien Ums\u00e4tzen \u00a7 4 Nr. 1a UStG": {
|
||||
"account_number": "4705"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen 7 % USt": {
|
||||
"account_number": "4710"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen 19 % USt": {
|
||||
"account_number": "4720"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen 16 % USt": {
|
||||
"account_number": "4723"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen aus steuerfreien innergem. Lieferungen": {
|
||||
"account_number": "4724"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 7 % USt": {
|
||||
"account_number": "4725"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 19 % USt": {
|
||||
"account_number": "4726"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen aus im anderen EU-Land steuerpfl. Lieferungen": {
|
||||
"account_number": "4727"
|
||||
},
|
||||
"Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 16 % USt": {
|
||||
"account_number": "4729"
|
||||
},
|
||||
"Gew\u00e4hrte Skonti (Gruppe)": {
|
||||
"is_group": 1,
|
||||
"Gew. Skonti": {
|
||||
"account_number": "4730"
|
||||
},
|
||||
"Gew. Skonti 7 % USt": {
|
||||
"account_number": "4731"
|
||||
},
|
||||
"Gew. Skonti 19 % USt": {
|
||||
"account_number": "4736"
|
||||
},
|
||||
"Gew. Skonti aus Lieferungen von Mobilfunkger./Schaltkr., f. die der Leistungsempf. die Ust. schuldet": {
|
||||
"account_number": "4738"
|
||||
},
|
||||
"Gew. Skonti aus Leistungen, f. die der Leistungsempf. die Umsatzsteuer nach \u00a7 13b UStG schuldet": {
|
||||
"account_number": "4741"
|
||||
},
|
||||
"Gew. Skonti aus Erl\u00f6sen aus im anderen EU-Land steuerpfl. Leistungen, f. die der Leistungsempf. die Ust. schuldet": {
|
||||
"account_number": "4742"
|
||||
},
|
||||
"Gew. Skonti aus steuerfreien innergem. Lieferungen \u00a7 4 Nr. 1b UStG": {
|
||||
"account_number": "4743"
|
||||
},
|
||||
"Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen": {
|
||||
"account_number": "4745"
|
||||
},
|
||||
"Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 7% USt": {
|
||||
"account_number": "4746"
|
||||
},
|
||||
"Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 19% USt": {
|
||||
"account_number": "4748"
|
||||
}
|
||||
},
|
||||
"Gew\u00e4hrte Boni 7 % USt": {
|
||||
"account_number": "4750"
|
||||
},
|
||||
"Gew\u00e4hrte Boni 19 % USt": {
|
||||
"account_number": "4760"
|
||||
},
|
||||
"Gew\u00e4hrte Boni": {
|
||||
"account_number": "4769"
|
||||
},
|
||||
"Gew\u00e4hrte Rabatte": {
|
||||
"account_number": "4770"
|
||||
},
|
||||
"Gew\u00e4hrte Rabatte 7 % USt": {
|
||||
"account_number": "4780"
|
||||
},
|
||||
"Gew\u00e4hrte Rabatte 19 % USt": {
|
||||
"account_number": "4790"
|
||||
}
|
||||
},
|
||||
"Sonstige betriebliche Aufwendungen": {
|
||||
"account_number": "6300"
|
||||
},
|
||||
@@ -3609,18 +3621,6 @@
|
||||
"Ertr\u00e4ge aus der Aufl\u00f6sung von R\u00fcckstellungen f. sonstige Steuern": {
|
||||
"account_number": "7694"
|
||||
}
|
||||
},
|
||||
"Debitoren": {
|
||||
"root_type": "Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"Kreditoren": {
|
||||
"root_type": "Liability",
|
||||
"is_group": 1,
|
||||
"Wareneingangs-Verrechnungskonto" : {
|
||||
"account_number": "70001",
|
||||
"account_type": "Stock Received But Not Billed"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,809 @@
|
||||
{
|
||||
"country_code": "sv",
|
||||
"name": "El Salvador Standard",
|
||||
"tree": {
|
||||
"100000 - ACTIVOS - xmC": {
|
||||
"11000000 - ACTIVOS CORRIENTES - xmC": {
|
||||
"11010000 - EFECTIVO Y EQUIVALENTES AL EFECTIVO - xmC": {
|
||||
"11010100 - Caja general - xmC": {
|
||||
"account_number": "11010100",
|
||||
"account_type": "Cash"
|
||||
},
|
||||
"Caja chica": {
|
||||
"account_number": "11010200",
|
||||
"account_type": "Cash",
|
||||
"is_group": 1
|
||||
},
|
||||
"Efectivo en bancos": {
|
||||
"account_number": "11010300",
|
||||
"account_type": "Bank",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "11010000",
|
||||
"account_type": "Cash"
|
||||
},
|
||||
"CUENTAS POR COBRAR ARRENDAMIENTOS FINANCIEROS": {
|
||||
"Arrendamientos financieros por cobrar": {
|
||||
"account_number": "11040100",
|
||||
"is_group": 1
|
||||
},
|
||||
"Estimaci\u00f3n para cuentas de cobro dudoso (CR)": {
|
||||
"account_number": "11040200",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "11040000"
|
||||
},
|
||||
"DEUDORES COMERCIALES Y OTRAS CUENTAS POR COBRAR": {
|
||||
"11030100 - Deudores comerciales - xmC": {
|
||||
"account_number": "11030100",
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
"Estimaci\u00f3n para cuentas de cobro dudoso (CR)": {
|
||||
"account_number": "11030200",
|
||||
"account_type": "Receivable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Otras cuentas por cobrar no comerciales": {
|
||||
"account_number": "11030300",
|
||||
"account_type": "Receivable",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "11030000",
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
"GASTOS PAGADOS POR ANTICIPADO": {
|
||||
"Adelantos a empleados": {
|
||||
"account_number": "110904",
|
||||
"account_type": "Temporary",
|
||||
"is_group": 1
|
||||
},
|
||||
"Papeler\u00eda y \u00fatiles en existencia": {
|
||||
"account_number": "11090300",
|
||||
"account_type": "Temporary",
|
||||
"is_group": 1
|
||||
},
|
||||
"Primas de seguros aun no vendidas": {
|
||||
"account_number": "11090100",
|
||||
"account_type": "Temporary",
|
||||
"is_group": 1
|
||||
},
|
||||
"Rentas aun no corridas por los inmuebles": {
|
||||
"account_number": "11090200",
|
||||
"account_type": "Temporary",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "11090000",
|
||||
"account_type": "Temporary"
|
||||
},
|
||||
"INVENTARIOS": {
|
||||
"11050100 - Inventarios en bodega al costo - xmC": {
|
||||
"account_number": "11050100",
|
||||
"account_type": "Stock"
|
||||
},
|
||||
"11050300 - Pedidos en transito - xmC": {
|
||||
"account_number": "11050300",
|
||||
"account_type": "Stock Received But Not Billed"
|
||||
},
|
||||
"Estimaci\u00f3n para obsolescencia de inventarios o de lento movimiento (CR)": {
|
||||
"account_number": "11050200",
|
||||
"account_type": "Stock",
|
||||
"is_group": 1
|
||||
},
|
||||
"Mercader\u00edas en consignaci\u00f3n": {
|
||||
"account_number": "11050400",
|
||||
"account_type": "Stock",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "11050000",
|
||||
"account_type": "Stock"
|
||||
},
|
||||
"INVERSIONES TEMPORALES": {
|
||||
"Acciones": {
|
||||
"account_number": "11020100",
|
||||
"account_type": "Temporary",
|
||||
"is_group": 1
|
||||
},
|
||||
"Bonos": {
|
||||
"account_number": "11020200",
|
||||
"account_type": "Temporary",
|
||||
"is_group": 1
|
||||
},
|
||||
"C\u00e9dulas hipotecarias": {
|
||||
"account_number": "11020300",
|
||||
"account_type": "Temporary",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "11020000",
|
||||
"account_type": "Temporary"
|
||||
},
|
||||
"IVA CREDITO FISCAL": {
|
||||
"IVA compras locales": {
|
||||
"account_number": "11060100",
|
||||
"account_type": "Tax",
|
||||
"is_group": 1,
|
||||
"tax_rate": 13.0
|
||||
},
|
||||
"IVA importaciones": {
|
||||
"account_number": "11060200",
|
||||
"account_type": "Tax",
|
||||
"is_group": 1,
|
||||
"tax_rate": 13.0
|
||||
},
|
||||
"account_number": "11060000",
|
||||
"account_type": "Tax",
|
||||
"tax_rate": 13.0
|
||||
},
|
||||
"IVA PERCIBIDO": {
|
||||
"account_number": "IVA PERCIBIDO",
|
||||
"account_type": "Tax",
|
||||
"is_group": 1,
|
||||
"tax_rate": 1.0
|
||||
},
|
||||
"IVA RETENIDO": {
|
||||
"account_number": "11070000",
|
||||
"account_type": "Tax",
|
||||
"is_group": 1,
|
||||
"tax_rate": 1.0
|
||||
},
|
||||
"account_number": "11000000"
|
||||
},
|
||||
"12000000 - ACTIVOS NO CORRIENTES - xmC": {
|
||||
"ACTIVOS INTANGIBLES": {
|
||||
"Concesiones y franquicias": {
|
||||
"account_number": "12080300",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"Derechos de llave": {
|
||||
"account_number": "12080100",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"Patentes y marcas de fabrica": {
|
||||
"account_number": "12080200",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"Software": {
|
||||
"account_number": "12080400",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "12080000",
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"CUENTAS POR COBRAR ARRENDAMIENTOS FINANCIEROS A LARGO PLAZO": {
|
||||
"Arrendamientos financieros por cobrar a largo plazo": {
|
||||
"account_number": "12060100",
|
||||
"account_type": "Receivable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Estimaci\u00f3n para cuentas de cobro dudoso a largo plazo (CR)": {
|
||||
"account_number": "12060200",
|
||||
"account_type": "Receivable",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "12060000",
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
"DEPRECIACION ACUMULUDA (CR)": {
|
||||
"12030100 - Deprec. acumulada de propiedades, planta y equipo propio al costo - xmC": {
|
||||
"account_number": "12030100",
|
||||
"account_type": "Accumulated Depreciation"
|
||||
},
|
||||
"Deprec. acumulada de prop., planta y equipo bajo arrend. Financiero": {
|
||||
"account_number": "12030200",
|
||||
"account_type": "Accumulated Depreciation",
|
||||
"is_group": 1
|
||||
},
|
||||
"Deprec. acumulada de revaluaos de propiedades, planta y equipo": {
|
||||
"account_number": "12030300",
|
||||
"account_type": "Accumulated Depreciation",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "12030000",
|
||||
"account_type": "Accumulated Depreciation"
|
||||
},
|
||||
"DEUDORES COMERCIALES Y OTRAS CUENTAS POR COBRAR A LARGO PLAZO": {
|
||||
"12050100 - Deudores comerciales a largo plazo - xmC": {
|
||||
"account_number": "12050100",
|
||||
"account_type": "Receivable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Cuentas por cobrar no comerciales a largo plazo": {
|
||||
"account_number": "12050300",
|
||||
"account_type": "Receivable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Estimaci\u00f3n para cuentas de cobro dudoso a largo plazo (CR)": {
|
||||
"account_number": "12050200",
|
||||
"account_type": "Receivable",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "12050000",
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
"IMPUESTO SOBRE LA RENTA DIFERIDO-ACTIVO": {
|
||||
"12070200 - Pago anticipados de impuestos sobre la renta - xmC": {
|
||||
"account_number": "12070200",
|
||||
"account_type": "Temporary",
|
||||
"is_group": 1
|
||||
},
|
||||
"Cr\u00e9dito impuestos sobre la renta de a\u00f1os anteriores": {
|
||||
"account_number": "12070100",
|
||||
"account_type": "Tax",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "12070000",
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"INVERSIONES PERMANENTES": {
|
||||
"Inversiones en asociadas": {
|
||||
"account_number": "12040200",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"Inversiones en negocios conjuntos": {
|
||||
"account_number": "12040300",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"Inversiones en subsidiarias": {
|
||||
"account_number": "12040100",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "12040000",
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"PROPIEDADES, PLANTA Y EQUIPO": {
|
||||
"12010300 - Maquinarias y equipos - xmC": {
|
||||
"account_number": "12010300",
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"Edificios": {
|
||||
"account_number": "12010200",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"Mobiliario y equipo": {
|
||||
"account_number": "12010400",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"Terrenos": {
|
||||
"account_number": "12010100",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"Veh\u00edculos": {
|
||||
"account_number": "12010500",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "12010000",
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"REVALUACIONES DE PROPIEDADES, PLANTA Y EQUIPO": {
|
||||
"Revaluaci\u00f3n de edificios": {
|
||||
"account_number": "12020200",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"Revaluaci\u00f3n de maquinarias y equipo": {
|
||||
"account_number": "12020300",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"Revaluaci\u00f3n de mobiliario y equipo": {
|
||||
"account_number": "12020400",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"Revaluaci\u00f3n de terrenos": {
|
||||
"account_number": "12020100",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"Revaluaci\u00f3n de veh\u00edculos": {
|
||||
"account_number": "12020500",
|
||||
"account_type": "Fixed Asset",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "12020000",
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"account_number": "12000000",
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"account_number": "100000",
|
||||
"root_type": "Asset"
|
||||
},
|
||||
"20000000 - PASIVOS - xmC": {
|
||||
"PASIVOS CORRIENTES": {
|
||||
"ACREEDORES COMERCIALES Y OTRAS CUENTAS POR PAGAR": {
|
||||
"21020100 - Cuentas por pagar comerciales - xmC": {
|
||||
"account_number": "21020100",
|
||||
"account_type": "Payable"
|
||||
},
|
||||
"Documentos por pagar comerciales": {
|
||||
"account_number": "21020200",
|
||||
"account_type": "Payable",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "21020000",
|
||||
"account_type": "Payable"
|
||||
},
|
||||
"BENEFICIOS A EMPLEADOS POR PAGAR": {
|
||||
"Beneficios a corto plazo por pagar": {
|
||||
"account_number": "21050100",
|
||||
"account_type": "Payable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Beneficios post empleo por pagar": {
|
||||
"account_number": "21050200",
|
||||
"account_type": "Payable",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "21050000",
|
||||
"account_type": "Payable"
|
||||
},
|
||||
"DIVIDENDOS POR PAGAR": {
|
||||
"account_number": "21080000",
|
||||
"account_type": "Payable",
|
||||
"is_group": 1
|
||||
},
|
||||
"IMPUESTO SOBRE LA RENTA CORRIENTE POR PAGAR": {
|
||||
"account_number": "21070000",
|
||||
"account_type": "Tax",
|
||||
"is_group": 1
|
||||
},
|
||||
"IVA DEBITOS FISCALES": {
|
||||
"Por ventas a consumidores": {
|
||||
"account_number": "21060200",
|
||||
"account_type": "Tax",
|
||||
"is_group": 1
|
||||
},
|
||||
"Por ventas a contribuyentes": {
|
||||
"account_number": "21060100",
|
||||
"account_type": "Tax",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "21060000",
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"OBLIGACIONES BAJO ARRENDAMIENTOS FINANCIEROS PORCION CORRIENTE": {
|
||||
"Contratos bajo arrendamientos financieros": {
|
||||
"account_number": "21030100",
|
||||
"account_type": "Payable",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "21030000",
|
||||
"account_type": "Payable"
|
||||
},
|
||||
"OTROS ACREEDORES, RETENCIONES Y DESCUENTOS": {
|
||||
"Cuentas por pagar a accionistas": {
|
||||
"account_number": "21040400",
|
||||
"account_type": "Payable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Descuentos": {
|
||||
"account_number": "21040300",
|
||||
"account_type": "Payable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Otros acreedores": {
|
||||
"account_number": "21040100",
|
||||
"account_type": "Payable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Retenciones": {
|
||||
"account_number": "21040200",
|
||||
"account_type": "Payable",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "21040000",
|
||||
"account_type": "Payable"
|
||||
},
|
||||
"PRESTAMOS Y SOBREGIROS BANCARIOS": {
|
||||
"Porci\u00f3n corriente de prestamos bancarios a largo plazo": {
|
||||
"account_number": "21010300",
|
||||
"is_group": 1
|
||||
},
|
||||
"Prestamos bancarios a corto plazo": {
|
||||
"account_number": "21010100",
|
||||
"is_group": 1
|
||||
},
|
||||
"Sobregiros bancarios": {
|
||||
"account_number": "21010200",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "21010000"
|
||||
},
|
||||
"account_number": "21000000"
|
||||
},
|
||||
"PASIVOS NO CORRIENTES": {
|
||||
"ANTICIPOS Y GARANTIAS DE CLIENTES": {
|
||||
"Anticipos de clientes": {
|
||||
"account_number": "22040100",
|
||||
"account_type": "Temporary",
|
||||
"is_group": 1
|
||||
},
|
||||
"Garant\u00edas de clientes": {
|
||||
"account_number": "22040200",
|
||||
"account_type": "Temporary",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "22040000",
|
||||
"account_type": "Temporary"
|
||||
},
|
||||
"INTERES MINOTARIO": {
|
||||
"Inter\u00e9s de accionista minotarios": {
|
||||
"account_number": "22050100",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "22050000"
|
||||
},
|
||||
"OBLIGACIONES BAJO ARRENDAMIENTOS FINANCIEROS A LARGO PLAZO": {
|
||||
"Contratos bajo arrendamientos financieros": {
|
||||
"account_number": "22030100",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "22030000"
|
||||
},
|
||||
"OTROS PRESTAMOS A LARGO PLAZO": {
|
||||
"account_number": "22020000",
|
||||
"is_group": 1
|
||||
},
|
||||
"PRESTAMOS BANCARIOS A LARGO PLAZO": {
|
||||
"account_number": "22010000",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "22000000"
|
||||
},
|
||||
"PROVISIONES": {
|
||||
"IMPUESTOS SOBRE LA RENTA COMPLEMENTARIO": {
|
||||
"Ejercicios anteriores": {
|
||||
"account_number": "23010100",
|
||||
"account_type": "Tax",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "23010000",
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"PROVISION PARA OBLIGACIONES LABORALES": {
|
||||
"Indemnizaci\u00f3n": {
|
||||
"account_number": "23020100",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "23020000"
|
||||
},
|
||||
"account_number": "23000000"
|
||||
},
|
||||
"account_number": "20000000",
|
||||
"root_type": "Liability"
|
||||
},
|
||||
"30000000 - PATRIMONIO - xmC": {
|
||||
"CAPITAL, RESERVAS Y RESULTADOS": {
|
||||
"CAPITAL SOCIAL": {
|
||||
"Capital Social M\u00ednimo": {
|
||||
"Capital Social M\u00ednimo NO Pagado": {
|
||||
"account_number": "31010102",
|
||||
"account_type": "Equity",
|
||||
"is_group": 1
|
||||
},
|
||||
"Capital Social M\u00ednimo Suscrito": {
|
||||
"account_number": "31010101",
|
||||
"account_type": "Equity",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "31010100",
|
||||
"account_type": "Equity"
|
||||
},
|
||||
"Capital Social Variable": {
|
||||
"Capital Social Variable NO Pagado": {
|
||||
"account_number": "31010202",
|
||||
"account_type": "Equity",
|
||||
"is_group": 1
|
||||
},
|
||||
"Capital Social Variable Suscrito": {
|
||||
"account_number": "31010201",
|
||||
"account_type": "Equity",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "31010200",
|
||||
"account_type": "Equity"
|
||||
},
|
||||
"account_number": "31010000",
|
||||
"account_type": "Equity"
|
||||
},
|
||||
"DIVIDENDOS PAGADOS": {
|
||||
"account_number": "31060000",
|
||||
"account_type": "Equity",
|
||||
"is_group": 1
|
||||
},
|
||||
"GANANCIAS NO DISTRIBUIDAS": {
|
||||
"De ejercicios anteriores": {
|
||||
"account_number": "31020100",
|
||||
"account_type": "Equity",
|
||||
"is_group": 1
|
||||
},
|
||||
"Del presente ejercicio": {
|
||||
"account_number": "31020200",
|
||||
"account_type": "Equity",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "31020000",
|
||||
"account_type": "Equity"
|
||||
},
|
||||
"GANANCIAS RESTRINGIDAS": {
|
||||
"Reserva legal": {
|
||||
"account_number": "31030100",
|
||||
"account_type": "Equity",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "31030000",
|
||||
"account_type": "Equity"
|
||||
},
|
||||
"PERDIDAS ACUMULADAS (CR)": {
|
||||
"De ejercicios anteriores": {
|
||||
"account_number": "31050100",
|
||||
"account_type": "Equity",
|
||||
"is_group": 1
|
||||
},
|
||||
"Del presente ejercicio": {
|
||||
"account_number": "31050200",
|
||||
"account_type": "Equity",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "31050000",
|
||||
"account_type": "Equity"
|
||||
},
|
||||
"SUPERAVIT POR REVALUACIONES": {
|
||||
"Super\u00e1vit por revaluaci\u00f3n de activos": {
|
||||
"account_number": "31040100",
|
||||
"account_type": "Equity",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "31040000",
|
||||
"account_type": "Equity"
|
||||
},
|
||||
"account_number": "31000000",
|
||||
"account_type": "Equity"
|
||||
},
|
||||
"account_number": "30000000",
|
||||
"root_type": "Equity"
|
||||
},
|
||||
"40000000 - CUENTAS DE RESULTADO DEUDORAS - xmC": {
|
||||
"COSTOS Y GASTOS DE OPERACI\u00d3N": {
|
||||
"41010000 - COSTO DE LAS VENTAS - xmC": {
|
||||
"account_number": "41010000",
|
||||
"account_type": "Cost of Goods Sold"
|
||||
},
|
||||
"GASTOS DE DEPARTAMENTO DE OPERACIONES": {
|
||||
"41020600 - Depreciaciones y amortizaciones - xmC": {
|
||||
"account_number": "41020600",
|
||||
"account_type": "Depreciation"
|
||||
},
|
||||
"41020900 - Redondeos - xmC": {
|
||||
"account_number": "41020900",
|
||||
"account_type": "Round Off"
|
||||
},
|
||||
"Gastos operativos": {
|
||||
"account_number": "41020700",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Mantenimientos": {
|
||||
"account_number": "41020400",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Materiales y suministros": {
|
||||
"Ajustes de Inventario": {
|
||||
"account_number": "41020201",
|
||||
"account_type": "Stock Adjustment"
|
||||
},
|
||||
"account_number": "41020200",
|
||||
"account_type": "Chargeable"
|
||||
},
|
||||
"Seguros": {
|
||||
"account_number": "41020500",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Servicios b\u00e1sicos": {
|
||||
"account_number": "41020300",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Servicios y honorarios profesionales": {
|
||||
"account_number": "41020800",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Sueldos y prestaciones laborales": {
|
||||
"account_number": "41020100",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "41020000",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"GASTOS DE VENTAS Y DISTRIBUCION": {
|
||||
"Depreciaciones y amortizaciones": {
|
||||
"account_number": "41030600",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Gastos operativos": {
|
||||
"account_number": "41030700",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Mantenimientos": {
|
||||
"account_number": "41030400",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Materiales y suministros": {
|
||||
"account_number": "41030200",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Seguros": {
|
||||
"account_number": "41030500",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Servicios b\u00e1sicos": {
|
||||
"account_number": "41030300",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Servicios y honorarios profesionales": {
|
||||
"account_number": "41030800",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"Sueldos y prestaciones laborales": {
|
||||
"account_number": "41030100",
|
||||
"account_type": "Chargeable",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "41030000",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"account_number": "41000000",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"GASTOS DE IMPUESTO SOBRE LA RENTA": {
|
||||
"GASTOS DE IMPUESTO SOBRE LA RENTA CORRIENTE": {
|
||||
"account_number": "43010000",
|
||||
"account_type": "Expense Account",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "43000000",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"GASTOS DE NO OPERACI\u00d3N": {
|
||||
"42020000 - GASTOS NO DEDUCIBLES - xmC": {
|
||||
"Garant\u00eda por venta de productos": {
|
||||
"account_number": "42020200",
|
||||
"account_type": "Expense Account",
|
||||
"is_group": 1
|
||||
},
|
||||
"Impuesto sobre la renta complementario": {
|
||||
"account_number": "42020100",
|
||||
"account_type": "Tax",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "42020000",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"GASTOS FINANCIEROS": {
|
||||
"42010100 - Intereses - xmC": {
|
||||
"account_number": "42010100",
|
||||
"account_type": "Expense Account",
|
||||
"is_group": 1
|
||||
},
|
||||
"42010300 - Diferenciales cambiarios - xmC": {
|
||||
"account_number": "42010300",
|
||||
"account_type": "Expense Account",
|
||||
"is_group": 1
|
||||
},
|
||||
"Comisiones bancarias": {
|
||||
"account_number": "42010200",
|
||||
"account_type": "Expense Account",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "42010000",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"account_number": "42000000",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"account_number": "40000000",
|
||||
"root_type": "Expense"
|
||||
},
|
||||
"50000000 - CUENTAS DE RESULTADO ACREEDORAS - xmC": {
|
||||
"INGRESOS DE NO OPERACI\u00d3N": {
|
||||
"DIVIDENDOS GANADOS": {
|
||||
"Dividendos devengados por inversiones": {
|
||||
"account_number": "52020100",
|
||||
"account_type": "Income Account",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "52020000",
|
||||
"account_type": "Income Account"
|
||||
},
|
||||
"INGRESOS FINANCIEROS": {
|
||||
"Comisiones": {
|
||||
"account_number": "52010200",
|
||||
"account_type": "Income Account",
|
||||
"is_group": 1
|
||||
},
|
||||
"Diferenciales cambiarios": {
|
||||
"account_number": "52010300",
|
||||
"account_type": "Income Account",
|
||||
"is_group": 1
|
||||
},
|
||||
"Intereses": {
|
||||
"account_number": "52010100",
|
||||
"account_type": "Income Account",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "52010000",
|
||||
"account_type": "Income Account"
|
||||
},
|
||||
"OTROS INGRESOS": {
|
||||
"Ingresos por activos dados en arrendamientos financieros": {
|
||||
"account_number": "52030200",
|
||||
"account_type": "Income Account",
|
||||
"is_group": 1
|
||||
},
|
||||
"Ingresos por conversi\u00f3n": {
|
||||
"account_number": "52030100",
|
||||
"account_type": "Income Account",
|
||||
"is_group": 1
|
||||
},
|
||||
"Reintegros de seguros": {
|
||||
"account_number": "52030300",
|
||||
"account_type": "Income Account",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "52030000",
|
||||
"account_type": "Income Account"
|
||||
},
|
||||
"account_number": "52000000",
|
||||
"account_type": "Income Account"
|
||||
},
|
||||
"INGRESOS POR OPERACIONES CONTINUAS": {
|
||||
"51010000 - VENTAS DE BIENES - xmC": {
|
||||
"account_number": "51010000",
|
||||
"account_type": "Income Account"
|
||||
},
|
||||
"VENTAS DE SERVICIOS": {
|
||||
"account_number": "51020000",
|
||||
"account_type": "Income Account",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "51000000",
|
||||
"account_type": "Income Account"
|
||||
},
|
||||
"account_number": "50000000",
|
||||
"root_type": "Income"
|
||||
},
|
||||
"60000000 - CUENTA LIQUIDADORA DE RESULTADOS - xmC": {
|
||||
"CUENTA DE CIERRE": {
|
||||
"PERDIDAS Y GANANCIAS": {
|
||||
"account_number": "61010000",
|
||||
"is_group": 1
|
||||
},
|
||||
"account_number": "61000000"
|
||||
},
|
||||
"account_number": "60000000",
|
||||
"root_type": "Income"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,7 @@ def _make_test_records(verbose):
|
||||
["_Test Payable USD", "Current Liabilities", 0, "Payable", "USD"]
|
||||
]
|
||||
|
||||
for company, abbr in [["_Test Company", "_TC"], ["_Test Company 1", "_TC1"]]:
|
||||
for company, abbr in [["_Test Company", "_TC"], ["_Test Company 1", "_TC1"], ["_Test Company with perpetual inventory", "TCP1"]]:
|
||||
test_objects = make_test_objects("Account", [{
|
||||
"doctype": "Account",
|
||||
"account_name": account_name,
|
||||
|
||||
@@ -4,45 +4,56 @@
|
||||
frappe.ui.form.on('Accounting Dimension', {
|
||||
|
||||
refresh: function(frm) {
|
||||
if (!frm.is_new()) {
|
||||
frm.add_custom_button(__('Show {0}', [frm.doc.document_type]), function () {
|
||||
frappe.set_route("List", frm.doc.document_type);
|
||||
});
|
||||
}
|
||||
|
||||
frm.set_query('document_type', () => {
|
||||
let invalid_doctypes = frappe.model.core_doctypes_list;
|
||||
invalid_doctypes.push('Accounting Dimension', 'Project',
|
||||
'Cost Center', 'Accounting Dimension Detail');
|
||||
|
||||
return {
|
||||
filters: {
|
||||
name: ['not in', ['Accounting Dimension', 'Project', 'Cost Center']]
|
||||
name: ['not in', invalid_doctypes]
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
let button = frm.doc.disabled ? "Enable" : "Disable";
|
||||
|
||||
frm.add_custom_button(__(button), function() {
|
||||
|
||||
frm.set_value('disabled', 1 - frm.doc.disabled);
|
||||
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.disable_dimension",
|
||||
args: {
|
||||
doc: frm.doc
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
let message = frm.doc.disabled ? "Dimension Disabled" : "Dimension Enabled";
|
||||
frm.save();
|
||||
frappe.show_alert({message:__(message), indicator:'green'});
|
||||
}
|
||||
if (!frm.is_new()) {
|
||||
frm.add_custom_button(__('Show {0}', [frm.doc.document_type]), function () {
|
||||
frappe.set_route("List", frm.doc.document_type);
|
||||
});
|
||||
});
|
||||
|
||||
let button = frm.doc.disabled ? "Enable" : "Disable";
|
||||
|
||||
frm.add_custom_button(__(button), function() {
|
||||
|
||||
frm.set_value('disabled', 1 - frm.doc.disabled);
|
||||
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.disable_dimension",
|
||||
args: {
|
||||
doc: frm.doc
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
let message = frm.doc.disabled ? "Dimension Disabled" : "Dimension Enabled";
|
||||
frm.save();
|
||||
frappe.show_alert({message:__(message), indicator:'green'});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
document_type: function(frm) {
|
||||
|
||||
frm.set_value('label', frm.doc.document_type);
|
||||
frm.set_value('fieldname', frappe.model.scrub(frm.doc.document_type));
|
||||
|
||||
if (frm.is_new()){
|
||||
let row = frappe.model.add_child(frm.doc, "Accounting Dimension Detail", "dimension_defaults");
|
||||
row.reference_document = frm.doc.document_type;
|
||||
frm.refresh_fields("dimension_defaults");
|
||||
}
|
||||
|
||||
frappe.db.get_value('Accounting Dimension', {'document_type': frm.doc.document_type}, 'document_type', (r) => {
|
||||
if (r && r.document_type) {
|
||||
frm.set_df_property('document_type', 'description', "Document type is already set as dimension");
|
||||
@@ -50,3 +61,10 @@ frappe.ui.form.on('Accounting Dimension', {
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
frappe.ui.form.on('Accounting Dimension Detail', {
|
||||
dimension_defaults_add: function(frm, cdt, cdn) {
|
||||
let row = locals[cdt][cdn];
|
||||
row.reference_document = frm.doc.document_type;
|
||||
}
|
||||
});
|
||||
@@ -1,6 +1,4 @@
|
||||
{
|
||||
"_comments": "[]",
|
||||
"_liked_by": "[]",
|
||||
"autoname": "field:label",
|
||||
"creation": "2019-05-04 18:13:37.002352",
|
||||
"doctype": "DocType",
|
||||
@@ -9,8 +7,7 @@
|
||||
"document_type",
|
||||
"label",
|
||||
"fieldname",
|
||||
"mandatory_for_bs",
|
||||
"mandatory_for_pl",
|
||||
"dimension_defaults",
|
||||
"disabled"
|
||||
],
|
||||
"fields": [
|
||||
@@ -43,19 +40,13 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "mandatory_for_bs",
|
||||
"fieldtype": "Check",
|
||||
"label": "Mandatory For Balance Sheet"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "mandatory_for_pl",
|
||||
"fieldtype": "Check",
|
||||
"label": "Mandatory For Profit and Loss Account"
|
||||
"fieldname": "dimension_defaults",
|
||||
"fieldtype": "Table",
|
||||
"label": "Dimension Defaults",
|
||||
"options": "Accounting Dimension Detail"
|
||||
}
|
||||
],
|
||||
"modified": "2019-07-14 17:25:01.307948",
|
||||
"modified": "2019-07-17 16:49:31.134385",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounting Dimension",
|
||||
|
||||
@@ -11,10 +11,25 @@ from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
from frappe import scrub
|
||||
from frappe.utils import cstr
|
||||
from frappe.utils.background_jobs import enqueue
|
||||
from frappe.model import core_doctypes_list
|
||||
|
||||
class AccountingDimension(Document):
|
||||
def before_insert(self):
|
||||
self.set_fieldname_and_label()
|
||||
|
||||
def validate(self):
|
||||
if self.document_type in core_doctypes_list + ('Accounting Dimension', 'Project',
|
||||
'Cost Center', 'Accounting Dimension Detail') :
|
||||
|
||||
msg = _("Not allowed to create accounting dimension for {0}").format(self.document_type)
|
||||
frappe.throw(msg)
|
||||
|
||||
exists = frappe.db.get_value("Accounting Dimension", {'document_type': self.document_type}, ['name'])
|
||||
|
||||
if exists and self.is_new():
|
||||
frappe.throw("Document Type already used as a dimension")
|
||||
|
||||
def after_insert(self):
|
||||
if frappe.flags.in_test:
|
||||
make_dimension_in_accounting_doctypes(doc=self)
|
||||
else:
|
||||
@@ -50,7 +65,8 @@ def make_dimension_in_accounting_doctypes(doc):
|
||||
"label": doc.label,
|
||||
"fieldtype": "Link",
|
||||
"options": doc.document_type,
|
||||
"insert_after": insert_after_field
|
||||
"insert_after": insert_after_field,
|
||||
"owner": "Administrator"
|
||||
}
|
||||
|
||||
if doctype == "Budget":
|
||||
@@ -96,13 +112,13 @@ def delete_accounting_dimension(doc):
|
||||
|
||||
frappe.db.sql("""
|
||||
DELETE FROM `tabCustom Field`
|
||||
WHERE fieldname = %s
|
||||
WHERE fieldname = %s
|
||||
AND dt IN (%s)""" % #nosec
|
||||
('%s', ', '.join(['%s']* len(doclist))), tuple([doc.fieldname] + doclist))
|
||||
|
||||
frappe.db.sql("""
|
||||
DELETE FROM `tabProperty Setter`
|
||||
WHERE field_name = %s
|
||||
WHERE field_name = %s
|
||||
AND doc_type IN (%s)""" % #nosec
|
||||
('%s', ', '.join(['%s']* len(doclist))), tuple([doc.fieldname] + doclist))
|
||||
|
||||
@@ -150,14 +166,40 @@ def get_doctypes_with_dimensions():
|
||||
"Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item", "Purchase Receipt Item",
|
||||
"Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
|
||||
"Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation",
|
||||
"Travel Request", "Fees", "POS Profile"]
|
||||
"Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item", "Subscription",
|
||||
"Subscription Plan"]
|
||||
|
||||
return doclist
|
||||
|
||||
def get_accounting_dimensions(as_list=True):
|
||||
accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "mandatory_for_pl", "mandatory_for_bs", "disabled"], filters={"disabled": 0})
|
||||
accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "disabled"])
|
||||
|
||||
if as_list:
|
||||
return [d.fieldname for d in accounting_dimensions]
|
||||
else:
|
||||
return accounting_dimensions
|
||||
|
||||
def get_checks_for_pl_and_bs_accounts():
|
||||
dimensions = frappe.db.sql("""SELECT p.label, p.disabled, p.fieldname, c.default_dimension, c.company, c.mandatory_for_pl, c.mandatory_for_bs
|
||||
FROM `tabAccounting Dimension`p ,`tabAccounting Dimension Detail` c
|
||||
WHERE p.name = c.parent""", as_dict=1)
|
||||
|
||||
return dimensions
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_dimension_filters():
|
||||
dimension_filters = frappe.db.sql("""
|
||||
SELECT label, fieldname, document_type
|
||||
FROM `tabAccounting Dimension`
|
||||
WHERE disabled = 0
|
||||
""", as_dict=1)
|
||||
|
||||
default_dimensions = frappe.db.sql("""SELECT parent, company, default_dimension
|
||||
FROM `tabAccounting Dimension Detail`""", as_dict=1)
|
||||
|
||||
default_dimensions_map = {}
|
||||
for dimension in default_dimensions:
|
||||
default_dimensions_map.setdefault(dimension['company'], {})
|
||||
default_dimensions_map[dimension['company']][dimension['parent']] = dimension['default_dimension']
|
||||
|
||||
return dimension_filters, default_dimensions_map
|
||||
|
||||
@@ -27,12 +27,20 @@ class TestAccountingDimension(unittest.TestCase):
|
||||
dimension1 = frappe.get_doc({
|
||||
"doctype": "Accounting Dimension",
|
||||
"document_type": "Location",
|
||||
"mandatory_for_pl": 1
|
||||
}).insert()
|
||||
})
|
||||
|
||||
dimension1.append("dimension_defaults", {
|
||||
"company": "_Test Company",
|
||||
"reference_document": "Location",
|
||||
"default_dimension": "Block 1",
|
||||
"mandatory_for_bs": 1
|
||||
})
|
||||
|
||||
dimension1.insert()
|
||||
dimension1.save()
|
||||
else:
|
||||
dimension1 = frappe.get_doc("Accounting Dimension", "Location")
|
||||
dimension1.disabled = 0
|
||||
dimension1.mandatory_for_pl = 1
|
||||
dimension1.save()
|
||||
|
||||
def test_dimension_against_sales_invoice(self):
|
||||
@@ -100,7 +108,6 @@ def disable_dimension():
|
||||
dimension1.save()
|
||||
|
||||
dimension2 = frappe.get_doc("Accounting Dimension", "Location")
|
||||
dimension2.mandatory_for_pl = 0
|
||||
dimension2.disabled = 1
|
||||
dimension2.save()
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"creation": "2019-07-16 17:53:18.718831",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"company",
|
||||
"reference_document",
|
||||
"default_dimension",
|
||||
"mandatory_for_bs",
|
||||
"mandatory_for_pl"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Company",
|
||||
"options": "Company"
|
||||
},
|
||||
{
|
||||
"fieldname": "reference_document",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"label": "Reference Document",
|
||||
"options": "DocType",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "default_dimension",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Default Dimension",
|
||||
"options": "reference_document"
|
||||
},
|
||||
{
|
||||
"columns": 3,
|
||||
"default": "0",
|
||||
"fieldname": "mandatory_for_bs",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Mandatory For Balance Sheet"
|
||||
},
|
||||
{
|
||||
"columns": 3,
|
||||
"default": "0",
|
||||
"fieldname": "mandatory_for_pl",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Mandatory For Profit and Loss Account"
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"modified": "2019-08-15 11:59:09.389891",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounting Dimension Detail",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class AccountingDimensionDetail(Document):
|
||||
pass
|
||||
@@ -167,39 +167,7 @@
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Open\nClosed",
|
||||
"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": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@@ -273,7 +241,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-04-13 19:14:47.593753",
|
||||
"modified": "2019-08-01 19:14:47.593753",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounting Period",
|
||||
|
||||
@@ -7,6 +7,8 @@ import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
|
||||
class OverlapError(frappe.ValidationError): pass
|
||||
|
||||
class AccountingPeriod(Document):
|
||||
def validate(self):
|
||||
self.validate_overlap()
|
||||
@@ -34,12 +36,13 @@ class AccountingPeriod(Document):
|
||||
}, as_dict=True)
|
||||
|
||||
if len(existing_accounting_period) > 0:
|
||||
frappe.throw(_("Accounting Period overlaps with {0}".format(existing_accounting_period[0].get("name"))))
|
||||
frappe.throw(_("Accounting Period overlaps with {0}")
|
||||
.format(existing_accounting_period[0].get("name")), OverlapError)
|
||||
|
||||
def get_doctypes_for_closing(self):
|
||||
docs_for_closing = []
|
||||
#if not self.closed_documents or len(self.closed_documents) == 0:
|
||||
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)
|
||||
@@ -52,4 +55,4 @@ class AccountingPeriod(Document):
|
||||
self.append('closed_documents', {
|
||||
"document_type": doctype_for_closing.document_type,
|
||||
"closed": doctype_for_closing.closed
|
||||
})
|
||||
})
|
||||
@@ -5,23 +5,42 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
from frappe.utils import nowdate, add_months
|
||||
from erpnext.accounts.general_ledger import ClosedAccountingPeriod
|
||||
from erpnext.accounts.doctype.accounting_period.accounting_period import OverlapError
|
||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||
|
||||
# class TestAccountingPeriod(unittest.TestCase):
|
||||
# def test_overlap(self):
|
||||
# ap1 = create_accounting_period({"start_date":"2018-04-01", "end_date":"2018-06-30", "company":"Wind Power LLC"})
|
||||
# ap1.save()
|
||||
# ap2 = create_accounting_period({"start_date":"2018-06-30", "end_date":"2018-07-10", "company":"Wind Power LLC"})
|
||||
# self.assertRaises(frappe.OverlapError, accounting_period_2.save())
|
||||
#
|
||||
# def tearDown(self):
|
||||
# pass
|
||||
#
|
||||
#
|
||||
# def create_accounting_period(**args):
|
||||
# accounting_period = frappe.new_doc("Accounting Period")
|
||||
# accounting_period.start_date = args.start_date or frappe.utils.datetime.date(2018, 4, 1)
|
||||
# accounting_period.end_date = args.end_date or frappe.utils.datetime.date(2018, 6, 30)
|
||||
# accounting_period.company = args.company
|
||||
# accounting_period.period_name = "_Test_Period_Name_1"
|
||||
#
|
||||
# return accounting_period
|
||||
class TestAccountingPeriod(unittest.TestCase):
|
||||
def test_overlap(self):
|
||||
ap1 = create_accounting_period(start_date = "2018-04-01",
|
||||
end_date = "2018-06-30", company = "Wind Power LLC")
|
||||
ap1.save()
|
||||
|
||||
ap2 = create_accounting_period(start_date = "2018-06-30",
|
||||
end_date = "2018-07-10", company = "Wind Power LLC", period_name = "Test Accounting Period 1")
|
||||
self.assertRaises(OverlapError, ap2.save)
|
||||
|
||||
def test_accounting_period(self):
|
||||
ap1 = create_accounting_period(period_name = "Test Accounting Period 2")
|
||||
ap1.save()
|
||||
|
||||
doc = create_sales_invoice(do_not_submit=1, cost_center = "_Test Company - _TC", warehouse = "Stores - _TC")
|
||||
self.assertRaises(ClosedAccountingPeriod, doc.submit)
|
||||
|
||||
def tearDown(self):
|
||||
for d in frappe.get_all("Accounting Period"):
|
||||
frappe.delete_doc("Accounting Period", d.name)
|
||||
|
||||
def create_accounting_period(**args):
|
||||
args = frappe._dict(args)
|
||||
|
||||
accounting_period = frappe.new_doc("Accounting Period")
|
||||
accounting_period.start_date = args.start_date or nowdate()
|
||||
accounting_period.end_date = args.end_date or add_months(nowdate(), 1)
|
||||
accounting_period.company = args.company or "_Test Company"
|
||||
accounting_period.period_name =args.period_name or "_Test_Period_Name_1"
|
||||
accounting_period.append("closed_documents", {
|
||||
"document_type": 'Sales Invoice', "closed": 1
|
||||
})
|
||||
|
||||
return accounting_period
|
||||
@@ -15,8 +15,8 @@ class AccountsSettings(Document):
|
||||
frappe.clear_cache()
|
||||
|
||||
def validate(self):
|
||||
for f in ["add_taxes_from_item_tax_template"]:
|
||||
frappe.db.set_default(f, self.get(f, ""))
|
||||
frappe.db.set_default("add_taxes_from_item_tax_template",
|
||||
self.get("add_taxes_from_item_tax_template", 0))
|
||||
|
||||
self.validate_stale_days()
|
||||
self.enable_payment_schedule_in_print()
|
||||
|
||||
@@ -8,11 +8,8 @@ def get_data():
|
||||
'fieldname': 'bank',
|
||||
'transactions': [
|
||||
{
|
||||
'label': _('Bank Deatils'),
|
||||
'label': _('Bank Details'),
|
||||
'items': ['Bank Account', 'Bank Guarantee']
|
||||
},
|
||||
{
|
||||
'items': ['Payment Order']
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ frappe.ui.form.on('Bank Account', {
|
||||
},
|
||||
refresh: function(frm) {
|
||||
frappe.dynamic_link = { doc: frm.doc, fieldname: 'name', doctype: 'Bank Account' }
|
||||
|
||||
|
||||
frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
|
||||
|
||||
if (frm.doc.__islocal) {
|
||||
@@ -37,5 +37,9 @@ frappe.ui.form.on('Bank Account', {
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
is_company_account: function(frm) {
|
||||
frm.set_df_property('account', 'reqd', frm.doc.is_company_account);
|
||||
}
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,12 +9,11 @@ def get_data():
|
||||
'non_standard_fieldnames': {
|
||||
'Customer': 'default_bank_account',
|
||||
'Supplier': 'default_bank_account',
|
||||
'Journal Entry': 'bank_account_no'
|
||||
},
|
||||
'transactions': [
|
||||
{
|
||||
'label': _('Payments'),
|
||||
'items': ['Payment Entry', 'Payment Request', 'Payment Order']
|
||||
'items': ['Payment Entry', 'Payment Request', 'Payment Order', 'Payroll Entry']
|
||||
},
|
||||
{
|
||||
'label': _('Party'),
|
||||
|
||||
@@ -45,12 +45,12 @@ class BankTransaction(StatusUpdater):
|
||||
def clear_linked_payment_entries(self):
|
||||
for payment_entry in self.payment_entries:
|
||||
allocated_amount = get_total_allocated_amount(payment_entry)
|
||||
paid_amount = get_paid_amount(payment_entry)
|
||||
paid_amount = get_paid_amount(payment_entry, self.currency)
|
||||
|
||||
if paid_amount and allocated_amount:
|
||||
if flt(allocated_amount[0]["allocated_amount"]) > flt(paid_amount):
|
||||
frappe.throw(_("The total allocated amount ({0}) is greated than the paid amount ({1}).".format(flt(allocated_amount[0]["allocated_amount"]), flt(paid_amount))))
|
||||
elif flt(allocated_amount[0]["allocated_amount"]) == flt(paid_amount):
|
||||
else:
|
||||
if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
|
||||
self.clear_simple_entry(payment_entry)
|
||||
|
||||
@@ -80,9 +80,17 @@ def get_total_allocated_amount(payment_entry):
|
||||
AND
|
||||
bt.docstatus = 1""", (payment_entry.payment_document, payment_entry.payment_entry), as_dict=True)
|
||||
|
||||
def get_paid_amount(payment_entry):
|
||||
def get_paid_amount(payment_entry, currency):
|
||||
if payment_entry.payment_document in ["Payment Entry", "Sales Invoice", "Purchase Invoice"]:
|
||||
return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "paid_amount")
|
||||
|
||||
paid_amount_field = "paid_amount"
|
||||
if payment_entry.payment_document == 'Payment Entry':
|
||||
doc = frappe.get_doc("Payment Entry", payment_entry.payment_entry)
|
||||
paid_amount_field = ("base_paid_amount"
|
||||
if doc.paid_to_account_currency == currency else "paid_amount")
|
||||
|
||||
return frappe.db.get_value(payment_entry.payment_document,
|
||||
payment_entry.payment_entry, paid_amount_field)
|
||||
|
||||
elif payment_entry.payment_document == "Journal Entry":
|
||||
return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "total_credit")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,32 +11,32 @@ from erpnext.buying.doctype.purchase_order.test_purchase_order import create_pur
|
||||
from erpnext.accounts.doctype.budget.budget import get_actual_expense, BudgetError
|
||||
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
|
||||
|
||||
class TestBudget(unittest.TestCase):
|
||||
class TestBudget(unittest.TestCase):
|
||||
def test_monthly_budget_crossed_ignore(self):
|
||||
set_total_expense_zero("2013-02-28", "Cost Center")
|
||||
|
||||
budget = make_budget(budget_against="Cost Center")
|
||||
|
||||
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
|
||||
|
||||
self.assertTrue(frappe.db.get_value("GL Entry",
|
||||
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
|
||||
|
||||
|
||||
budget.cancel()
|
||||
|
||||
def test_monthly_budget_crossed_stop1(self):
|
||||
set_total_expense_zero("2013-02-28", "Cost Center")
|
||||
|
||||
budget = make_budget(budget_against="Cost Center")
|
||||
|
||||
|
||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-02-28")
|
||||
|
||||
self.assertRaises(BudgetError, jv.submit)
|
||||
|
||||
|
||||
budget.load_from_db()
|
||||
budget.cancel()
|
||||
|
||||
@@ -46,7 +46,7 @@ class TestBudget(unittest.TestCase):
|
||||
budget = make_budget(budget_against="Cost Center")
|
||||
|
||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||
|
||||
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-03-02")
|
||||
|
||||
@@ -117,14 +117,14 @@ class TestBudget(unittest.TestCase):
|
||||
set_total_expense_zero("2013-02-28", "Project")
|
||||
|
||||
budget = make_budget(budget_against="Project")
|
||||
|
||||
|
||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", project="_Test Project", posting_date="2013-02-28")
|
||||
|
||||
self.assertRaises(BudgetError, jv.submit)
|
||||
|
||||
|
||||
budget.load_from_db()
|
||||
budget.cancel()
|
||||
|
||||
@@ -132,31 +132,31 @@ class TestBudget(unittest.TestCase):
|
||||
set_total_expense_zero("2013-02-28", "Cost Center")
|
||||
|
||||
budget = make_budget(budget_against="Cost Center")
|
||||
|
||||
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Bank - _TC", 150000, "_Test Cost Center - _TC", posting_date="2013-03-28")
|
||||
|
||||
self.assertRaises(BudgetError, jv.submit)
|
||||
|
||||
|
||||
budget.cancel()
|
||||
|
||||
def test_yearly_budget_crossed_stop2(self):
|
||||
set_total_expense_zero("2013-02-28", "Project")
|
||||
|
||||
budget = make_budget(budget_against="Project")
|
||||
|
||||
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Bank - _TC", 150000, "_Test Cost Center - _TC", project="_Test Project", posting_date="2013-03-28")
|
||||
|
||||
self.assertRaises(BudgetError, jv.submit)
|
||||
|
||||
|
||||
budget.cancel()
|
||||
|
||||
def test_monthly_budget_on_cancellation1(self):
|
||||
set_total_expense_zero("2013-02-28", "Cost Center")
|
||||
|
||||
budget = make_budget(budget_against="Cost Center")
|
||||
|
||||
|
||||
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
|
||||
|
||||
@@ -170,9 +170,9 @@ class TestBudget(unittest.TestCase):
|
||||
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
|
||||
|
||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||
|
||||
|
||||
self.assertRaises(BudgetError, jv1.cancel)
|
||||
|
||||
|
||||
budget.load_from_db()
|
||||
budget.cancel()
|
||||
|
||||
@@ -180,7 +180,7 @@ class TestBudget(unittest.TestCase):
|
||||
set_total_expense_zero("2013-02-28", "Project")
|
||||
|
||||
budget = make_budget(budget_against="Project")
|
||||
|
||||
|
||||
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True, project="_Test Project")
|
||||
|
||||
@@ -194,16 +194,16 @@ class TestBudget(unittest.TestCase):
|
||||
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
|
||||
|
||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||
|
||||
|
||||
self.assertRaises(BudgetError, jv1.cancel)
|
||||
|
||||
|
||||
budget.load_from_db()
|
||||
budget.cancel()
|
||||
|
||||
def test_monthly_budget_against_group_cost_center(self):
|
||||
set_total_expense_zero("2013-02-28", "Cost Center")
|
||||
set_total_expense_zero("2013-02-28", "Cost Center", "_Test Cost Center 2 - _TC")
|
||||
|
||||
|
||||
budget = make_budget(budget_against="Cost Center", cost_center="_Test Company - _TC")
|
||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||
|
||||
@@ -211,7 +211,7 @@ class TestBudget(unittest.TestCase):
|
||||
"_Test Bank - _TC", 40000, "_Test Cost Center 2 - _TC", posting_date="2013-02-28")
|
||||
|
||||
self.assertRaises(BudgetError, jv.submit)
|
||||
|
||||
|
||||
budget.load_from_db()
|
||||
budget.cancel()
|
||||
|
||||
@@ -239,8 +239,6 @@ class TestBudget(unittest.TestCase):
|
||||
budget.cancel()
|
||||
jv.cancel()
|
||||
|
||||
frappe.delete_doc('Journal Entry', jv.name)
|
||||
frappe.delete_doc('Cost Center', cost_center)
|
||||
|
||||
def set_total_expense_zero(posting_date, budget_against_field=None, budget_against_CC=None):
|
||||
if budget_against_field == "Project":
|
||||
@@ -256,7 +254,7 @@ def set_total_expense_zero(posting_date, budget_against_field=None, budget_again
|
||||
"budget_against_field": budget_against_field,
|
||||
"budget_against": budget_against
|
||||
}))
|
||||
|
||||
|
||||
if existing_expense:
|
||||
if budget_against_field == "Cost Center":
|
||||
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
@@ -281,13 +279,13 @@ def make_budget(**args):
|
||||
frappe.db.sql("delete from `tabBudget Account` where parent = %(name)s", d)
|
||||
|
||||
budget = frappe.new_doc("Budget")
|
||||
|
||||
|
||||
if budget_against == "Project":
|
||||
budget.project = "_Test Project"
|
||||
else:
|
||||
budget.cost_center =cost_center or "_Test Cost Center - _TC"
|
||||
|
||||
|
||||
|
||||
|
||||
budget.fiscal_year = "_Test Fiscal Year 2013"
|
||||
budget.monthly_distribution = "_Test Distribution"
|
||||
budget.company = "_Test Company"
|
||||
@@ -299,7 +297,7 @@ def make_budget(**args):
|
||||
"account": "_Test Account Cost for Goods Sold - _TC",
|
||||
"budget_amount": 100000
|
||||
})
|
||||
|
||||
|
||||
if args.applicable_on_material_request:
|
||||
budget.applicable_on_material_request = 1
|
||||
budget.action_if_annual_budget_exceeded_on_mr = args.action_if_annual_budget_exceeded_on_mr or 'Warn'
|
||||
|
||||
@@ -150,7 +150,7 @@ def validate_accounts(file_name):
|
||||
accounts_dict = {}
|
||||
for account in accounts:
|
||||
accounts_dict.setdefault(account["account_name"], account)
|
||||
if account["parent_account"] and accounts_dict[account["parent_account"]]:
|
||||
if account["parent_account"] and accounts_dict.get(account["parent_account"]):
|
||||
accounts_dict[account["parent_account"]]["is_group"] = 1
|
||||
|
||||
message = validate_root(accounts_dict)
|
||||
|
||||
@@ -1,457 +1,170 @@
|
||||
{
|
||||
"allow_copy": 1,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:cost_center_name",
|
||||
"beta": 0,
|
||||
"creation": "2013-01-23 19:57:17",
|
||||
"custom": 0,
|
||||
"description": "Track separate Income and Expense for product verticals or divisions.",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"editable_grid": 0,
|
||||
"allow_copy": 1,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2013-01-23 19:57:17",
|
||||
"description": "Track separate Income and Expense for product verticals or divisions.",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"sb0",
|
||||
"cost_center_name",
|
||||
"cost_center_number",
|
||||
"parent_cost_center",
|
||||
"company",
|
||||
"cb0",
|
||||
"is_group",
|
||||
"disabled",
|
||||
"lft",
|
||||
"rgt",
|
||||
"old_parent"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "sb0",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "sb0",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "cost_center_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Cost Center Name",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "cost_center_name",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "cost_center_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Cost Center Name",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "cost_center_name",
|
||||
"oldfieldtype": "Data",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "cost_center_number",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Cost Center Number",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "cost_center_number",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Cost Center Number",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "parent_cost_center",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 1,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Parent Cost Center",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "parent_cost_center",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Cost Center",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "parent_cost_center",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Parent Cost Center",
|
||||
"oldfieldname": "parent_cost_center",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Cost Center",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"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": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "company_name",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Company",
|
||||
"oldfieldname": "company_name",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Company",
|
||||
"remember_last_selected_value": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "cb0",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"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": 0,
|
||||
"fieldname": "cb0",
|
||||
"fieldtype": "Column Break",
|
||||
"width": "50%"
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "is_group",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Is Group",
|
||||
"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": 0
|
||||
},
|
||||
"default": "0",
|
||||
"fieldname": "is_group",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Group"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "lft",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "lft",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "lft",
|
||||
"oldfieldtype": "Int",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 1,
|
||||
"reqd": 0,
|
||||
"search_index": 1,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "lft",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 1,
|
||||
"label": "lft",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "lft",
|
||||
"oldfieldtype": "Int",
|
||||
"print_hide": 1,
|
||||
"report_hide": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "rgt",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "rgt",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "rgt",
|
||||
"oldfieldtype": "Int",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 1,
|
||||
"reqd": 0,
|
||||
"search_index": 1,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "rgt",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 1,
|
||||
"label": "rgt",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "rgt",
|
||||
"oldfieldtype": "Int",
|
||||
"print_hide": 1,
|
||||
"report_hide": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "old_parent",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 1,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "old_parent",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "old_parent",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "Cost Center",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 1,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldname": "old_parent",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "old_parent",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "old_parent",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "Cost Center",
|
||||
"print_hide": 1,
|
||||
"report_hide": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "disabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Disabled"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"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,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-04-26 15:26:25.325778",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cost Center",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"icon": "fa fa-money",
|
||||
"idx": 1,
|
||||
"modified": "2019-09-16 14:44:17.103548",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cost Center",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 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,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Auditor",
|
||||
"set_user_permissions": 0,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
"export": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Auditor"
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User"
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Sales User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
"read": 1,
|
||||
"role": "Sales User"
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 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": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"search_fields": "parent_cost_center, is_group",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_order": "ASC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"search_fields": "parent_cost_center, is_group",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC"
|
||||
}
|
||||
44
erpnext/accounts/doctype/coupon_code/coupon_code.js
Normal file
44
erpnext/accounts/doctype/coupon_code/coupon_code.js
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Coupon Code', {
|
||||
setup: function(frm) {
|
||||
frm.set_query("pricing_rule", function() {
|
||||
return {
|
||||
filters: [
|
||||
["Pricing Rule","coupon_code_based", "=", "1"]
|
||||
]
|
||||
};
|
||||
});
|
||||
},
|
||||
coupon_name:function(frm){
|
||||
if (frm.doc.__islocal===1) {
|
||||
frm.trigger("make_coupon_code");
|
||||
}
|
||||
},
|
||||
coupon_type:function(frm){
|
||||
if (frm.doc.__islocal===1) {
|
||||
frm.trigger("make_coupon_code");
|
||||
}
|
||||
},
|
||||
make_coupon_code: function(frm) {
|
||||
var coupon_name=frm.doc.coupon_name;
|
||||
var coupon_code;
|
||||
if (frm.doc.coupon_type=='Gift Card') {
|
||||
coupon_code=Math.random().toString(12).substring(2, 12).toUpperCase();
|
||||
}
|
||||
else if(frm.doc.coupon_type=='Promotional'){
|
||||
coupon_name=coupon_name.replace(/\s/g,'');
|
||||
coupon_code=coupon_name.toUpperCase().slice(0,8);
|
||||
}
|
||||
frm.doc.coupon_code=coupon_code;
|
||||
frm.refresh_field('coupon_code');
|
||||
},
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.pricing_rule) {
|
||||
frm.add_custom_button(__("Add/Edit Coupon Conditions"), function(){
|
||||
frappe.set_route("Form", "Pricing Rule", frm.doc.pricing_rule);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
177
erpnext/accounts/doctype/coupon_code/coupon_code.json
Normal file
177
erpnext/accounts/doctype/coupon_code/coupon_code.json
Normal file
@@ -0,0 +1,177 @@
|
||||
{
|
||||
"allow_import": 1,
|
||||
"autoname": "field:coupon_name",
|
||||
"creation": "2018-01-22 14:34:39.701832",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Other",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"coupon_name",
|
||||
"coupon_type",
|
||||
"customer",
|
||||
"column_break_4",
|
||||
"coupon_code",
|
||||
"pricing_rule",
|
||||
"uses",
|
||||
"valid_from",
|
||||
"valid_upto",
|
||||
"maximum_use",
|
||||
"used",
|
||||
"column_break_11",
|
||||
"description",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"description": "e.g. \"Summer Holiday 2019 Offer 20\"",
|
||||
"fieldname": "coupon_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Coupon Name",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "coupon_type",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Coupon Type",
|
||||
"options": "Promotional\nGift Card",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval: doc.coupon_type == \"Gift Card\"",
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"label": "Customer",
|
||||
"options": "Customer"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"description": "unique e.g. SAVE20 To be used to get discount",
|
||||
"fieldname": "coupon_code",
|
||||
"fieldtype": "Data",
|
||||
"label": "Coupon Code",
|
||||
"no_copy": 1,
|
||||
"set_only_once": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "pricing_rule",
|
||||
"fieldtype": "Link",
|
||||
"label": "Pricing Rule",
|
||||
"options": "Pricing Rule",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "uses",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Validity and Usage"
|
||||
},
|
||||
{
|
||||
"fieldname": "valid_from",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Valid From"
|
||||
},
|
||||
{
|
||||
"fieldname": "valid_upto",
|
||||
"fieldtype": "Date",
|
||||
"label": "Valid Upto"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval: doc.coupon_type == \"Promotional\"",
|
||||
"fieldname": "maximum_use",
|
||||
"fieldtype": "Int",
|
||||
"label": "Maximum Use"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "used",
|
||||
"fieldtype": "Int",
|
||||
"label": "Used",
|
||||
"no_copy": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_11",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "Coupon Description"
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Coupon Code",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"modified": "2019-10-19 14:48:14.602481",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Coupon Code",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Website Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "coupon_name",
|
||||
"track_changes": 1
|
||||
}
|
||||
25
erpnext/accounts/doctype/coupon_code/coupon_code.py
Normal file
25
erpnext/accounts/doctype/coupon_code/coupon_code.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import (strip)
|
||||
class CouponCode(Document):
|
||||
def autoname(self):
|
||||
self.coupon_name = strip(self.coupon_name)
|
||||
self.name = self.coupon_name
|
||||
|
||||
if not self.coupon_code:
|
||||
if self.coupon_type == "Promotional":
|
||||
self.coupon_code =''.join([i for i in self.coupon_name if not i.isdigit()])[0:8].upper()
|
||||
elif self.coupon_type == "Gift Card":
|
||||
self.coupon_code = frappe.generate_hash()[:10].upper()
|
||||
|
||||
def validate(self):
|
||||
if self.coupon_type == "Gift Card":
|
||||
self.maximum_use = 1
|
||||
if not self.customer:
|
||||
frappe.throw(_("Please select the customer."))
|
||||
@@ -2,15 +2,15 @@
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Asset Settings", function (assert) {
|
||||
QUnit.test("test: Coupon Code", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Asset Settings
|
||||
() => frappe.tests.make('Asset Settings', [
|
||||
// insert a new Coupon Code
|
||||
() => frappe.tests.make('Coupon Code', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
132
erpnext/accounts/doctype/coupon_code/test_coupon_code.py
Normal file
132
erpnext/accounts/doctype/coupon_code/test_coupon_code.py
Normal file
@@ -0,0 +1,132 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||
from erpnext.stock.get_item_details import get_item_details
|
||||
from frappe.test_runner import make_test_objects
|
||||
|
||||
def test_create_test_data():
|
||||
frappe.set_user("Administrator")
|
||||
# create test item
|
||||
if not frappe.db.exists("Item","_Test Tesla Car"):
|
||||
item = frappe.get_doc({
|
||||
"description": "_Test Tesla Car",
|
||||
"doctype": "Item",
|
||||
"has_batch_no": 0,
|
||||
"has_serial_no": 0,
|
||||
"inspection_required": 0,
|
||||
"is_stock_item": 1,
|
||||
"opening_stock":100,
|
||||
"is_sub_contracted_item": 0,
|
||||
"item_code": "_Test Tesla Car",
|
||||
"item_group": "_Test Item Group",
|
||||
"item_name": "_Test Tesla Car",
|
||||
"apply_warehouse_wise_reorder_level": 0,
|
||||
"warehouse":"_Test Warehouse - _TC",
|
||||
"gst_hsn_code": "999800",
|
||||
"valuation_rate": 5000,
|
||||
"standard_rate":5000,
|
||||
"item_defaults": [{
|
||||
"company": "_Test Company",
|
||||
"default_warehouse": "_Test Warehouse - _TC",
|
||||
"default_price_list":"_Test Price List",
|
||||
"expense_account": "_Test Account Cost for Goods Sold - _TC",
|
||||
"buying_cost_center": "_Test Cost Center - _TC",
|
||||
"selling_cost_center": "_Test Cost Center - _TC",
|
||||
"income_account": "Sales - _TC"
|
||||
}],
|
||||
"show_in_website": 1,
|
||||
"route":"-test-tesla-car",
|
||||
"website_warehouse": "_Test Warehouse - _TC"
|
||||
})
|
||||
item.insert()
|
||||
# create test item price
|
||||
item_price = frappe.get_list('Item Price', filters={'item_code': '_Test Tesla Car', 'price_list': '_Test Price List'}, fields=['name'])
|
||||
if len(item_price)==0:
|
||||
item_price = frappe.get_doc({
|
||||
"doctype": "Item Price",
|
||||
"item_code": "_Test Tesla Car",
|
||||
"price_list": "_Test Price List",
|
||||
"price_list_rate": 5000
|
||||
})
|
||||
item_price.insert()
|
||||
# create test item pricing rule
|
||||
if not frappe.db.exists("Pricing Rule","_Test Pricing Rule for _Test Item"):
|
||||
item_pricing_rule = frappe.get_doc({
|
||||
"doctype": "Pricing Rule",
|
||||
"title": "_Test Pricing Rule for _Test Item",
|
||||
"apply_on": "Item Code",
|
||||
"items": [{
|
||||
"item_code": "_Test Tesla Car"
|
||||
}],
|
||||
"warehouse":"_Test Warehouse - _TC",
|
||||
"coupon_code_based":1,
|
||||
"selling": 1,
|
||||
"rate_or_discount": "Discount Percentage",
|
||||
"discount_percentage": 30,
|
||||
"company": "_Test Company",
|
||||
"currency":"INR",
|
||||
"for_price_list":"_Test Price List"
|
||||
})
|
||||
item_pricing_rule.insert()
|
||||
# create test item sales partner
|
||||
if not frappe.db.exists("Sales Partner","_Test Coupon Partner"):
|
||||
sales_partner = frappe.get_doc({
|
||||
"doctype": "Sales Partner",
|
||||
"partner_name":"_Test Coupon Partner",
|
||||
"commission_rate":2,
|
||||
"referral_code": "COPART"
|
||||
})
|
||||
sales_partner.insert()
|
||||
# create test item coupon code
|
||||
if not frappe.db.exists("Coupon Code","SAVE30"):
|
||||
coupon_code = frappe.get_doc({
|
||||
"doctype": "Coupon Code",
|
||||
"coupon_name":"SAVE30",
|
||||
"coupon_code":"SAVE30",
|
||||
"pricing_rule": "_Test Pricing Rule for _Test Item",
|
||||
"valid_from": "2014-01-01",
|
||||
"maximum_use":1,
|
||||
"used":0
|
||||
})
|
||||
coupon_code.insert()
|
||||
|
||||
|
||||
class TestCouponCode(unittest.TestCase):
|
||||
def setUp(self):
|
||||
test_create_test_data()
|
||||
|
||||
def tearDown(self):
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
def test_1_check_coupon_code_used_before_so(self):
|
||||
coupon_code = frappe.get_doc("Coupon Code", frappe.db.get_value("Coupon Code", {"coupon_name":"SAVE30"}))
|
||||
# reset used coupon code count
|
||||
coupon_code.used=0
|
||||
coupon_code.save()
|
||||
# check no coupon code is used before sales order is made
|
||||
self.assertEqual(coupon_code.get("used"),0)
|
||||
|
||||
def test_2_sales_order_with_coupon_code(self):
|
||||
so = make_sales_order(customer="_Test Customer",selling_price_list="_Test Price List",item_code="_Test Tesla Car", rate=5000,qty=1, do_not_submit=True)
|
||||
so = frappe.get_doc('Sales Order', so.name)
|
||||
# check item price before coupon code is applied
|
||||
self.assertEqual(so.items[0].rate, 5000)
|
||||
so.coupon_code='SAVE30'
|
||||
so.sales_partner='_Test Coupon Partner'
|
||||
so.save()
|
||||
# check item price after coupon code is applied
|
||||
self.assertEqual(so.items[0].rate, 3500)
|
||||
so.submit()
|
||||
|
||||
def test_3_check_coupon_code_used_after_so(self):
|
||||
doc = frappe.get_doc("Coupon Code", frappe.db.get_value("Coupon Code", {"coupon_name":"SAVE30"}))
|
||||
# check no coupon code is used before sales order is made
|
||||
self.assertEqual(doc.get("used"),1)
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"customer",
|
||||
"column_break_3",
|
||||
"posting_date",
|
||||
"outstanding_amount"
|
||||
"outstanding_amount",
|
||||
"debit_to"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@@ -37,21 +38,29 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "sales_invoice.grand_total",
|
||||
"fetch_from": "sales_invoice.outstanding_amount",
|
||||
"fetch_if_empty": 1,
|
||||
"fieldname": "outstanding_amount",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Outstanding Amount",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
"options": "Company:company:default_currency"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fetch_from": "sales_invoice.debit_to",
|
||||
"fieldname": "debit_to",
|
||||
"fieldtype": "Link",
|
||||
"label": "Debit to",
|
||||
"options": "Account",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"modified": "2019-05-30 19:27:29.436153",
|
||||
"modified": "2019-09-26 11:05:36.016772",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Discounted Invoice",
|
||||
|
||||
@@ -12,7 +12,7 @@ from erpnext.accounts.party import validate_party_gle_currency, validate_party_f
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from erpnext.exceptions import InvalidAccountCurrency
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_checks_for_pl_and_bs_accounts
|
||||
|
||||
exclude_from_linked_with = True
|
||||
class GLEntry(Document):
|
||||
@@ -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)
|
||||
@@ -86,16 +86,16 @@ class GLEntry(Document):
|
||||
|
||||
account_type = frappe.db.get_value("Account", self.account, "report_type")
|
||||
|
||||
for dimension in get_accounting_dimensions(as_list=False):
|
||||
for dimension in get_checks_for_pl_and_bs_accounts():
|
||||
|
||||
if account_type == "Profit and Loss" \
|
||||
and dimension.mandatory_for_pl and not dimension.disabled:
|
||||
and self.company == dimension.company and dimension.mandatory_for_pl and not dimension.disabled:
|
||||
if not self.get(dimension.fieldname):
|
||||
frappe.throw(_("Accounting Dimension <b>{0}</b> is required for 'Profit and Loss' account {1}.")
|
||||
.format(dimension.label, self.account))
|
||||
|
||||
if account_type == "Balance Sheet" \
|
||||
and dimension.mandatory_for_bs and not dimension.disabled:
|
||||
and self.company == dimension.company and dimension.mandatory_for_bs and not dimension.disabled:
|
||||
if not self.get(dimension.fieldname):
|
||||
frappe.throw(_("Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}.")
|
||||
.format(dimension.label, self.account))
|
||||
|
||||
@@ -13,41 +13,57 @@ frappe.ui.form.on('Invoice Discounting', {
|
||||
};
|
||||
});
|
||||
|
||||
frm.events.filter_accounts("bank_account", frm, {"account_type": "Bank"});
|
||||
frm.events.filter_accounts("bank_charges_account", frm, {"root_type": "Expense"});
|
||||
frm.events.filter_accounts("short_term_loan", frm, {"root_type": "Liability"});
|
||||
frm.events.filter_accounts("accounts_receivable_credit", frm, {"account_type": "Receivable"});
|
||||
frm.events.filter_accounts("accounts_receivable_discounted", frm, {"account_type": "Receivable"});
|
||||
frm.events.filter_accounts("accounts_receivable_unpaid", frm, {"account_type": "Receivable"});
|
||||
|
||||
frm.events.filter_accounts("bank_account", frm, [["account_type", "=", "Bank"]]);
|
||||
frm.events.filter_accounts("bank_charges_account", frm, [["root_type", "=", "Expense"]]);
|
||||
frm.events.filter_accounts("short_term_loan", frm, [["root_type", "=", "Liability"]]);
|
||||
frm.events.filter_accounts("accounts_receivable_discounted", frm, [["account_type", "=", "Receivable"]]);
|
||||
frm.events.filter_accounts("accounts_receivable_credit", frm, [["account_type", "=", "Receivable"]]);
|
||||
frm.events.filter_accounts("accounts_receivable_unpaid", frm, [["account_type", "=", "Receivable"]]);
|
||||
|
||||
},
|
||||
|
||||
filter_accounts: (fieldname, frm, addl_filters) => {
|
||||
let filters = {
|
||||
"company": frm.doc.company,
|
||||
"is_group": 0
|
||||
};
|
||||
if(addl_filters) Object.assign(filters, addl_filters);
|
||||
let filters = [
|
||||
["company", "=", frm.doc.company],
|
||||
["is_group", "=", 0]
|
||||
];
|
||||
if(addl_filters){
|
||||
filters = $.merge(filters , addl_filters);
|
||||
}
|
||||
|
||||
frm.set_query(fieldname, () => { return { "filters": filters }; });
|
||||
},
|
||||
|
||||
refresh_filters: (frm) =>{
|
||||
let invoice_accounts = Object.keys(frm.doc.invoices).map(function(key) {
|
||||
return frm.doc.invoices[key].debit_to;
|
||||
});
|
||||
let filters = [
|
||||
["account_type", "=", "Receivable"],
|
||||
["name", "not in", invoice_accounts]
|
||||
];
|
||||
frm.events.filter_accounts("accounts_receivable_credit", frm, filters);
|
||||
frm.events.filter_accounts("accounts_receivable_discounted", frm, filters);
|
||||
frm.events.filter_accounts("accounts_receivable_unpaid", frm, filters);
|
||||
},
|
||||
|
||||
refresh: (frm) => {
|
||||
frm.events.show_general_ledger(frm);
|
||||
|
||||
if(frm.doc.docstatus === 0) {
|
||||
if (frm.doc.docstatus === 0) {
|
||||
frm.add_custom_button(__('Get Invoices'), function() {
|
||||
frm.events.get_invoices(frm);
|
||||
});
|
||||
}
|
||||
|
||||
if(frm.doc.docstatus === 1 && frm.doc.status !== "Settled") {
|
||||
if(frm.doc.status == "Sanctioned") {
|
||||
if (frm.doc.docstatus === 1 && frm.doc.status !== "Settled") {
|
||||
if (frm.doc.status == "Sanctioned") {
|
||||
frm.add_custom_button(__('Disburse Loan'), function() {
|
||||
frm.events.create_disbursement_entry(frm);
|
||||
}).addClass("btn-primary");
|
||||
}
|
||||
if(frm.doc.status == "Disbursed") {
|
||||
if (frm.doc.status == "Disbursed") {
|
||||
frm.add_custom_button(__('Close Loan'), function() {
|
||||
frm.events.close_loan(frm);
|
||||
}).addClass("btn-primary");
|
||||
@@ -64,7 +80,7 @@ frappe.ui.form.on('Invoice Discounting', {
|
||||
},
|
||||
|
||||
set_end_date: (frm) => {
|
||||
if(frm.doc.loan_start_date && frm.doc.loan_period) {
|
||||
if (frm.doc.loan_start_date && frm.doc.loan_period) {
|
||||
let end_date = frappe.datetime.add_days(frm.doc.loan_start_date, frm.doc.loan_period);
|
||||
frm.set_value("loan_end_date", end_date);
|
||||
}
|
||||
@@ -81,7 +97,6 @@ frappe.ui.form.on('Invoice Discounting', {
|
||||
}
|
||||
frm.set_value("total_amount", total_amount);
|
||||
},
|
||||
|
||||
get_invoices: (frm) => {
|
||||
var d = new frappe.ui.Dialog({
|
||||
title: __('Get Invoices based on Filters'),
|
||||
@@ -132,6 +147,7 @@ frappe.ui.form.on('Invoice Discounting', {
|
||||
frm.doc.invoices = frm.doc.invoices.filter(row => row.sales_invoice);
|
||||
let row = frm.add_child("invoices");
|
||||
$.extend(row, v);
|
||||
frm.events.refresh_filters(frm);
|
||||
});
|
||||
refresh_field("invoices");
|
||||
}
|
||||
@@ -190,8 +206,10 @@ frappe.ui.form.on('Invoice Discounting', {
|
||||
frappe.ui.form.on('Discounted Invoice', {
|
||||
sales_invoice: (frm) => {
|
||||
frm.events.calculate_total_amount(frm);
|
||||
frm.events.refresh_filters(frm);
|
||||
},
|
||||
invoices_remove: (frm) => {
|
||||
frm.events.calculate_total_amount(frm);
|
||||
frm.events.refresh_filters(frm);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@ from erpnext.accounts.general_ledger import make_gl_entries
|
||||
class InvoiceDiscounting(AccountsController):
|
||||
def validate(self):
|
||||
self.validate_mandatory()
|
||||
self.validate_invoices()
|
||||
self.calculate_total_amount()
|
||||
self.set_status()
|
||||
self.set_end_date()
|
||||
@@ -24,6 +25,21 @@ class InvoiceDiscounting(AccountsController):
|
||||
if self.docstatus == 1 and not (self.loan_start_date and self.loan_period):
|
||||
frappe.throw(_("Loan Start Date and Loan Period are mandatory to save the Invoice Discounting"))
|
||||
|
||||
def validate_invoices(self):
|
||||
discounted_invoices = [record.sales_invoice for record in
|
||||
frappe.get_all("Discounted Invoice",fields=["sales_invoice"], filters={"docstatus":1})]
|
||||
|
||||
for record in self.invoices:
|
||||
if record.sales_invoice in discounted_invoices:
|
||||
frappe.throw(_("Row({0}): {1} is already discounted in {2}")
|
||||
.format(record.idx, frappe.bold(record.sales_invoice), frappe.bold(record.parent)))
|
||||
|
||||
actual_outstanding = frappe.db.get_value("Sales Invoice", record.sales_invoice,"outstanding_amount")
|
||||
if record.outstanding_amount > actual_outstanding :
|
||||
frappe.throw(_
|
||||
("Row({0}): Outstanding Amount cannot be greater than actual Outstanding Amount {1} in {2}").format(
|
||||
record.idx, frappe.bold(actual_outstanding), frappe.bold(record.sales_invoice)))
|
||||
|
||||
def calculate_total_amount(self):
|
||||
self.total_amount = sum([flt(d.outstanding_amount) for d in self.invoices])
|
||||
|
||||
@@ -212,7 +228,8 @@ def get_invoices(filters):
|
||||
name as sales_invoice,
|
||||
customer,
|
||||
posting_date,
|
||||
outstanding_amount
|
||||
outstanding_amount,
|
||||
debit_to
|
||||
from `tabSales Invoice` si
|
||||
where
|
||||
docstatus = 1
|
||||
|
||||
@@ -7,7 +7,7 @@ frappe.provide("erpnext.journal_entry");
|
||||
|
||||
frappe.ui.form.on("Journal Entry", {
|
||||
setup: function(frm) {
|
||||
frm.add_fetch("bank_account_no", "account", "account");
|
||||
frm.add_fetch("bank_account", "account", "account");
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
@@ -190,7 +190,6 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
||||
if(jvd.reference_type==="Employee Advance") {
|
||||
return {
|
||||
filters: {
|
||||
'status': ['=', 'Unpaid'],
|
||||
'docstatus': 1
|
||||
}
|
||||
};
|
||||
@@ -398,7 +397,7 @@ cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
|
||||
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
|
||||
args: {
|
||||
"account_type": (doc.voucher_type=="Bank Entry" ?
|
||||
"Bank" : (doc.voucher_type=="Cash" ? "Cash" : null)),
|
||||
"Bank" : (doc.voucher_type=="Cash Entry" ? "Cash" : null)),
|
||||
"company": doc.company
|
||||
},
|
||||
callback: function(r) {
|
||||
@@ -570,7 +569,7 @@ $.extend(erpnext.journal_entry, {
|
||||
},
|
||||
{fieldtype: "Date", fieldname: "posting_date", label: __("Date"), reqd: 1,
|
||||
default: frm.doc.posting_date},
|
||||
{fieldtype: "Small Text", fieldname: "user_remark", label: __("User Remark"), reqd: 1},
|
||||
{fieldtype: "Small Text", fieldname: "user_remark", label: __("User Remark")},
|
||||
{fieldtype: "Select", fieldname: "naming_series", label: __("Series"), reqd: 1,
|
||||
options: naming_series_options, default: naming_series_default},
|
||||
]
|
||||
@@ -608,15 +607,9 @@ $.extend(erpnext.journal_entry, {
|
||||
},
|
||||
|
||||
account_query: function(frm) {
|
||||
var inter_company = 0;
|
||||
if (frm.doc.voucher_type == "Inter Company Journal Entry") {
|
||||
inter_company = 1;
|
||||
}
|
||||
|
||||
var filters = {
|
||||
company: frm.doc.company,
|
||||
is_group: 0,
|
||||
inter_company_account: inter_company
|
||||
is_group: 0
|
||||
};
|
||||
if(!frm.doc.multi_currency) {
|
||||
$.extend(filters, {
|
||||
|
||||
@@ -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
|
||||
@@ -606,8 +605,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:
|
||||
@@ -827,10 +826,10 @@ def get_opening_accounts(company):
|
||||
accounts = frappe.db.sql_list("""select
|
||||
name from tabAccount
|
||||
where
|
||||
is_group=0 and report_type='Balance Sheet' and company=%s and
|
||||
name not in(select distinct account from tabWarehouse where
|
||||
is_group=0 and report_type='Balance Sheet' and company={0} and
|
||||
name not in (select distinct account from tabWarehouse where
|
||||
account is not null and account != '')
|
||||
order by name asc""", frappe.db.escape(company))
|
||||
order by name asc""".format(frappe.db.escape(company)))
|
||||
|
||||
return [{"account": a, "balance": get_balance_on(a)} for a in accounts]
|
||||
|
||||
@@ -968,7 +967,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
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"account_type",
|
||||
"balance",
|
||||
"col_break1",
|
||||
"bank_account_no",
|
||||
"bank_account",
|
||||
"party_type",
|
||||
"party",
|
||||
"party_balance",
|
||||
@@ -40,7 +40,7 @@
|
||||
"fields": [
|
||||
{
|
||||
"bold": 1,
|
||||
"columns": 3,
|
||||
"columns": 2,
|
||||
"fieldname": "account",
|
||||
"fieldtype": "Link",
|
||||
"in_global_search": 1,
|
||||
@@ -89,21 +89,16 @@
|
||||
"fieldname": "col_break1",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "bank_account_no",
|
||||
"fieldtype": "Link",
|
||||
"label": "Bank Account No",
|
||||
"options": "Bank Account"
|
||||
},
|
||||
{
|
||||
"fieldname": "party_type",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Party Type",
|
||||
"options": "DocType",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"columns": 3,
|
||||
"columns": 2,
|
||||
"fieldname": "party",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"in_list_view": 1,
|
||||
@@ -258,6 +253,7 @@
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "accounting_dimensions_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Accounting Dimensions"
|
||||
@@ -265,16 +261,23 @@
|
||||
{
|
||||
"fieldname": "dimension_col_break",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "bank_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Bank Account",
|
||||
"options": "Bank Account"
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-05-25 22:14:02.715509",
|
||||
"modified": "2020-01-13 12:41:33.968025",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Journal Entry Account",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -8,10 +8,12 @@ import unittest
|
||||
from frappe.utils import today, cint, flt, getdate
|
||||
from erpnext.accounts.doctype.loyalty_program.loyalty_program import get_loyalty_program_details_with_points
|
||||
from erpnext.accounts.party import get_dashboard_info
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
|
||||
|
||||
class TestLoyaltyProgram(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
set_perpetual_inventory(0)
|
||||
# create relevant item, customer, loyalty program, etc
|
||||
create_records()
|
||||
|
||||
@@ -49,7 +51,6 @@ class TestLoyaltyProgram(unittest.TestCase):
|
||||
# cancel and delete
|
||||
for d in [si_redeem, si_original]:
|
||||
d.cancel()
|
||||
frappe.delete_doc('Sales Invoice', d.name)
|
||||
|
||||
def test_loyalty_points_earned_multiple_tier(self):
|
||||
frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Multiple Loyalty")
|
||||
@@ -91,7 +92,6 @@ class TestLoyaltyProgram(unittest.TestCase):
|
||||
# cancel and delete
|
||||
for d in [si_redeem, si_original]:
|
||||
d.cancel()
|
||||
frappe.delete_doc('Sales Invoice', d.name)
|
||||
|
||||
def test_cancel_sales_invoice(self):
|
||||
''' cancelling the sales invoice should cancel the earned points'''
|
||||
@@ -143,7 +143,6 @@ class TestLoyaltyProgram(unittest.TestCase):
|
||||
d.cancel()
|
||||
except frappe.TimestampMismatchError:
|
||||
frappe.get_doc('Sales Invoice', d.name).cancel()
|
||||
frappe.delete_doc('Sales Invoice', d.name)
|
||||
|
||||
def test_loyalty_points_for_dashboard(self):
|
||||
doc = frappe.get_doc('Customer', 'Test Loyalty Customer')
|
||||
|
||||
@@ -1,171 +1,74 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:mode_of_payment",
|
||||
"beta": 0,
|
||||
"creation": "2012-12-04 17:49:20",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"editable_grid": 0,
|
||||
"engine": "InnoDB",
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:mode_of_payment",
|
||||
"creation": "2012-12-04 17:49:20",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"mode_of_payment",
|
||||
"enabled",
|
||||
"type",
|
||||
"accounts"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "mode_of_payment",
|
||||
"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": "Mode of Payment",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "mode_of_payment",
|
||||
"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": "mode_of_payment",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Mode of Payment",
|
||||
"oldfieldname": "mode_of_payment",
|
||||
"oldfieldtype": "Data",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "type",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Cash\nBank\nGeneral",
|
||||
"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": "type",
|
||||
"fieldtype": "Select",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Type",
|
||||
"options": "Cash\nBank\nGeneral"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "accounts",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Accounts",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Mode of Payment Account",
|
||||
"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": "accounts",
|
||||
"fieldtype": "Table",
|
||||
"label": "Accounts",
|
||||
"options": "Mode of Payment Account"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "enabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enabled"
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"icon": "fa fa-credit-card",
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-02-17 16:31:34.207683",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Mode of Payment",
|
||||
"owner": "harshada@webnotestech.com",
|
||||
],
|
||||
"icon": "fa fa-credit-card",
|
||||
"idx": 1,
|
||||
"modified": "2019-08-14 14:58:42.079115",
|
||||
"modified_by": "sammish.thundiyil@gmail.com",
|
||||
"module": "Accounts",
|
||||
"name": "Mode of Payment",
|
||||
"owner": "harshada@webnotestech.com",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 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": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User"
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_order": "ASC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC"
|
||||
}
|
||||
@@ -10,7 +10,9 @@
|
||||
"create_missing_party",
|
||||
"column_break_3",
|
||||
"invoice_type",
|
||||
"accounting_dimensions_section",
|
||||
"cost_center",
|
||||
"dimension_col_break",
|
||||
"section_break_4",
|
||||
"invoices"
|
||||
],
|
||||
@@ -59,11 +61,21 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Cost Center",
|
||||
"options": "Cost Center"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "accounting_dimensions_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Accounting Dimensions"
|
||||
},
|
||||
{
|
||||
"fieldname": "dimension_col_break",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"hide_toolbar": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2019-06-13 11:45:31.405267",
|
||||
"modified": "2019-07-25 14:57:33.187689",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Opening Invoice Creation Tool",
|
||||
|
||||
@@ -7,6 +7,7 @@ import frappe
|
||||
from frappe import _, scrub
|
||||
from frappe.utils import flt, nowdate
|
||||
from frappe.model.document import Document
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
|
||||
|
||||
class OpeningInvoiceCreationTool(Document):
|
||||
@@ -31,8 +32,10 @@ class OpeningInvoiceCreationTool(Document):
|
||||
})
|
||||
invoices_summary.update({company: _summary})
|
||||
|
||||
paid_amount.append(invoice.paid_amount)
|
||||
outstanding_amount.append(invoice.outstanding_amount)
|
||||
if invoice.paid_amount:
|
||||
paid_amount.append(invoice.paid_amount)
|
||||
if invoice.outstanding_amount:
|
||||
outstanding_amount.append(invoice.outstanding_amount)
|
||||
|
||||
if paid_amount or outstanding_amount:
|
||||
max_count.update({
|
||||
@@ -173,6 +176,13 @@ class OpeningInvoiceCreationTool(Document):
|
||||
"currency": frappe.get_cached_value('Company', self.company, "default_currency")
|
||||
})
|
||||
|
||||
accounting_dimension = get_accounting_dimensions()
|
||||
|
||||
for dimension in accounting_dimension:
|
||||
args.update({
|
||||
dimension: item.get(dimension)
|
||||
})
|
||||
|
||||
if self.invoice_type == "Sales":
|
||||
args["is_pos"] = 0
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
"outstanding_amount",
|
||||
"column_break_4",
|
||||
"qty",
|
||||
"cost_center"
|
||||
"accounting_dimensions_section",
|
||||
"cost_center",
|
||||
"dimension_col_break"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@@ -92,10 +94,19 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Cost Center",
|
||||
"options": "Cost Center"
|
||||
},
|
||||
{
|
||||
"fieldname": "accounting_dimensions_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Accounting Dimensions"
|
||||
},
|
||||
{
|
||||
"fieldname": "dimension_col_break",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"modified": "2019-06-13 11:48:08.324063",
|
||||
"modified": "2019-07-25 15:00:00.460695",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Opening Invoice Creation Tool Item",
|
||||
|
||||
@@ -308,7 +308,7 @@ frappe.ui.form.on('Payment Entry', {
|
||||
() => {
|
||||
frm.set_party_account_based_on_party = false;
|
||||
if (r.message.bank_account) {
|
||||
frm.set_value("bank_account", r.message.bank_account);
|
||||
frm.set_value("party_bank_account", r.message.bank_account);
|
||||
}
|
||||
}
|
||||
]);
|
||||
@@ -554,7 +554,7 @@ frappe.ui.form.on('Payment Entry', {
|
||||
frappe.flags.allocate_payment_amount = true;
|
||||
frm.events.validate_filters_data(frm, filters);
|
||||
frm.events.get_outstanding_documents(frm, filters);
|
||||
}, __("Filters"), __("Get Outstanding Invoices"));
|
||||
}, __("Filters"), __("Get Outstanding Documents"));
|
||||
},
|
||||
|
||||
validate_filters_data: function(frm, filters) {
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,7 +722,7 @@ frappe.ui.form.on('Payment Entry', {
|
||||
|
||||
$.each(frm.doc.references || [], function(i, row) {
|
||||
row.allocated_amount = 0 //If allocate payment amount checkbox is unchecked, set zero to allocate amount
|
||||
if(frappe.flags.allocate_payment_amount){
|
||||
if(frappe.flags.allocate_payment_amount != 0){
|
||||
if(row.outstanding_amount > 0 && allocated_positive_outstanding > 0) {
|
||||
if(row.outstanding_amount >= allocated_positive_outstanding) {
|
||||
row.allocated_amount = allocated_positive_outstanding;
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"dimension_col_break",
|
||||
"cost_center",
|
||||
"section_break_12",
|
||||
"status",
|
||||
"remarks",
|
||||
"column_break_16",
|
||||
"letter_head",
|
||||
@@ -563,10 +564,18 @@
|
||||
{
|
||||
"fieldname": "dimension_col_break",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "Draft",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"options": "\nDraft\nSubmitted\nCancelled",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-05-27 15:53:21.108857",
|
||||
"modified": "2019-11-06 12:59:43.151721",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Entry",
|
||||
|
||||
@@ -61,6 +61,7 @@ class PaymentEntry(AccountsController):
|
||||
self.validate_duplicate_entry()
|
||||
self.validate_allocated_amount()
|
||||
self.ensure_supplier_is_not_blocked()
|
||||
self.set_status()
|
||||
|
||||
def on_submit(self):
|
||||
self.setup_party_account_field()
|
||||
@@ -70,6 +71,7 @@ class PaymentEntry(AccountsController):
|
||||
self.update_outstanding_amounts()
|
||||
self.update_advance_paid()
|
||||
self.update_expense_claim()
|
||||
self.set_status()
|
||||
|
||||
|
||||
def on_cancel(self):
|
||||
@@ -79,6 +81,7 @@ class PaymentEntry(AccountsController):
|
||||
self.update_advance_paid()
|
||||
self.update_expense_claim()
|
||||
self.delink_advance_entry_references()
|
||||
self.set_status()
|
||||
|
||||
def update_outstanding_amounts(self):
|
||||
self.set_missing_ref_details(force=True)
|
||||
@@ -126,7 +129,7 @@ class PaymentEntry(AccountsController):
|
||||
if not self.party:
|
||||
frappe.throw(_("Party is mandatory"))
|
||||
|
||||
_party_name = "title" if self.party_type == "Student" else self.party_type.lower() + "_name"
|
||||
_party_name = "title" if self.party_type in ("Student", "Shareholder") else self.party_type.lower() + "_name"
|
||||
self.party_name = frappe.db.get_value(self.party_type, self.party, _party_name)
|
||||
|
||||
if self.party:
|
||||
@@ -275,6 +278,14 @@ class PaymentEntry(AccountsController):
|
||||
frappe.throw(_("Against Journal Entry {0} does not have any unmatched {1} entry")
|
||||
.format(d.reference_name, dr_or_cr))
|
||||
|
||||
def set_status(self):
|
||||
if self.docstatus == 2:
|
||||
self.status = 'Cancelled'
|
||||
elif self.docstatus == 1:
|
||||
self.status = 'Submitted'
|
||||
else:
|
||||
self.status = 'Draft'
|
||||
|
||||
def set_amounts(self):
|
||||
self.set_amounts_in_company_currency()
|
||||
self.set_total_allocated_amount()
|
||||
@@ -624,8 +635,8 @@ def get_outstanding_reference_documents(args):
|
||||
data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
|
||||
|
||||
if not data:
|
||||
frappe.msgprint(_("No outstanding invoices found for the {0} <b>{1}</b>.")
|
||||
.format(args.get("party_type").lower(), args.get("party")))
|
||||
frappe.msgprint(_("No outstanding invoices found for the {0} {1} which qualify the filters you have specified.")
|
||||
.format(args.get("party_type").lower(), frappe.bold(args.get("party"))))
|
||||
|
||||
return data
|
||||
|
||||
@@ -648,13 +659,18 @@ def get_orders_to_be_billed(posting_date, party_type, party,
|
||||
|
||||
orders = []
|
||||
if voucher_type:
|
||||
ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
|
||||
if party_account_currency == company_currency:
|
||||
grand_total_field = "base_grand_total"
|
||||
rounded_total_field = "base_rounded_total"
|
||||
else:
|
||||
grand_total_field = "grand_total"
|
||||
rounded_total_field = "rounded_total"
|
||||
|
||||
orders = frappe.db.sql("""
|
||||
select
|
||||
name as voucher_no,
|
||||
{ref_field} as invoice_amount,
|
||||
({ref_field} - advance_paid) as outstanding_amount,
|
||||
if({rounded_total_field}, {rounded_total_field}, {grand_total_field}) as invoice_amount,
|
||||
(if({rounded_total_field}, {rounded_total_field}, {grand_total_field}) - advance_paid) as outstanding_amount,
|
||||
transaction_date as posting_date
|
||||
from
|
||||
`tab{voucher_type}`
|
||||
@@ -663,13 +679,14 @@ def get_orders_to_be_billed(posting_date, party_type, party,
|
||||
and docstatus = 1
|
||||
and company = %s
|
||||
and ifnull(status, "") != "Closed"
|
||||
and {ref_field} > advance_paid
|
||||
and if({rounded_total_field}, {rounded_total_field}, {grand_total_field}) > advance_paid
|
||||
and abs(100 - per_billed) > 0.01
|
||||
{condition}
|
||||
order by
|
||||
transaction_date, name
|
||||
""".format(**{
|
||||
"ref_field": ref_field,
|
||||
"rounded_total_field": rounded_total_field,
|
||||
"grand_total_field": grand_total_field,
|
||||
"voucher_type": voucher_type,
|
||||
"party_type": scrub(party_type),
|
||||
"condition": condition
|
||||
@@ -677,8 +694,8 @@ def get_orders_to_be_billed(posting_date, party_type, party,
|
||||
|
||||
order_list = []
|
||||
for d in orders:
|
||||
if not (d.outstanding_amount >= filters.get("outstanding_amt_greater_than")
|
||||
and d.outstanding_amount <= filters.get("outstanding_amt_less_than")):
|
||||
if not (flt(d.outstanding_amount) >= flt(filters.get("outstanding_amt_greater_than"))
|
||||
and flt(d.outstanding_amount) <= flt(filters.get("outstanding_amt_less_than"))):
|
||||
continue
|
||||
|
||||
d["voucher_type"] = voucher_type
|
||||
@@ -755,9 +772,23 @@ def get_party_details(company, party_type, party, date, cost_center=None):
|
||||
@frappe.whitelist()
|
||||
def get_account_details(account, date, cost_center=None):
|
||||
frappe.has_permission('Payment Entry', throw=True)
|
||||
|
||||
# to check if the passed account is accessible under reference doctype Payment Entry
|
||||
account_list = frappe.get_list('Account', {
|
||||
'name': account
|
||||
}, reference_doctype='Payment Entry', limit=1)
|
||||
|
||||
# There might be some user permissions which will allow account under certain doctypes
|
||||
# except for Payment Entry, only in such case we should throw permission error
|
||||
if not account_list:
|
||||
frappe.throw(_('Account: {0} is not permitted under Payment Entry').format(account))
|
||||
|
||||
account_balance = get_balance_on(account, date, cost_center=cost_center,
|
||||
ignore_account_permission=True)
|
||||
|
||||
return frappe._dict({
|
||||
"account_currency": get_account_currency(account),
|
||||
"account_balance": get_balance_on(account, date, cost_center=cost_center),
|
||||
"account_balance": account_balance,
|
||||
"account_type": frappe.db.get_value("Account", account, "account_type")
|
||||
})
|
||||
|
||||
@@ -880,7 +911,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)) \
|
||||
@@ -900,9 +934,9 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
grand_total = doc.rounded_total or doc.grand_total
|
||||
outstanding_amount = doc.outstanding_amount
|
||||
elif dt in ("Expense Claim"):
|
||||
grand_total = doc.total_sanctioned_amount
|
||||
outstanding_amount = doc.total_sanctioned_amount \
|
||||
- doc.total_amount_reimbursed - flt(doc.total_advance_amount)
|
||||
grand_total = doc.total_sanctioned_amount + doc.total_taxes_and_charges
|
||||
outstanding_amount = doc.grand_total \
|
||||
- doc.total_amount_reimbursed
|
||||
elif dt == "Employee Advance":
|
||||
grand_total = doc.advance_amount
|
||||
outstanding_amount = flt(doc.advance_amount) - flt(doc.paid_amount)
|
||||
@@ -920,6 +954,10 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
bank = get_default_bank_cash_account(doc.company, "Bank", mode_of_payment=doc.get("mode_of_payment"),
|
||||
account=bank_account)
|
||||
|
||||
if not bank:
|
||||
bank = get_default_bank_cash_account(doc.company, "Cash", mode_of_payment=doc.get("mode_of_payment"),
|
||||
account=bank_account)
|
||||
|
||||
paid_amount = received_amount = 0
|
||||
if party_account_currency == bank.account_currency:
|
||||
paid_amount = received_amount = abs(outstanding_amount)
|
||||
@@ -927,10 +965,15 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
paid_amount = abs(outstanding_amount)
|
||||
if bank_amount:
|
||||
received_amount = bank_amount
|
||||
else:
|
||||
received_amount = paid_amount * doc.conversion_rate
|
||||
else:
|
||||
received_amount = abs(outstanding_amount)
|
||||
if bank_amount:
|
||||
paid_amount = bank_amount
|
||||
else:
|
||||
# if party account currency and bank currency is different then populate paid amount as well
|
||||
paid_amount = received_amount * doc.conversion_rate
|
||||
|
||||
pe = frappe.new_doc("Payment Entry")
|
||||
pe.payment_type = payment_type
|
||||
@@ -1016,7 +1059,7 @@ def make_payment_order(source_name, target_doc=None):
|
||||
|
||||
def update_item(source_doc, target_doc, source_parent):
|
||||
target_doc.bank_account = source_parent.party_bank_account
|
||||
target_doc.amount = source_parent.base_paid_amount
|
||||
target_doc.amount = source_doc.allocated_amount
|
||||
target_doc.account = source_parent.paid_to
|
||||
target_doc.payment_entry = source_parent.name
|
||||
target_doc.supplier = source_parent.party
|
||||
|
||||
@@ -66,9 +66,10 @@ frappe.ui.form.on('Payment Order', {
|
||||
get_query_filters: {
|
||||
bank: frm.doc.bank,
|
||||
docstatus: 1,
|
||||
payment_type: ["!=", "Receive"],
|
||||
bank_account: frm.doc.company_bank_account,
|
||||
paid_from: frm.doc.account,
|
||||
payment_order_status: ["=", "Initiated"],
|
||||
payment_order_status: ["=", "Initiated"]
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
frappe.ui.form.on('Payment Order', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus==1 && frm.doc.payment_order_type==='Payment Entry') {
|
||||
frm.add_custom_button(__('Generate Text File'), function() {
|
||||
frm.trigger("generate_text_and_download_file");
|
||||
});
|
||||
}
|
||||
},
|
||||
generate_text_and_download_file: (frm) => {
|
||||
return frappe.call({
|
||||
method: "erpnext.regional.india.bank_remittance.generate_report",
|
||||
args: {
|
||||
name: frm.doc.name
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
{
|
||||
frm.reload_doc();
|
||||
const a = document.createElement('a');
|
||||
let file_obj = r.message;
|
||||
a.href = file_obj.file_url;
|
||||
a.target = '_blank';
|
||||
a.download = file_obj.file_name;
|
||||
a.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -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,10 +92,11 @@ 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}`.is_return = 1 and `tabGL Entry`.against_voucher_type = %(voucher_type)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
|
||||
and `tabGL Entry`.party_type = %(party_type)s and `tabGL Entry`.account = %(account)s
|
||||
GROUP BY `tabSales Invoice`.name
|
||||
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), {
|
||||
@@ -257,11 +260,8 @@ def reconcile_dr_cr_note(dr_cr_notes):
|
||||
voucher_type = ('Credit Note'
|
||||
if d.voucher_type == 'Sales Invoice' else 'Debit Note')
|
||||
|
||||
dr_or_cr = ('credit_in_account_currency'
|
||||
if d.reference_type == 'Sales Invoice' else 'debit_in_account_currency')
|
||||
|
||||
reconcile_dr_or_cr = ('debit_in_account_currency'
|
||||
if dr_or_cr == 'credit_in_account_currency' else 'credit_in_account_currency')
|
||||
if d.dr_or_cr == 'credit_in_account_currency' else 'credit_in_account_currency')
|
||||
|
||||
jv = frappe.get_doc({
|
||||
"doctype": "Journal Entry",
|
||||
@@ -272,8 +272,7 @@ def reconcile_dr_cr_note(dr_cr_notes):
|
||||
'account': d.account,
|
||||
'party': d.party,
|
||||
'party_type': d.party_type,
|
||||
reconcile_dr_or_cr: (abs(d.allocated_amount)
|
||||
if abs(d.unadjusted_amount) > abs(d.allocated_amount) else abs(d.unadjusted_amount)),
|
||||
d.dr_or_cr: abs(d.allocated_amount),
|
||||
'reference_type': d.against_voucher_type,
|
||||
'reference_name': d.against_voucher
|
||||
},
|
||||
@@ -281,7 +280,8 @@ def reconcile_dr_cr_note(dr_cr_notes):
|
||||
'account': d.account,
|
||||
'party': d.party,
|
||||
'party_type': d.party_type,
|
||||
dr_or_cr: abs(d.allocated_amount),
|
||||
reconcile_dr_or_cr: (abs(d.allocated_amount)
|
||||
if abs(d.unadjusted_amount) > abs(d.allocated_amount) else abs(d.unadjusted_amount)),
|
||||
'reference_type': d.voucher_type,
|
||||
'reference_name': d.voucher_no
|
||||
}
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
cur_frm.add_fetch("payment_gateway", "payment_account", "payment_account")
|
||||
cur_frm.add_fetch("payment_gateway", "payment_gateway", "payment_gateway")
|
||||
cur_frm.add_fetch("payment_gateway", "message", "message")
|
||||
cur_frm.add_fetch("payment_gateway", "payment_url_message", "payment_url_message")
|
||||
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) {
|
||||
|
||||
@@ -20,7 +20,7 @@ class PaymentRequest(Document):
|
||||
if self.get("__islocal"):
|
||||
self.status = 'Draft'
|
||||
self.validate_reference_document()
|
||||
self.validate_payment_request()
|
||||
self.validate_payment_request_amount()
|
||||
self.validate_currency()
|
||||
self.validate_subscription_details()
|
||||
|
||||
@@ -28,10 +28,19 @@ class PaymentRequest(Document):
|
||||
if not self.reference_doctype or not self.reference_name:
|
||||
frappe.throw(_("To create a Payment Request reference document is required"))
|
||||
|
||||
def validate_payment_request(self):
|
||||
if frappe.db.get_value("Payment Request", {"reference_name": self.reference_name,
|
||||
"name": ("!=", self.name), "status": ("not in", ["Initiated", "Paid"]), "docstatus": 1}, "name"):
|
||||
frappe.throw(_("Payment Request already exists {0}".format(self.reference_name)))
|
||||
def validate_payment_request_amount(self):
|
||||
existing_payment_request_amount = \
|
||||
get_existing_payment_request_amount(self.reference_doctype, self.reference_name)
|
||||
|
||||
if existing_payment_request_amount:
|
||||
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
|
||||
if (hasattr(ref_doc, "order_type") \
|
||||
and getattr(ref_doc, "order_type") != "Shopping Cart"):
|
||||
ref_amount = get_amount(ref_doc)
|
||||
|
||||
if existing_payment_request_amount + flt(self.grand_total)> ref_amount:
|
||||
frappe.throw(_("Total Payment Request amount cannot be greater than {0} amount"
|
||||
.format(self.reference_doctype)))
|
||||
|
||||
def validate_currency(self):
|
||||
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
|
||||
@@ -271,7 +280,7 @@ def make_payment_request(**args):
|
||||
args = frappe._dict(args)
|
||||
|
||||
ref_doc = frappe.get_doc(args.dt, args.dn)
|
||||
grand_total = get_amount(ref_doc, args.dt)
|
||||
grand_total = get_amount(ref_doc)
|
||||
if args.loyalty_points and args.dt == "Sales Order":
|
||||
from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points
|
||||
loyalty_amount = validate_loyalty_points(ref_doc, int(args.loyalty_points))
|
||||
@@ -281,17 +290,25 @@ def make_payment_request(**args):
|
||||
|
||||
gateway_account = get_gateway_details(args) or frappe._dict()
|
||||
|
||||
existing_payment_request = frappe.db.get_value("Payment Request",
|
||||
{"reference_doctype": args.dt, "reference_name": args.dn, "docstatus": ["!=", 2]})
|
||||
|
||||
bank_account = (get_party_bank_account(args.get('party_type'), args.get('party'))
|
||||
if args.get('party_type') else '')
|
||||
|
||||
existing_payment_request = None
|
||||
if args.order_type == "Shopping Cart":
|
||||
existing_payment_request = frappe.db.get_value("Payment Request",
|
||||
{"reference_doctype": args.dt, "reference_name": args.dn, "docstatus": ("!=", 2)})
|
||||
|
||||
if existing_payment_request:
|
||||
frappe.db.set_value("Payment Request", existing_payment_request, "grand_total", grand_total, update_modified=False)
|
||||
pr = frappe.get_doc("Payment Request", existing_payment_request)
|
||||
|
||||
else:
|
||||
if args.order_type != "Shopping Cart":
|
||||
existing_payment_request_amount = \
|
||||
get_existing_payment_request_amount(args.dt, args.dn)
|
||||
|
||||
if existing_payment_request_amount:
|
||||
grand_total -= existing_payment_request_amount
|
||||
|
||||
pr = frappe.new_doc("Payment Request")
|
||||
pr.update({
|
||||
"payment_gateway_account": gateway_account.get("name"),
|
||||
@@ -327,18 +344,19 @@ def make_payment_request(**args):
|
||||
|
||||
return pr.as_dict()
|
||||
|
||||
def get_amount(ref_doc, dt):
|
||||
def get_amount(ref_doc):
|
||||
"""get amount based on doctype"""
|
||||
dt = ref_doc.doctype
|
||||
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 :
|
||||
@@ -347,6 +365,17 @@ def get_amount(ref_doc, dt):
|
||||
else:
|
||||
frappe.throw(_("Payment Entry is already created"))
|
||||
|
||||
def get_existing_payment_request_amount(ref_dt, ref_dn):
|
||||
existing_payment_request_amount = frappe.db.sql("""
|
||||
select sum(grand_total)
|
||||
from `tabPayment Request`
|
||||
where
|
||||
reference_doctype = %s
|
||||
and reference_name = %s
|
||||
and docstatus = 1
|
||||
""", (ref_dt, ref_dn))
|
||||
return flt(existing_payment_request_amount[0][0]) if existing_payment_request_amount else 0
|
||||
|
||||
def get_gateway_details(args):
|
||||
"""return gateway and payment account of default payment gateway"""
|
||||
if args.get("payment_gateway"):
|
||||
|
||||
@@ -37,12 +37,12 @@ class TestPaymentRequest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
if not frappe.db.get_value("Payment Gateway", payment_gateway["gateway"], "name"):
|
||||
frappe.get_doc(payment_gateway).insert(ignore_permissions=True)
|
||||
|
||||
|
||||
for method in payment_method:
|
||||
if not frappe.db.get_value("Payment Gateway Account", {"payment_gateway": method["payment_gateway"],
|
||||
if not frappe.db.get_value("Payment Gateway Account", {"payment_gateway": method["payment_gateway"],
|
||||
"currency": method["currency"]}, "name"):
|
||||
frappe.get_doc(method).insert(ignore_permissions=True)
|
||||
|
||||
|
||||
def test_payment_request_linkings(self):
|
||||
so_inr = make_sales_order(currency="INR")
|
||||
pr = make_payment_request(dt="Sales Order", dn=so_inr.name, recipient_id="saurabh@erpnext.com")
|
||||
@@ -100,3 +100,23 @@ class TestPaymentRequest(unittest.TestCase):
|
||||
self.assertEqual(expected_gle[gle.account][1], gle.debit)
|
||||
self.assertEqual(expected_gle[gle.account][2], gle.credit)
|
||||
self.assertEqual(expected_gle[gle.account][3], gle.against_voucher)
|
||||
|
||||
def test_multiple_payment_entries_against_sales_order(self):
|
||||
# Make Sales Order, grand_total = 1000
|
||||
so = make_sales_order()
|
||||
|
||||
# Payment Request amount = 200
|
||||
pr1 = make_payment_request(dt="Sales Order", dn=so.name,
|
||||
recipient_id="nabin@erpnext.com", return_doc=1)
|
||||
pr1.grand_total = 200
|
||||
pr1.submit()
|
||||
|
||||
# Make a 2nd Payment Request
|
||||
pr2 = make_payment_request(dt="Sales Order", dn=so.name,
|
||||
recipient_id="nabin@erpnext.com", return_doc=1)
|
||||
|
||||
self.assertEqual(pr2.grand_total, 800)
|
||||
|
||||
# Try to make Payment Request more than SO amount, should give validation
|
||||
pr2.grand_total = 900
|
||||
self.assertRaises(frappe.ValidationError, pr2.save)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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"))
|
||||
@@ -181,8 +187,9 @@ def get_serial_no_for_item(args):
|
||||
item_details.serial_no = get_serial_no(args)
|
||||
return item_details
|
||||
|
||||
def get_pricing_rule_for_item(args, price_list_rate=0, doc=None):
|
||||
from erpnext.accounts.doctype.pricing_rule.utils import get_pricing_rules
|
||||
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_product_discount_rule)
|
||||
|
||||
if isinstance(doc, string_types):
|
||||
doc = json.loads(doc)
|
||||
@@ -209,6 +216,57 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None):
|
||||
item_details, args.get('item_code'))
|
||||
return item_details
|
||||
|
||||
update_args_for_pricing_rule(args)
|
||||
|
||||
pricing_rules = (get_applied_pricing_rules(args)
|
||||
if for_validate and args.get("pricing_rules") else get_pricing_rules(args, doc))
|
||||
|
||||
if pricing_rules:
|
||||
rules = []
|
||||
|
||||
for pricing_rule in pricing_rules:
|
||||
if not pricing_rule: continue
|
||||
|
||||
if isinstance(pricing_rule, string_types):
|
||||
pricing_rule = frappe.get_cached_doc("Pricing Rule", pricing_rule)
|
||||
pricing_rule.apply_rule_on_other_items = get_pricing_rule_items(pricing_rule)
|
||||
|
||||
if pricing_rule.get('suggestion'): continue
|
||||
|
||||
item_details.validate_applied_rule = pricing_rule.get("validate_applied_rule", 0)
|
||||
item_details.price_or_product_discount = pricing_rule.get("price_or_product_discount")
|
||||
|
||||
rules.append(get_pricing_rule_details(args, pricing_rule))
|
||||
|
||||
if pricing_rule.mixed_conditions or pricing_rule.apply_rule_on_other:
|
||||
item_details.update({
|
||||
'apply_rule_on_other_items': json.dumps(pricing_rule.apply_rule_on_other_items),
|
||||
'apply_rule_on': (frappe.scrub(pricing_rule.apply_rule_on_other)
|
||||
if pricing_rule.apply_rule_on_other else frappe.scrub(pricing_rule.get('apply_on')))
|
||||
})
|
||||
|
||||
if pricing_rule.coupon_code_based==1 and args.coupon_code==None:
|
||||
return item_details
|
||||
|
||||
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, doc)
|
||||
|
||||
item_details.has_pricing_rule = 1
|
||||
|
||||
item_details.pricing_rules = ','.join([d.pricing_rule for d in rules])
|
||||
|
||||
if not doc: return item_details
|
||||
|
||||
elif args.get("pricing_rules"):
|
||||
item_details = remove_pricing_rule_for_item(args.get("pricing_rules"),
|
||||
item_details, args.get('item_code'))
|
||||
|
||||
return item_details
|
||||
|
||||
def update_args_for_pricing_rule(args):
|
||||
if not (args.item_group and args.brand):
|
||||
try:
|
||||
args.item_group, args.brand = frappe.get_cached_value("Item", args.item_code, ["item_group", "brand"])
|
||||
@@ -235,53 +293,16 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None):
|
||||
args.supplier_group = frappe.get_cached_value("Supplier", args.supplier, "supplier_group")
|
||||
args.customer = args.customer_group = args.territory = None
|
||||
|
||||
pricing_rules = get_pricing_rules(args, doc)
|
||||
|
||||
if pricing_rules:
|
||||
rules = []
|
||||
|
||||
for pricing_rule in pricing_rules:
|
||||
if not pricing_rule or pricing_rule.get('suggestion'): continue
|
||||
|
||||
item_details.validate_applied_rule = pricing_rule.get("validate_applied_rule", 0)
|
||||
|
||||
rules.append(get_pricing_rule_details(args, pricing_rule))
|
||||
if pricing_rule.mixed_conditions or pricing_rule.apply_rule_on_other:
|
||||
continue
|
||||
|
||||
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)
|
||||
|
||||
item_details.has_pricing_rule = 1
|
||||
|
||||
# if discount is applied on the rate and not on price list rate
|
||||
# if price_list_rate:
|
||||
# set_discount_amount(price_list_rate, item_details)
|
||||
|
||||
item_details.pricing_rules = ','.join([d.pricing_rule for d in rules])
|
||||
|
||||
if not doc: return item_details
|
||||
|
||||
for rule in rules:
|
||||
doc.append('pricing_rules', rule)
|
||||
|
||||
elif args.get("pricing_rules"):
|
||||
item_details = remove_pricing_rule_for_item(args.get("pricing_rules"),
|
||||
item_details, args.get('item_code'))
|
||||
|
||||
return item_details
|
||||
|
||||
def get_pricing_rule_details(args, pricing_rule):
|
||||
return frappe._dict({
|
||||
'pricing_rule': pricing_rule.name,
|
||||
'rate_or_discount': pricing_rule.rate_or_discount,
|
||||
'margin_type': pricing_rule.margin_type,
|
||||
'item_code': pricing_rule.item_code or args.get("item_code"),
|
||||
'item_code': args.get("item_code"),
|
||||
'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)
|
||||
@@ -324,10 +345,10 @@ def set_discount_amount(rate, item_details):
|
||||
item_details.rate = rate
|
||||
|
||||
def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None):
|
||||
from erpnext.accounts.doctype.pricing_rule.utils import get_apply_on_and_items
|
||||
from erpnext.accounts.doctype.pricing_rule.utils import get_pricing_rule_items
|
||||
for d in pricing_rules.split(','):
|
||||
if not d or not frappe.db.exists("Pricing Rule", d): continue
|
||||
pricing_rule = frappe.get_doc('Pricing Rule', d)
|
||||
pricing_rule = frappe.get_cached_doc('Pricing Rule', d)
|
||||
|
||||
if pricing_rule.price_or_product_discount == 'Price':
|
||||
if pricing_rule.rate_or_discount == 'Discount Percentage':
|
||||
@@ -345,8 +366,9 @@ def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None):
|
||||
else pricing_rule.get('free_item'))
|
||||
|
||||
if pricing_rule.get("mixed_conditions") or pricing_rule.get("apply_rule_on_other"):
|
||||
apply_on, items = get_apply_on_and_items(pricing_rule, item_details)
|
||||
item_details.apply_on = apply_on
|
||||
items = get_pricing_rule_items(pricing_rule)
|
||||
item_details.apply_on = (frappe.scrub(pricing_rule.apply_rule_on_other)
|
||||
if pricing_rule.apply_rule_on_other else frappe.scrub(pricing_rule.get('apply_on')))
|
||||
item_details.applied_on_items = ','.join(items)
|
||||
|
||||
item_details.pricing_rules = ''
|
||||
@@ -400,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)
|
||||
|
||||
@@ -7,7 +7,8 @@ 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
|
||||
|
||||
@@ -173,10 +174,11 @@ def filter_pricing_rules(args, pricing_rules, doc=None):
|
||||
|
||||
if (field and pricing_rules[0].get('other_' + field) != args.get(field)): return
|
||||
|
||||
pr_doc = frappe.get_doc('Pricing Rule', pricing_rules[0].name)
|
||||
pr_doc = frappe.get_cached_doc('Pricing Rule', pricing_rules[0].name)
|
||||
|
||||
if pricing_rules[0].mixed_conditions and doc:
|
||||
stock_qty, amount = get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args)
|
||||
stock_qty, amount, items = get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args)
|
||||
pricing_rules[0].apply_rule_on_other_items = items
|
||||
|
||||
elif pricing_rules[0].is_cumulative:
|
||||
items = [args.get(frappe.scrub(pr_doc.get('apply_on')))]
|
||||
@@ -282,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)
|
||||
@@ -339,17 +341,19 @@ def get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args):
|
||||
sum_qty += data[0]
|
||||
sum_amt += data[1]
|
||||
|
||||
return sum_qty, sum_amt
|
||||
return sum_qty, sum_amt, items
|
||||
|
||||
def get_qty_and_rate_for_other_item(doc, pr_doc, pricing_rules):
|
||||
for d in get_pricing_rule_items(pr_doc):
|
||||
for row in doc.items:
|
||||
if d == row.get(frappe.scrub(pr_doc.apply_on)):
|
||||
pricing_rules = filter_pricing_rules_for_qty_amount(row.get("stock_qty"),
|
||||
row.get("amount"), pricing_rules, row)
|
||||
items = get_pricing_rule_items(pr_doc)
|
||||
|
||||
if pricing_rules and pricing_rules[0]:
|
||||
return pricing_rules
|
||||
for row in doc.items:
|
||||
if row.get(frappe.scrub(pr_doc.apply_rule_on_other)) in items:
|
||||
pricing_rules = filter_pricing_rules_for_qty_amount(row.get("stock_qty"),
|
||||
row.get("amount"), pricing_rules, row)
|
||||
|
||||
if pricing_rules and pricing_rules[0]:
|
||||
pricing_rules[0].apply_rule_on_other_items = items
|
||||
return pricing_rules
|
||||
|
||||
def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]):
|
||||
sum_qty, sum_amt = [0, 0]
|
||||
@@ -382,7 +386,7 @@ def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]):
|
||||
`tab{child_doc}`.amount
|
||||
FROM `tab{child_doc}`, `tab{parent_doc}`
|
||||
WHERE
|
||||
`tab{child_doc}`.parent = `tab{parent_doc}`.name and {date_field}
|
||||
`tab{child_doc}`.parent = `tab{parent_doc}`.name and `tab{parent_doc}`.{date_field}
|
||||
between %s and %s and `tab{parent_doc}`.docstatus = 1
|
||||
{condition} group by `tab{child_doc}`.name
|
||||
""".format(parent_doc = doctype,
|
||||
@@ -397,38 +401,15 @@ def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]):
|
||||
|
||||
return [sum_qty, sum_amt]
|
||||
|
||||
def validate_pricing_rules(doc):
|
||||
validate_pricing_rule_on_transactions(doc)
|
||||
|
||||
for d in doc.items:
|
||||
validate_pricing_rule_on_items(doc, d)
|
||||
|
||||
doc.calculate_taxes_and_totals()
|
||||
|
||||
def validate_pricing_rule_on_items(doc, item_row, do_not_validate = False):
|
||||
value = 0
|
||||
for pricing_rule in get_applied_pricing_rules(doc, item_row):
|
||||
pr_doc = frappe.get_doc('Pricing Rule', pricing_rule)
|
||||
|
||||
if pr_doc.get('apply_on') == 'Transaction': continue
|
||||
|
||||
if pr_doc.get('price_or_product_discount') == 'Product':
|
||||
apply_pricing_rule_for_free_items(doc, pr_doc)
|
||||
else:
|
||||
for field in ['discount_percentage', 'discount_amount', 'rate']:
|
||||
if not pr_doc.get(field): continue
|
||||
|
||||
value += pr_doc.get(field)
|
||||
apply_pricing_rule(doc, pr_doc, item_row, value, do_not_validate)
|
||||
|
||||
def validate_pricing_rule_on_transactions(doc):
|
||||
def apply_pricing_rule_on_transaction(doc):
|
||||
conditions = "apply_on = 'Transaction'"
|
||||
|
||||
values = {}
|
||||
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,
|
||||
@@ -440,95 +421,108 @@ def validate_pricing_rule_on_transactions(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))
|
||||
elif d.price_or_product_discount == 'Product':
|
||||
apply_pricing_rule_for_free_items(doc, d)
|
||||
|
||||
def get_applied_pricing_rules(doc, item_row):
|
||||
doc.calculate_taxes_and_totals()
|
||||
elif d.price_or_product_discount == 'Product':
|
||||
item_details = frappe._dict({'parenttype': doc.doctype})
|
||||
get_product_discount_rule(d, item_details, 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, doc=None):
|
||||
free_item = (pricing_rule.free_item
|
||||
if not pricing_rule.same_item or pricing_rule.apply_on == 'Transaction' else item_details.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'),
|
||||
'is_free_item': 1
|
||||
})
|
||||
|
||||
doc.set_missing_values()
|
||||
|
||||
def apply_pricing_rule(doc, pr_doc, item_row, value, do_not_validate=False):
|
||||
apply_on, items = get_apply_on_and_items(pr_doc, item_row)
|
||||
|
||||
rule_applied = {}
|
||||
|
||||
for item in doc.get("items"):
|
||||
if item.get(apply_on) in items:
|
||||
if not item.pricing_rules:
|
||||
item.pricing_rules = item_row.pricing_rules
|
||||
|
||||
for field in ['discount_percentage', 'discount_amount', 'rate']:
|
||||
if not pr_doc.get(field): continue
|
||||
|
||||
key = (item.name, item.pricing_rules)
|
||||
if not pr_doc.validate_applied_rule:
|
||||
rule_applied[key] = 1
|
||||
item.set(field, value)
|
||||
elif item.get(field) < value:
|
||||
if not do_not_validate and item.idx == item_row.idx:
|
||||
rule_applied[key] = 0
|
||||
frappe.msgprint(_("Row {0}: user has not applied rule <b>{1}</b> on the item <b>{2}</b>")
|
||||
.format(item.idx, pr_doc.title, item.item_code))
|
||||
|
||||
if rule_applied and doc.get("pricing_rules"):
|
||||
for d in doc.get("pricing_rules"):
|
||||
key = (d.child_docname, d.pricing_rule)
|
||||
if key in rule_applied:
|
||||
d.rule_applied = 1
|
||||
|
||||
def get_apply_on_and_items(pr_doc, item_row):
|
||||
# for mixed or other items conditions
|
||||
apply_on = frappe.scrub(pr_doc.get('apply_on'))
|
||||
items = (get_pricing_rule_items(pr_doc)
|
||||
if pr_doc.mixed_conditions else [item_row.get(apply_on)])
|
||||
|
||||
if pr_doc.apply_rule_on_other:
|
||||
apply_on = frappe.scrub(pr_doc.apply_rule_on_other)
|
||||
items = [pr_doc.get(apply_on)]
|
||||
|
||||
return apply_on, items
|
||||
doc.append('items', pricing_rule_args)
|
||||
|
||||
def get_pricing_rule_items(pr_doc):
|
||||
apply_on_data = []
|
||||
apply_on = frappe.scrub(pr_doc.get('apply_on'))
|
||||
|
||||
pricing_rule_apply_on = apply_on_table.get(pr_doc.get('apply_on'))
|
||||
|
||||
return [item.get(apply_on) for item in pr_doc.get(pricing_rule_apply_on)] or []
|
||||
for d in pr_doc.get(pricing_rule_apply_on):
|
||||
if apply_on == 'item_group':
|
||||
get_child_item_groups(d.get(apply_on))
|
||||
else:
|
||||
apply_on_data.append(d.get(apply_on))
|
||||
|
||||
@frappe.whitelist()
|
||||
def validate_pricing_rule_for_different_cond(doc):
|
||||
if isinstance(doc, string_types):
|
||||
doc = json.loads(doc)
|
||||
if pr_doc.apply_rule_on_other:
|
||||
apply_on = frappe.scrub(pr_doc.apply_rule_on_other)
|
||||
apply_on_data.append(pr_doc.get("other_" + apply_on))
|
||||
|
||||
doc = frappe.get_doc(doc)
|
||||
for d in doc.get("items"):
|
||||
validate_pricing_rule_on_items(doc, d, True)
|
||||
return list(set(apply_on_data))
|
||||
|
||||
return doc
|
||||
def validate_coupon_code(coupon_name):
|
||||
from frappe.utils import today,getdate
|
||||
coupon=frappe.get_doc("Coupon Code",coupon_name)
|
||||
if coupon.valid_from:
|
||||
if coupon.valid_from > getdate(today()) :
|
||||
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"))
|
||||
elif coupon.used>=coupon.maximum_use:
|
||||
frappe.throw(_("Sorry,coupon code are exhausted"))
|
||||
else:
|
||||
return
|
||||
|
||||
def update_coupon_code_count(coupon_name,transaction_type):
|
||||
coupon=frappe.get_doc("Coupon Code",coupon_name)
|
||||
if coupon:
|
||||
if transaction_type=='used':
|
||||
if coupon.used<coupon.maximum_use:
|
||||
coupon.used=coupon.used+1
|
||||
coupon.save(ignore_permissions=True)
|
||||
else:
|
||||
frappe.throw(_("{0} Coupon used are {1}. Allowed quantity is exhausted").format(coupon.coupon_code,coupon.used))
|
||||
elif transaction_type=='cancelled':
|
||||
if coupon.used>0:
|
||||
coupon.used=coupon.used-1
|
||||
coupon.save(ignore_permissions=True)
|
||||
@@ -330,23 +330,6 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
frm: cur_frm
|
||||
})
|
||||
},
|
||||
|
||||
asset: function(frm, cdt, cdn) {
|
||||
var row = locals[cdt][cdn];
|
||||
if(row.asset) {
|
||||
frappe.call({
|
||||
method: "erpnext.assets.doctype.asset_category.asset_category.get_asset_category_account",
|
||||
args: {
|
||||
"asset": row.asset,
|
||||
"fieldname": "fixed_asset_account",
|
||||
"account": row.expense_account
|
||||
},
|
||||
callback: function(r, rt) {
|
||||
frappe.model.set_value(cdt, cdn, "expense_account", r.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cur_frm.script_manager.make(erpnext.accounts.PurchaseInvoice);
|
||||
@@ -399,21 +382,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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -430,19 +403,7 @@ cur_frm.fields_dict['select_print_heading'].get_query = function(doc, cdt, cdn)
|
||||
cur_frm.set_query("expense_account", "items", function(doc) {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.get_expense_account",
|
||||
filters: {'company': doc.company}
|
||||
}
|
||||
});
|
||||
|
||||
cur_frm.set_query("asset", "items", function(doc, cdt, cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
return {
|
||||
filters: {
|
||||
'item_code': d.item_code,
|
||||
'docstatus': 1,
|
||||
'company': doc.company,
|
||||
'status': 'Submitted'
|
||||
}
|
||||
filters: {'company': doc.company }
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,13 +18,14 @@ from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entri
|
||||
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
||||
from erpnext.buying.utils import check_on_hold_or_closed_status
|
||||
from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
|
||||
from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_disabled
|
||||
from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_enabled
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from six import iteritems
|
||||
from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\
|
||||
unlink_inter_company_doc
|
||||
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
|
||||
from erpnext.accounts.deferred_revenue import validate_service_stop_date
|
||||
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import get_item_account_wise_additional_cost
|
||||
|
||||
form_grid_templates = {
|
||||
"items": "templates/form_grid/item_grid.html"
|
||||
@@ -97,7 +98,6 @@ class PurchaseInvoice(BuyingController):
|
||||
self.set_against_expense_account()
|
||||
self.validate_write_off_account()
|
||||
self.validate_multiple_billing("Purchase Receipt", "pr_detail", "amount", "items")
|
||||
self.validate_fixed_asset()
|
||||
self.create_remarks()
|
||||
self.set_status()
|
||||
self.validate_purchase_receipt_if_update_stock()
|
||||
@@ -225,6 +225,8 @@ class PurchaseInvoice(BuyingController):
|
||||
# in case of auto inventory accounting,
|
||||
# expense account is always "Stock Received But Not Billed" for a stock item
|
||||
# except epening entry, drop-ship entry and fixed asset items
|
||||
if item.item_code:
|
||||
asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category")
|
||||
|
||||
if auto_accounting_for_stock and item.item_code in stock_items \
|
||||
and self.is_opening == 'No' and not item.is_fixed_asset \
|
||||
@@ -235,12 +237,8 @@ class PurchaseInvoice(BuyingController):
|
||||
item.expense_account = warehouse_account[item.warehouse]["account"]
|
||||
else:
|
||||
item.expense_account = stock_not_billed_account
|
||||
elif item.is_fixed_asset and is_cwip_accounting_disabled():
|
||||
if not item.asset:
|
||||
frappe.throw(_("Row {0}: asset is required for item {1}")
|
||||
.format(item.idx, item.item_code))
|
||||
|
||||
item.expense_account = get_asset_category_account(item.asset, 'fixed_asset_account',
|
||||
elif item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category):
|
||||
item.expense_account = get_asset_category_account('fixed_asset_account', item=item.item_code,
|
||||
company = self.company)
|
||||
elif item.is_fixed_asset and item.pr_detail:
|
||||
item.expense_account = asset_received_but_not_billed
|
||||
@@ -250,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)
|
||||
@@ -364,7 +362,7 @@ class PurchaseInvoice(BuyingController):
|
||||
update_outstanding = "No" if (cint(self.is_paid) or self.write_off_account) else "Yes"
|
||||
|
||||
make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
|
||||
update_outstanding=update_outstanding, merge_entries=False)
|
||||
update_outstanding=update_outstanding, merge_entries=False, from_repost=from_repost)
|
||||
|
||||
if update_outstanding == "No":
|
||||
update_outstanding_amt(self.credit_to, "Supplier", self.supplier,
|
||||
@@ -391,7 +389,8 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
self.make_supplier_gl_entry(gl_entries)
|
||||
self.make_item_gl_entries(gl_entries)
|
||||
if not is_cwip_accounting_disabled():
|
||||
|
||||
if self.check_asset_cwip_enabled():
|
||||
self.get_asset_gl_entry(gl_entries)
|
||||
|
||||
self.make_tax_gl_entries(gl_entries)
|
||||
@@ -404,6 +403,15 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
return gl_entries
|
||||
|
||||
def check_asset_cwip_enabled(self):
|
||||
# Check if there exists any item with cwip accounting enabled in it's asset category
|
||||
for item in self.get("items"):
|
||||
if item.item_code and item.is_fixed_asset:
|
||||
asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category")
|
||||
if is_cwip_accounting_enabled(asset_category):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def make_supplier_gl_entry(self, gl_entries):
|
||||
# Checked both rounding_adjustment and rounded_total
|
||||
# because rounded_total had value even before introcution of posting GLE based on rounded total
|
||||
@@ -436,15 +444,23 @@ class PurchaseInvoice(BuyingController):
|
||||
if self.update_stock and self.auto_accounting_for_stock:
|
||||
warehouse_account = get_warehouse_account_map(self.company)
|
||||
|
||||
landed_cost_entries = get_item_account_wise_additional_cost(self.name)
|
||||
|
||||
voucher_wise_stock_value = {}
|
||||
if self.update_stock:
|
||||
for d in frappe.get_all('Stock Ledger Entry',
|
||||
fields = ["voucher_detail_no", "stock_value_difference"], filters={'voucher_no': self.name}):
|
||||
voucher_wise_stock_value.setdefault(d.voucher_detail_no, d.stock_value_difference)
|
||||
|
||||
valuation_tax_accounts = [d.account_head for d in self.get("taxes")
|
||||
if d.category in ('Valuation', 'Total and Valuation')
|
||||
and flt(d.base_tax_amount_after_discount_amount)]
|
||||
|
||||
for item in self.get("items"):
|
||||
if flt(item.base_net_amount):
|
||||
account_currency = get_account_currency(item.expense_account)
|
||||
if item.item_code:
|
||||
asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category")
|
||||
|
||||
if self.update_stock and self.auto_accounting_for_stock and item.item_code in stock_items:
|
||||
# warehouse account
|
||||
@@ -463,15 +479,16 @@ class PurchaseInvoice(BuyingController):
|
||||
)
|
||||
|
||||
# Amount added through landed-cost-voucher
|
||||
if flt(item.landed_cost_voucher_amount):
|
||||
gl_entries.append(self.get_gl_dict({
|
||||
"account": expenses_included_in_valuation,
|
||||
"against": item.expense_account,
|
||||
"cost_center": item.cost_center,
|
||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||
"credit": flt(item.landed_cost_voucher_amount),
|
||||
"project": item.project
|
||||
}, item=item))
|
||||
if landed_cost_entries:
|
||||
for account, amount in iteritems(landed_cost_entries[(item.item_code, item.name)]):
|
||||
gl_entries.append(self.get_gl_dict({
|
||||
"account": account,
|
||||
"against": item.expense_account,
|
||||
"cost_center": item.cost_center,
|
||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||
"credit": flt(amount),
|
||||
"project": item.project
|
||||
}, item=item))
|
||||
|
||||
# sub-contracting warehouse
|
||||
if flt(item.rm_supp_cost):
|
||||
@@ -486,31 +503,61 @@ class PurchaseInvoice(BuyingController):
|
||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||
"credit": flt(item.rm_supp_cost)
|
||||
}, warehouse_account[self.supplier_warehouse]["account_currency"], item=item))
|
||||
elif not item.is_fixed_asset or (item.is_fixed_asset and is_cwip_accounting_disabled()):
|
||||
|
||||
elif not item.is_fixed_asset or (item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category)):
|
||||
expense_account = (item.expense_account
|
||||
if (not item.enable_deferred_expense or self.is_return) else item.deferred_expense_account)
|
||||
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
if not item.is_fixed_asset:
|
||||
amount = flt(item.base_net_amount, item.precision("base_net_amount"))
|
||||
else:
|
||||
amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount"))
|
||||
|
||||
gl_entries.append(self.get_gl_dict({
|
||||
"account": expense_account,
|
||||
"against": self.supplier,
|
||||
"debit": flt(item.base_net_amount, item.precision("base_net_amount")),
|
||||
"debit_in_account_currency": (flt(item.base_net_amount,
|
||||
item.precision("base_net_amount")) if account_currency==self.company_currency
|
||||
else flt(item.net_amount, item.precision("net_amount"))),
|
||||
"debit": amount,
|
||||
"cost_center": item.cost_center,
|
||||
"project": item.project
|
||||
}, account_currency, item=item)
|
||||
)
|
||||
}, account_currency, item=item))
|
||||
|
||||
# If asset is bought through this document and not linked to PR
|
||||
if self.update_stock and item.landed_cost_voucher_amount:
|
||||
expenses_included_in_asset_valuation = self.get_company_default("expenses_included_in_asset_valuation")
|
||||
# Amount added through landed-cost-voucher
|
||||
gl_entries.append(self.get_gl_dict({
|
||||
"account": expenses_included_in_asset_valuation,
|
||||
"against": expense_account,
|
||||
"cost_center": item.cost_center,
|
||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||
"credit": flt(item.landed_cost_voucher_amount),
|
||||
"project": item.project
|
||||
}, item=item))
|
||||
|
||||
gl_entries.append(self.get_gl_dict({
|
||||
"account": expense_account,
|
||||
"against": expenses_included_in_asset_valuation,
|
||||
"cost_center": item.cost_center,
|
||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||
"debit": flt(item.landed_cost_voucher_amount),
|
||||
"project": item.project
|
||||
}, item=item))
|
||||
|
||||
# update gross amount of asset bought through this document
|
||||
assets = frappe.db.get_all('Asset',
|
||||
filters={ 'purchase_invoice': self.name, 'item_code': item.item_code }
|
||||
)
|
||||
for asset in assets:
|
||||
frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(item.valuation_rate))
|
||||
frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate))
|
||||
|
||||
if self.auto_accounting_for_stock and self.is_opening == "No" and \
|
||||
item.item_code in stock_items and item.item_tax_amount:
|
||||
# Post reverse entry for Stock-Received-But-Not-Billed if it is booked in Purchase Receipt
|
||||
if item.purchase_receipt:
|
||||
if item.purchase_receipt and valuation_tax_accounts:
|
||||
negative_expense_booked_in_pr = frappe.db.sql("""select name from `tabGL Entry`
|
||||
where voucher_type='Purchase Receipt' and voucher_no=%s and account=%s""",
|
||||
(item.purchase_receipt, self.expenses_included_in_valuation))
|
||||
where voucher_type='Purchase Receipt' and voucher_no=%s and account in %s""",
|
||||
(item.purchase_receipt, valuation_tax_accounts))
|
||||
|
||||
if not negative_expense_booked_in_pr:
|
||||
gl_entries.append(
|
||||
@@ -527,27 +574,27 @@ class PurchaseInvoice(BuyingController):
|
||||
item.precision("item_tax_amount"))
|
||||
|
||||
def get_asset_gl_entry(self, gl_entries):
|
||||
arbnb_account = self.get_company_default("asset_received_but_not_billed")
|
||||
eiiav_account = self.get_company_default("expenses_included_in_asset_valuation")
|
||||
|
||||
for item in self.get("items"):
|
||||
if item.is_fixed_asset:
|
||||
eiiav_account = self.get_company_default("expenses_included_in_asset_valuation")
|
||||
|
||||
asset_amount = flt(item.net_amount) + flt(item.item_tax_amount/self.conversion_rate)
|
||||
base_asset_amount = flt(item.base_net_amount + item.item_tax_amount)
|
||||
|
||||
if (not item.expense_account or frappe.db.get_value('Account',
|
||||
item.expense_account, 'account_type') not in ['Asset Received But Not Billed', 'Fixed Asset']):
|
||||
arbnb_account = self.get_company_default("asset_received_but_not_billed")
|
||||
item_exp_acc_type = frappe.db.get_value('Account', item.expense_account, 'account_type')
|
||||
if (not item.expense_account or item_exp_acc_type not in ['Asset Received But Not Billed', 'Fixed Asset']):
|
||||
item.expense_account = arbnb_account
|
||||
|
||||
if not self.update_stock:
|
||||
asset_rbnb_currency = get_account_currency(item.expense_account)
|
||||
arbnb_currency = get_account_currency(item.expense_account)
|
||||
gl_entries.append(self.get_gl_dict({
|
||||
"account": item.expense_account,
|
||||
"against": self.supplier,
|
||||
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
|
||||
"debit": base_asset_amount,
|
||||
"debit_in_account_currency": (base_asset_amount
|
||||
if asset_rbnb_currency == self.company_currency else asset_amount),
|
||||
if arbnb_currency == self.company_currency else asset_amount),
|
||||
"cost_center": item.cost_center
|
||||
}, item=item))
|
||||
|
||||
@@ -564,8 +611,7 @@ class PurchaseInvoice(BuyingController):
|
||||
item.item_tax_amount / self.conversion_rate)
|
||||
}, item=item))
|
||||
else:
|
||||
cwip_account = get_asset_account("capital_work_in_progress_account",
|
||||
item.asset, company = self.company)
|
||||
cwip_account = get_asset_account("capital_work_in_progress_account", company = self.company)
|
||||
|
||||
cwip_account_currency = get_account_currency(cwip_account)
|
||||
gl_entries.append(self.get_gl_dict({
|
||||
@@ -591,6 +637,36 @@ class PurchaseInvoice(BuyingController):
|
||||
item.item_tax_amount / self.conversion_rate)
|
||||
}, item=item))
|
||||
|
||||
# When update stock is checked
|
||||
# Assets are bought through this document then it will be linked to this document
|
||||
if self.update_stock:
|
||||
if flt(item.landed_cost_voucher_amount):
|
||||
gl_entries.append(self.get_gl_dict({
|
||||
"account": eiiav_account,
|
||||
"against": cwip_account,
|
||||
"cost_center": item.cost_center,
|
||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||
"credit": flt(item.landed_cost_voucher_amount),
|
||||
"project": item.project
|
||||
}, item=item))
|
||||
|
||||
gl_entries.append(self.get_gl_dict({
|
||||
"account": cwip_account,
|
||||
"against": eiiav_account,
|
||||
"cost_center": item.cost_center,
|
||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||
"debit": flt(item.landed_cost_voucher_amount),
|
||||
"project": item.project
|
||||
}, item=item))
|
||||
|
||||
# update gross amount of assets bought through this document
|
||||
assets = frappe.db.get_all('Asset',
|
||||
filters={ 'purchase_invoice': self.name, 'item_code': item.item_code }
|
||||
)
|
||||
for asset in assets:
|
||||
frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(item.valuation_rate))
|
||||
frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate))
|
||||
|
||||
return gl_entries
|
||||
|
||||
def make_stock_adjustment_entry(self, gl_entries, item, voucher_wise_stock_value, account_currency):
|
||||
@@ -641,14 +717,14 @@ class PurchaseInvoice(BuyingController):
|
||||
if account_currency==self.company_currency \
|
||||
else tax.tax_amount_after_discount_amount,
|
||||
"cost_center": tax.cost_center
|
||||
}, account_currency)
|
||||
}, account_currency, item=tax)
|
||||
)
|
||||
# accumulate valuation tax
|
||||
if self.is_opening == "No" and tax.category in ("Valuation", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount):
|
||||
if self.auto_accounting_for_stock and not tax.cost_center:
|
||||
frappe.throw(_("Cost Center is required in row {0} in Taxes table for type {1}").format(tax.idx, _(tax.category)))
|
||||
valuation_tax.setdefault(tax.cost_center, 0)
|
||||
valuation_tax[tax.cost_center] += \
|
||||
valuation_tax.setdefault(tax.name, 0)
|
||||
valuation_tax[tax.name] += \
|
||||
(tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.base_tax_amount_after_discount_amount)
|
||||
|
||||
if self.is_opening == "No" and self.negative_expense_to_be_booked and valuation_tax:
|
||||
@@ -658,36 +734,38 @@ class PurchaseInvoice(BuyingController):
|
||||
total_valuation_amount = sum(valuation_tax.values())
|
||||
amount_including_divisional_loss = self.negative_expense_to_be_booked
|
||||
i = 1
|
||||
for cost_center, amount in iteritems(valuation_tax):
|
||||
if i == len(valuation_tax):
|
||||
applicable_amount = amount_including_divisional_loss
|
||||
else:
|
||||
applicable_amount = self.negative_expense_to_be_booked * (amount / total_valuation_amount)
|
||||
amount_including_divisional_loss -= applicable_amount
|
||||
for tax in self.get("taxes"):
|
||||
if valuation_tax.get(tax.name):
|
||||
if i == len(valuation_tax):
|
||||
applicable_amount = amount_including_divisional_loss
|
||||
else:
|
||||
applicable_amount = self.negative_expense_to_be_booked * (valuation_tax[tax.name] / total_valuation_amount)
|
||||
amount_including_divisional_loss -= applicable_amount
|
||||
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": self.expenses_included_in_valuation,
|
||||
"cost_center": cost_center,
|
||||
"against": self.supplier,
|
||||
"credit": applicable_amount,
|
||||
"remarks": self.remarks or "Accounting Entry for Stock"
|
||||
})
|
||||
)
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": tax.account_head,
|
||||
"cost_center": tax.cost_center,
|
||||
"against": self.supplier,
|
||||
"credit": applicable_amount,
|
||||
"remarks": self.remarks or _("Accounting Entry for Stock"),
|
||||
}, item=tax)
|
||||
)
|
||||
|
||||
i += 1
|
||||
i += 1
|
||||
|
||||
if self.auto_accounting_for_stock and self.update_stock and valuation_tax:
|
||||
for cost_center, amount in iteritems(valuation_tax):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": self.expenses_included_in_valuation,
|
||||
"cost_center": cost_center,
|
||||
"against": self.supplier,
|
||||
"credit": amount,
|
||||
"remarks": self.remarks or "Accounting Entry for Stock"
|
||||
})
|
||||
)
|
||||
for tax in self.get("taxes"):
|
||||
if valuation_tax.get(tax.name):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": tax.account_head,
|
||||
"cost_center": tax.cost_center,
|
||||
"against": self.supplier,
|
||||
"credit": valuation_tax[tax.name],
|
||||
"remarks": self.remarks or "Accounting Entry for Stock"
|
||||
}, item=tax)
|
||||
)
|
||||
|
||||
def make_payment_gl_entries(self, gl_entries):
|
||||
# Make Cash GL Entries
|
||||
@@ -752,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)
|
||||
|
||||
@@ -880,6 +962,17 @@ class PurchaseInvoice(BuyingController):
|
||||
# calculate totals again after applying TDS
|
||||
self.calculate_taxes_and_totals()
|
||||
|
||||
def get_list_context(context=None):
|
||||
from erpnext.controllers.website_list_for_contact import get_list_context
|
||||
list_context = get_list_context(context)
|
||||
list_context.update({
|
||||
'show_sidebar': True,
|
||||
'show_search': True,
|
||||
'no_breadcrumbs': True,
|
||||
'title': _('Purchase Invoices'),
|
||||
})
|
||||
return list_context
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_debit_note(source_name, target_doc=None):
|
||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||
|
||||
@@ -6,8 +6,8 @@ frappe.listview_settings['Purchase Invoice'] = {
|
||||
add_fields: ["supplier", "supplier_name", "base_grand_total", "outstanding_amount", "due_date", "company",
|
||||
"currency", "is_return", "release_date", "on_hold"],
|
||||
get_indicator: function(doc) {
|
||||
if(flt(doc.outstanding_amount) < 0 && doc.docstatus == 1) {
|
||||
return [__("Debit Note Issued"), "darkgrey", "outstanding_amount,<,0"]
|
||||
if( (flt(doc.outstanding_amount) <= 0) && doc.docstatus == 1 && doc.status == 'Debit Note Issued') {
|
||||
return [__("Debit Note Issued"), "darkgrey", "outstanding_amount,<=,0"];
|
||||
} else if(flt(doc.outstanding_amount) > 0 && doc.docstatus==1) {
|
||||
if(cint(doc.on_hold) && !doc.release_date) {
|
||||
return [__("On Hold"), "darkgrey"];
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{% include "erpnext/regional/india/taxes.js" %}
|
||||
|
||||
erpnext.setup_auto_gst_taxation('Purchase Invoice');
|
||||
@@ -10,7 +10,7 @@ from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_ent
|
||||
from frappe.utils import cint, flt, today, nowdate, add_days
|
||||
import frappe.defaults
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \
|
||||
test_records as pr_test_records
|
||||
test_records as pr_test_records, make_purchase_receipt, get_taxes
|
||||
from erpnext.controllers.accounts_controller import get_payment_terms
|
||||
from erpnext.exceptions import InvalidCurrency
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_transaction
|
||||
@@ -20,11 +20,13 @@ test_dependencies = ["Item", "Cost Center", "Payment Term", "Payment Terms Templ
|
||||
test_ignore = ["Serial No"]
|
||||
|
||||
class TestPurchaseInvoice(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
unlink_payment_on_cancel_of_invoice()
|
||||
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
|
||||
|
||||
def tearDown(self):
|
||||
@classmethod
|
||||
def tearDownClass(self):
|
||||
unlink_payment_on_cancel_of_invoice(0)
|
||||
|
||||
def test_gl_entries_without_perpetual_inventory(self):
|
||||
@@ -55,16 +57,11 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
self.assertEqual([d.debit, d.credit], expected_gl_entries.get(d.account))
|
||||
|
||||
def test_gl_entries_with_perpetual_inventory(self):
|
||||
pi = frappe.copy_doc(test_records[1])
|
||||
set_perpetual_inventory(1, pi.company)
|
||||
pi = make_purchase_invoice(company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1", warehouse= "Stores - TCP1", cost_center = "Main - TCP1", expense_account ="_Test Account Cost for Goods Sold - TCP1", get_taxes_and_charges=True, qty=10)
|
||||
self.assertTrue(cint(erpnext.is_perpetual_inventory_enabled(pi.company)), 1)
|
||||
pi.insert()
|
||||
pi.submit()
|
||||
|
||||
self.check_gle_for_pi(pi.name)
|
||||
|
||||
set_perpetual_inventory(0, pi.company)
|
||||
|
||||
def test_terms_added_after_save(self):
|
||||
pi = frappe.copy_doc(test_records[1])
|
||||
pi.insert()
|
||||
@@ -91,6 +88,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
pi_doc = frappe.get_doc('Purchase Invoice', pi_doc.name)
|
||||
|
||||
self.assertRaises(frappe.LinkExistsError, pi_doc.cancel)
|
||||
unlink_payment_on_cancel_of_invoice()
|
||||
|
||||
def test_purchase_invoice_for_blocked_supplier(self):
|
||||
supplier = frappe.get_doc('Supplier', '_Test Supplier')
|
||||
@@ -193,32 +191,33 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
self.assertEqual(pi.on_hold, 0)
|
||||
|
||||
def test_gl_entries_with_perpetual_inventory_against_pr(self):
|
||||
pr = frappe.copy_doc(pr_test_records[0])
|
||||
set_perpetual_inventory(1, pr.company)
|
||||
self.assertTrue(cint(erpnext.is_perpetual_inventory_enabled(pr.company)), 1)
|
||||
pr.submit()
|
||||
|
||||
pi = frappe.copy_doc(test_records[1])
|
||||
for d in pi.get("items"):
|
||||
pr = make_purchase_receipt(company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1", warehouse= "Stores - TCP1", cost_center = "Main - TCP1", get_taxes_and_charges=True,)
|
||||
|
||||
self.assertTrue(cint(erpnext.is_perpetual_inventory_enabled(pr.company)), 1)
|
||||
|
||||
pi = make_purchase_invoice(company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1", warehouse= "Stores - TCP1", cost_center = "Main - TCP1", expense_account ="_Test Account Cost for Goods Sold - TCP1", get_taxes_and_charges=True, qty=10,do_not_save= "True")
|
||||
|
||||
for d in pi.items:
|
||||
d.purchase_receipt = pr.name
|
||||
|
||||
pi.insert()
|
||||
pi.submit()
|
||||
|
||||
self.check_gle_for_pi(pi.name)
|
||||
|
||||
set_perpetual_inventory(0, pr.company)
|
||||
|
||||
def check_gle_for_pi(self, pi):
|
||||
gl_entries = frappe.db.sql("""select account, debit, credit
|
||||
gl_entries = frappe.db.sql("""select account, sum(debit) as debit, sum(credit) as credit
|
||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
order by account asc""", pi, as_dict=1)
|
||||
group by account""", pi, as_dict=1)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
|
||||
expected_values = dict((d[0], d) for d in [
|
||||
["_Test Payable - _TC", 0, 720],
|
||||
["Stock Received But Not Billed - _TC", 500.0, 0],
|
||||
["_Test Account Shipping Charges - _TC", 100.0, 0],
|
||||
["_Test Account VAT - _TC", 120.0, 0],
|
||||
["Creditors - TCP1", 0, 720],
|
||||
["Stock Received But Not Billed - TCP1", 500.0, 0],
|
||||
["_Test Account Shipping Charges - TCP1", 100.0, 0.0],
|
||||
["_Test Account VAT - TCP1", 120.0, 0]
|
||||
])
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
@@ -521,10 +520,9 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
self.assertFalse(gle)
|
||||
|
||||
def test_purchase_invoice_update_stock_gl_entry_with_perpetual_inventory(self):
|
||||
set_perpetual_inventory()
|
||||
|
||||
pi = make_purchase_invoice(update_stock=1, posting_date=frappe.utils.nowdate(),
|
||||
posting_time=frappe.utils.nowtime())
|
||||
posting_time=frappe.utils.nowtime(), cash_bank_account="Cash - TCP1", company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1", warehouse= "Stores - TCP1", cost_center = "Main - TCP1", expense_account ="_Test Account Cost for Goods Sold - TCP1")
|
||||
|
||||
gl_entries = frappe.db.sql("""select account, account_currency, debit, credit,
|
||||
debit_in_account_currency, credit_in_account_currency
|
||||
@@ -545,9 +543,9 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
self.assertEqual(expected_gl_entries[gle.account][2], gle.credit)
|
||||
|
||||
def test_purchase_invoice_for_is_paid_and_update_stock_gl_entry_with_perpetual_inventory(self):
|
||||
set_perpetual_inventory()
|
||||
|
||||
pi = make_purchase_invoice(update_stock=1, posting_date=frappe.utils.nowdate(),
|
||||
posting_time=frappe.utils.nowtime(), cash_bank_account="Cash - _TC", is_paid=1)
|
||||
posting_time=frappe.utils.nowtime(), cash_bank_account="Cash - TCP1", is_paid=1, company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1", warehouse= "Stores - TCP1", cost_center = "Main - TCP1", expense_account ="_Test Account Cost for Goods Sold - TCP1")
|
||||
|
||||
gl_entries = frappe.db.sql("""select account, account_currency, sum(debit) as debit,
|
||||
sum(credit) as credit, debit_in_account_currency, credit_in_account_currency
|
||||
@@ -560,7 +558,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
expected_gl_entries = dict((d[0], d) for d in [
|
||||
[pi.credit_to, 250.0, 250.0],
|
||||
[stock_in_hand_account, 250.0, 0.0],
|
||||
["Cash - _TC", 0.0, 250.0]
|
||||
["Cash - TCP1", 0.0, 250.0]
|
||||
])
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
@@ -627,6 +625,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
self.assertEqual(pi.get("items")[0].rm_supp_cost, flt(rm_supp_cost, 2))
|
||||
|
||||
def test_rejected_serial_no(self):
|
||||
set_perpetual_inventory(0)
|
||||
pi = make_purchase_invoice(item_code="_Test Serialized Item With Series", received_qty=2, qty=1,
|
||||
rejected_qty=1, rate=500, update_stock=1,
|
||||
rejected_warehouse = "_Test Rejected Warehouse - _TC")
|
||||
@@ -878,7 +877,7 @@ def make_purchase_invoice(**args):
|
||||
pi.is_return = args.is_return
|
||||
pi.return_against = args.return_against
|
||||
pi.is_subcontracted = args.is_subcontracted or "No"
|
||||
pi.supplier_warehouse = "_Test Warehouse 1 - _TC"
|
||||
pi.supplier_warehouse = args.supplier_warehouse or "_Test Warehouse 1 - _TC"
|
||||
|
||||
pi.append("items", {
|
||||
"item_code": args.item or args.item_code or "_Test Item",
|
||||
@@ -887,14 +886,21 @@ def make_purchase_invoice(**args):
|
||||
"received_qty": args.received_qty or 0,
|
||||
"rejected_qty": args.rejected_qty or 0,
|
||||
"rate": args.rate or 50,
|
||||
'expense_account': args.expense_account or '_Test Account Cost for Goods Sold - _TC',
|
||||
"conversion_factor": 1.0,
|
||||
"serial_no": args.serial_no,
|
||||
"stock_uom": "_Test UOM",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"cost_center": args.cost_center or "_Test Cost Center - _TC",
|
||||
"project": args.project,
|
||||
"rejected_warehouse": args.rejected_warehouse or "",
|
||||
"rejected_serial_no": args.rejected_serial_no or ""
|
||||
})
|
||||
|
||||
if args.get_taxes_and_charges:
|
||||
taxes = get_taxes()
|
||||
for tax in taxes:
|
||||
pi.append("taxes", tax)
|
||||
|
||||
if not args.do_not_save:
|
||||
pi.insert()
|
||||
if not args.do_not_submit:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "hash",
|
||||
"creation": "2013-05-22 12:43:10",
|
||||
"doctype": "DocType",
|
||||
@@ -71,8 +72,8 @@
|
||||
"expense_account",
|
||||
"col_break5",
|
||||
"is_fixed_asset",
|
||||
"asset",
|
||||
"asset_location",
|
||||
"asset_category",
|
||||
"deferred_expense_section",
|
||||
"deferred_expense_account",
|
||||
"service_stop_date",
|
||||
@@ -116,6 +117,8 @@
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fetch_from": "item_code.item_name",
|
||||
"fetch_if_empty": 1,
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Data",
|
||||
"in_global_search": 1,
|
||||
@@ -414,6 +417,7 @@
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.is_fixed_asset",
|
||||
"fieldname": "batch_no",
|
||||
"fieldtype": "Link",
|
||||
"label": "Batch No",
|
||||
@@ -425,12 +429,14 @@
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.is_fixed_asset",
|
||||
"fieldname": "serial_no",
|
||||
"fieldtype": "Text",
|
||||
"label": "Serial No",
|
||||
"no_copy": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.is_fixed_asset",
|
||||
"fieldname": "rejected_serial_no",
|
||||
"fieldtype": "Text",
|
||||
"label": "Rejected Serial No",
|
||||
@@ -502,7 +508,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",
|
||||
@@ -518,13 +525,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",
|
||||
@@ -591,7 +600,6 @@
|
||||
"oldfieldname": "purchase_order",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Purchase Order",
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
@@ -607,6 +615,7 @@
|
||||
"fieldname": "include_exploded_items",
|
||||
"fieldtype": "Check",
|
||||
"label": "Include Exploded Items",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
@@ -615,6 +624,7 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fetch_from": "item_code.is_fixed_asset",
|
||||
"fieldname": "is_fixed_asset",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
@@ -623,14 +633,6 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "is_fixed_asset",
|
||||
"fieldname": "asset",
|
||||
"fieldtype": "Link",
|
||||
"label": "Asset",
|
||||
"no_copy": 1,
|
||||
"options": "Asset"
|
||||
},
|
||||
{
|
||||
"depends_on": "is_fixed_asset",
|
||||
"fieldname": "asset_location",
|
||||
@@ -676,7 +678,7 @@
|
||||
"fieldname": "pr_detail",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "PR Detail",
|
||||
"label": "Purchase Receipt Detail",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "pr_detail",
|
||||
"oldfieldtype": "Data",
|
||||
@@ -754,11 +756,22 @@
|
||||
"fieldtype": "Data",
|
||||
"label": "Manufacturer Part Number",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "is_fixed_asset",
|
||||
"fetch_from": "item_code.asset_category",
|
||||
"fieldname": "asset_category",
|
||||
"fieldtype": "Data",
|
||||
"in_preview": 1,
|
||||
"label": "Asset Category",
|
||||
"options": "Asset Category",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-06-02 06:36:17.078419",
|
||||
"links": [],
|
||||
"modified": "2019-12-04 12:23:17.046413",
|
||||
"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
|
||||
}
|
||||
@@ -41,6 +41,8 @@ def get_pos_data():
|
||||
items_list = get_items_list(pos_profile, doc.company)
|
||||
customers = get_customers_list(pos_profile)
|
||||
|
||||
doc.plc_conversion_rate = update_plc_conversion_rate(doc, pos_profile)
|
||||
|
||||
return {
|
||||
'doc': doc,
|
||||
'default_customer': pos_profile.get('customer'),
|
||||
@@ -53,7 +55,7 @@ def get_pos_data():
|
||||
'batch_no_data': get_batch_no_data(),
|
||||
'barcode_data': get_barcode_data(items_list),
|
||||
'tax_data': get_item_tax_data(),
|
||||
'price_list_data': get_price_list_data(doc.selling_price_list),
|
||||
'price_list_data': get_price_list_data(doc.selling_price_list, doc.plc_conversion_rate),
|
||||
'customer_wise_price_list': get_customer_wise_price_list(),
|
||||
'bin_data': get_bin_data(pos_profile),
|
||||
'pricing_rules': get_pricing_rule_data(doc),
|
||||
@@ -62,6 +64,15 @@ def get_pos_data():
|
||||
'meta': get_meta()
|
||||
}
|
||||
|
||||
def update_plc_conversion_rate(doc, pos_profile):
|
||||
conversion_rate = 1.0
|
||||
|
||||
price_list_currency = frappe.get_cached_value("Price List", doc.selling_price_list, "currency")
|
||||
if pos_profile.get("currency") != price_list_currency:
|
||||
conversion_rate = get_exchange_rate(price_list_currency,
|
||||
pos_profile.get("currency"), nowdate(), args="for_selling") or 1.0
|
||||
|
||||
return conversion_rate
|
||||
|
||||
def get_meta():
|
||||
doctype_meta = {
|
||||
@@ -228,7 +239,7 @@ def get_contacts(customers):
|
||||
|
||||
for data in customers:
|
||||
contact = frappe.db.sql(""" select email_id, phone, mobile_no from `tabContact`
|
||||
where is_primary_contact =1 and name in
|
||||
where is_primary_contact=1 and name in
|
||||
(select parent from `tabDynamic Link` where link_doctype = 'Customer' and link_name = %s
|
||||
and parenttype = 'Contact')""", data.name, as_dict=1)
|
||||
if contact:
|
||||
@@ -307,7 +318,7 @@ def get_item_tax_data():
|
||||
# example: {'Consulting Services': {'Excise 12 - TS': '12.000'}}
|
||||
|
||||
itemwise_tax = {}
|
||||
taxes = frappe.db.sql(""" select parent, tax_type, tax_rate from `tabItem Tax`""", as_dict=1)
|
||||
taxes = frappe.db.sql(""" select parent, tax_type, tax_rate from `tabItem Tax Template Detail`""", as_dict=1)
|
||||
|
||||
for tax in taxes:
|
||||
if tax.parent not in itemwise_tax:
|
||||
@@ -317,14 +328,14 @@ def get_item_tax_data():
|
||||
return itemwise_tax
|
||||
|
||||
|
||||
def get_price_list_data(selling_price_list):
|
||||
def get_price_list_data(selling_price_list, conversion_rate):
|
||||
itemwise_price_list = {}
|
||||
price_lists = frappe.db.sql("""Select ifnull(price_list_rate, 0) as price_list_rate,
|
||||
item_code from `tabItem Price` ip where price_list = %(price_list)s""",
|
||||
{'price_list': selling_price_list}, as_dict=1)
|
||||
|
||||
for item in price_lists:
|
||||
itemwise_price_list[item.item_code] = item.price_list_rate
|
||||
itemwise_price_list[item.item_code] = item.price_list_rate * conversion_rate
|
||||
|
||||
return itemwise_price_list
|
||||
|
||||
@@ -346,14 +357,11 @@ def get_customer_wise_price_list():
|
||||
|
||||
def get_bin_data(pos_profile):
|
||||
itemwise_bin_data = {}
|
||||
cond = "1=1"
|
||||
filters = { 'actual_qty': ['>', 0] }
|
||||
if pos_profile.get('warehouse'):
|
||||
cond = "warehouse = %(warehouse)s"
|
||||
filters.update({ 'warehouse': pos_profile.get('warehouse') })
|
||||
|
||||
bin_data = frappe.db.sql(""" select item_code, warehouse, actual_qty from `tabBin`
|
||||
where actual_qty > 0 and {cond}""".format(cond=cond), {
|
||||
'warehouse': frappe.db.escape(pos_profile.get('warehouse'))
|
||||
}, as_dict=1)
|
||||
bin_data = frappe.db.get_all('Bin', fields = ['item_code', 'warehouse', 'actual_qty'], filters=filters)
|
||||
|
||||
for bins in bin_data:
|
||||
if bins.item_code not in itemwise_bin_data:
|
||||
@@ -391,14 +399,21 @@ def make_invoice(doc_list={}, email_queue_list={}, customers_list={}):
|
||||
for docs in doc_list:
|
||||
for name, doc in iteritems(docs):
|
||||
if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
|
||||
validate_records(doc)
|
||||
si_doc = frappe.new_doc('Sales Invoice')
|
||||
si_doc.offline_pos_name = name
|
||||
si_doc.update(doc)
|
||||
si_doc.set_posting_time = 1
|
||||
si_doc.customer = get_customer_id(doc)
|
||||
si_doc.due_date = doc.get('posting_date')
|
||||
name_list = submit_invoice(si_doc, name, doc, name_list)
|
||||
if isinstance(doc, dict):
|
||||
validate_records(doc)
|
||||
si_doc = frappe.new_doc('Sales Invoice')
|
||||
si_doc.offline_pos_name = name
|
||||
si_doc.update(doc)
|
||||
si_doc.set_posting_time = 1
|
||||
si_doc.customer = get_customer_id(doc)
|
||||
si_doc.due_date = doc.get('posting_date')
|
||||
name_list = submit_invoice(si_doc, name, doc, name_list)
|
||||
else:
|
||||
doc.due_date = doc.get('posting_date')
|
||||
doc.customer = get_customer_id(doc)
|
||||
doc.set_posting_time = 1
|
||||
doc.offline_pos_name = name
|
||||
name_list = submit_invoice(doc, name, doc, name_list)
|
||||
else:
|
||||
name_list.append(name)
|
||||
|
||||
@@ -432,7 +447,6 @@ def get_customer_id(doc, customer=None):
|
||||
|
||||
return cust_id
|
||||
|
||||
|
||||
def make_customer_and_address(customers):
|
||||
customers_list = []
|
||||
for customer, data in iteritems(customers):
|
||||
@@ -449,7 +463,6 @@ def make_customer_and_address(customers):
|
||||
frappe.db.commit()
|
||||
return customers_list
|
||||
|
||||
|
||||
def add_customer(data):
|
||||
customer = data.get('full_name') or data.get('customer')
|
||||
if frappe.db.exists("Customer", customer.strip()):
|
||||
@@ -466,21 +479,18 @@ def add_customer(data):
|
||||
frappe.db.commit()
|
||||
return customer_doc.name
|
||||
|
||||
|
||||
def get_territory(data):
|
||||
if data.get('territory'):
|
||||
return data.get('territory')
|
||||
|
||||
return frappe.db.get_single_value('Selling Settings','territory') or _('All Territories')
|
||||
|
||||
|
||||
def get_customer_group(data):
|
||||
if data.get('customer_group'):
|
||||
return data.get('customer_group')
|
||||
|
||||
return frappe.db.get_single_value('Selling Settings', 'customer_group') or frappe.db.get_value('Customer Group', {'is_group': 0}, 'name')
|
||||
|
||||
|
||||
def make_contact(args, customer):
|
||||
if args.get('email_id') or args.get('phone'):
|
||||
name = frappe.db.get_value('Dynamic Link',
|
||||
@@ -506,7 +516,6 @@ def make_contact(args, customer):
|
||||
doc.flags.ignore_mandatory = True
|
||||
doc.save(ignore_permissions=True)
|
||||
|
||||
|
||||
def make_address(args, customer):
|
||||
if not args.get('address_line1'):
|
||||
return
|
||||
@@ -521,7 +530,10 @@ def make_address(args, customer):
|
||||
address = frappe.get_doc('Address', name)
|
||||
else:
|
||||
address = frappe.new_doc('Address')
|
||||
address.country = frappe.get_cached_value('Company', args.get('company'), 'country')
|
||||
if args.get('company'):
|
||||
address.country = frappe.get_cached_value('Company',
|
||||
args.get('company'), 'country')
|
||||
|
||||
address.append('links', {
|
||||
'link_doctype': 'Customer',
|
||||
'link_name': customer
|
||||
@@ -533,14 +545,17 @@ def make_address(args, customer):
|
||||
address.flags.ignore_mandatory = True
|
||||
address.save(ignore_permissions=True)
|
||||
|
||||
|
||||
def make_email_queue(email_queue):
|
||||
name_list = []
|
||||
|
||||
for key, data in iteritems(email_queue):
|
||||
name = frappe.db.get_value('Sales Invoice', {'offline_pos_name': key}, 'name')
|
||||
if not name: continue
|
||||
|
||||
data = json.loads(data)
|
||||
sender = frappe.session.user
|
||||
print_format = "POS Invoice" if not cint(frappe.db.get_value('Print Format', 'POS Invoice', 'disabled')) else None
|
||||
|
||||
attachments = [frappe.attach_print('Sales Invoice', name, print_format=print_format)]
|
||||
|
||||
make(subject=data.get('subject'), content=data.get('content'), recipients=data.get('recipients'),
|
||||
@@ -550,7 +565,6 @@ def make_email_queue(email_queue):
|
||||
|
||||
return name_list
|
||||
|
||||
|
||||
def validate_item(doc):
|
||||
for item in doc.get('items'):
|
||||
if not frappe.db.exists('Item', item.get('item_code')):
|
||||
@@ -569,7 +583,6 @@ def validate_item(doc):
|
||||
item_doc.save(ignore_permissions=True)
|
||||
frappe.db.commit()
|
||||
|
||||
|
||||
def submit_invoice(si_doc, name, doc, name_list):
|
||||
try:
|
||||
si_doc.insert()
|
||||
@@ -585,7 +598,6 @@ def submit_invoice(si_doc, name, doc, name_list):
|
||||
|
||||
return name_list
|
||||
|
||||
|
||||
def save_invoice(doc, name, name_list):
|
||||
try:
|
||||
if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
|
||||
this.frm.toggle_reqd("due_date", !this.frm.doc.is_return);
|
||||
|
||||
if (this.frm.doc.is_return) {
|
||||
this.frm.return_print_format = "Sales Invoice Return";
|
||||
}
|
||||
|
||||
this.show_general_ledger();
|
||||
|
||||
if(doc.update_stock) this.show_stock_ledger();
|
||||
@@ -148,16 +152,24 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
},
|
||||
|
||||
set_default_print_format: function() {
|
||||
// set default print format to POS type
|
||||
// set default print format to POS type or Credit Note
|
||||
if(cur_frm.doc.is_pos) {
|
||||
if(cur_frm.pos_print_format) {
|
||||
cur_frm.meta._default_print_format = cur_frm.meta.default_print_format;
|
||||
cur_frm.meta.default_print_format = cur_frm.pos_print_format;
|
||||
}
|
||||
} else if(cur_frm.doc.is_return && !cur_frm.meta.default_print_format) {
|
||||
if(cur_frm.return_print_format) {
|
||||
cur_frm.meta._default_print_format = cur_frm.meta.default_print_format;
|
||||
cur_frm.meta.default_print_format = cur_frm.return_print_format;
|
||||
}
|
||||
} else {
|
||||
if(cur_frm.meta._default_print_format) {
|
||||
cur_frm.meta.default_print_format = cur_frm.meta._default_print_format;
|
||||
cur_frm.meta._default_print_format = null;
|
||||
} else if(in_list([cur_frm.pos_print_format, cur_frm.return_print_format], cur_frm.meta.default_print_format)) {
|
||||
cur_frm.meta.default_print_format = null;
|
||||
cur_frm.meta._default_print_format = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -544,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
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -685,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)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -78,6 +78,7 @@ class SalesInvoice(SellingController):
|
||||
self.so_dn_required()
|
||||
|
||||
self.validate_proj_cust()
|
||||
self.validate_pos_return()
|
||||
self.validate_with_previous_doc()
|
||||
self.validate_uom_is_integer("stock_uom", "stock_qty")
|
||||
self.validate_uom_is_integer("uom", "qty")
|
||||
@@ -135,6 +136,16 @@ class SalesInvoice(SellingController):
|
||||
if self.redeem_loyalty_points and self.loyalty_program and self.loyalty_points:
|
||||
validate_loyalty_points(self, self.loyalty_points)
|
||||
|
||||
def validate_fixed_asset(self):
|
||||
for d in self.get("items"):
|
||||
if d.is_fixed_asset and d.meta.get_field("asset") and d.asset:
|
||||
asset = frappe.get_doc("Asset", d.asset)
|
||||
if self.doctype == "Sales Invoice" and self.docstatus == 1:
|
||||
if self.update_stock:
|
||||
frappe.throw(_("'Update Stock' cannot be checked for fixed asset sale"))
|
||||
|
||||
elif asset.status in ("Scrapped", "Cancelled", "Sold"):
|
||||
frappe.throw(_("Row #{0}: Asset {1} cannot be submitted, it is already {2}").format(d.idx, d.asset, asset.status))
|
||||
|
||||
def before_save(self):
|
||||
set_account_for_mode_of_payment(self)
|
||||
@@ -199,6 +210,16 @@ class SalesInvoice(SellingController):
|
||||
if "Healthcare" in active_domains:
|
||||
manage_invoice_submit_cancel(self, "on_submit")
|
||||
|
||||
def validate_pos_return(self):
|
||||
|
||||
if self.is_pos and self.is_return:
|
||||
total_amount_in_payments = 0
|
||||
for payment in self.payments:
|
||||
total_amount_in_payments += payment.amount
|
||||
invoice_total = self.rounded_total or self.grand_total
|
||||
if total_amount_in_payments < invoice_total:
|
||||
frappe.throw(_("Total payments amount can't be greater than {}".format(-invoice_total)))
|
||||
|
||||
def validate_pos_paid_amount(self):
|
||||
if len(self.payments) == 0 and self.is_pos:
|
||||
frappe.throw(_("At least one mode of payment is required for POS invoice."))
|
||||
@@ -293,8 +314,10 @@ class SalesInvoice(SellingController):
|
||||
from erpnext.selling.doctype.customer.customer import check_credit_limit
|
||||
|
||||
validate_against_credit_limit = False
|
||||
bypass_credit_limit_check_at_sales_order = cint(frappe.get_cached_value("Customer", self.customer,
|
||||
"bypass_credit_limit_check_at_sales_order"))
|
||||
bypass_credit_limit_check_at_sales_order = frappe.db.get_value("Customer Credit Limit",
|
||||
filters={'parent': self.customer, 'parenttype': 'Customer', 'company': self.company},
|
||||
fieldname=["bypass_credit_limit_check"])
|
||||
|
||||
if bypass_credit_limit_check_at_sales_order:
|
||||
validate_against_credit_limit = True
|
||||
|
||||
@@ -673,7 +696,6 @@ class SalesInvoice(SellingController):
|
||||
|
||||
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
|
||||
auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
|
||||
|
||||
if not gl_entries:
|
||||
gl_entries = self.get_gl_entries()
|
||||
|
||||
@@ -685,7 +707,7 @@ class SalesInvoice(SellingController):
|
||||
cint(self.redeem_loyalty_points)) else "Yes"
|
||||
|
||||
make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
|
||||
update_outstanding=update_outstanding, merge_entries=False)
|
||||
update_outstanding=update_outstanding, merge_entries=False, from_repost=from_repost)
|
||||
|
||||
if update_outstanding == "No":
|
||||
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
||||
@@ -931,7 +953,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)
|
||||
|
||||
@@ -979,10 +1001,8 @@ class SalesInvoice(SellingController):
|
||||
continue
|
||||
|
||||
for serial_no in item.serial_no.split("\n"):
|
||||
if serial_no and frappe.db.exists('Serial No', serial_no):
|
||||
sno = frappe.get_doc('Serial No', serial_no)
|
||||
sno.sales_invoice = invoice
|
||||
sno.db_update()
|
||||
if serial_no and frappe.db.get_value('Serial No', serial_no, 'item_code') == item.item_code:
|
||||
frappe.db.set_value('Serial No', serial_no, 'sales_invoice', invoice)
|
||||
|
||||
def validate_serial_numbers(self):
|
||||
"""
|
||||
@@ -1028,12 +1048,18 @@ class SalesInvoice(SellingController):
|
||||
continue
|
||||
|
||||
for serial_no in item.serial_no.split("\n"):
|
||||
sales_invoice = frappe.db.get_value("Serial No", serial_no, "sales_invoice")
|
||||
if sales_invoice 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:
|
||||
@@ -1218,7 +1244,8 @@ class SalesInvoice(SellingController):
|
||||
self.status = "Unpaid and Discounted"
|
||||
elif flt(self.outstanding_amount) > 0 and getdate(self.due_date) >= getdate(nowdate()):
|
||||
self.status = "Unpaid"
|
||||
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}):
|
||||
#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}):
|
||||
self.status = "Credit Note Issued"
|
||||
elif self.is_return == 1:
|
||||
self.status = "Return"
|
||||
@@ -1499,4 +1526,4 @@ def create_invoice_discounting(source_name, target_doc=None):
|
||||
"outstanding_amount": invoice.outstanding_amount
|
||||
})
|
||||
|
||||
return invoice_discounting
|
||||
return invoice_discounting
|
||||
|
||||
@@ -68,8 +68,6 @@
|
||||
"selling_price_list": "_Test Price List",
|
||||
"territory": "_Test Territory"
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"company": "_Test Company",
|
||||
"conversion_rate": 1.0,
|
||||
@@ -276,7 +274,6 @@
|
||||
"uom": "_Test UOM 1",
|
||||
"conversion_factor": 1,
|
||||
"stock_uom": "_Test UOM 1"
|
||||
|
||||
},
|
||||
{
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
|
||||
@@ -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
|
||||
@@ -20,6 +20,9 @@ from erpnext.stock.doctype.item.test_item import create_item
|
||||
from six import iteritems
|
||||
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction
|
||||
from erpnext.regional.india.utils import get_ewb_data
|
||||
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
|
||||
|
||||
class TestSalesInvoice(unittest.TestCase):
|
||||
def make(self):
|
||||
@@ -29,10 +32,12 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
w.submit()
|
||||
return w
|
||||
|
||||
def setUp(self):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
unlink_payment_on_cancel_of_invoice()
|
||||
|
||||
def tearDown(self):
|
||||
@classmethod
|
||||
def tearDownClass(self):
|
||||
unlink_payment_on_cancel_of_invoice(0)
|
||||
|
||||
def test_timestamp_change(self):
|
||||
@@ -135,6 +140,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
unlink_payment_on_cancel_of_invoice(0)
|
||||
si = frappe.get_doc('Sales Invoice', si.name)
|
||||
self.assertRaises(frappe.LinkExistsError, si.cancel)
|
||||
unlink_payment_on_cancel_of_invoice()
|
||||
|
||||
def test_sales_invoice_calculation_export_currency(self):
|
||||
si = frappe.copy_doc(test_records[2])
|
||||
@@ -547,7 +553,6 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
si.get("taxes")[6].tax_amount = 2
|
||||
|
||||
si.insert()
|
||||
print(si.name)
|
||||
|
||||
expected_values = [
|
||||
{
|
||||
@@ -676,56 +681,67 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
self.assertFalse(gle)
|
||||
|
||||
def test_pos_gl_entry_with_perpetual_inventory(self):
|
||||
set_perpetual_inventory()
|
||||
make_pos_profile()
|
||||
|
||||
self._insert_purchase_receipt()
|
||||
pos = copy.deepcopy(test_records[1])
|
||||
pos["is_pos"] = 1
|
||||
pos["update_stock"] = 1
|
||||
pos["payments"] = [{'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 300},
|
||||
{'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 300}]
|
||||
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)
|
||||
|
||||
pos.is_pos = 1
|
||||
pos.update_stock = 1
|
||||
|
||||
pos.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - TCP1', 'amount': 50})
|
||||
pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - TCP1', 'amount': 50})
|
||||
|
||||
taxes = get_taxes_and_charges()
|
||||
pos.taxes = []
|
||||
for tax in taxes:
|
||||
pos.append("taxes", tax)
|
||||
|
||||
si = frappe.copy_doc(pos)
|
||||
si.insert()
|
||||
si.submit()
|
||||
self.assertEqual(si.paid_amount, 100.0)
|
||||
|
||||
self.assertEqual(si.paid_amount, 600.0)
|
||||
|
||||
self.pos_gl_entry(si, pos, 300)
|
||||
self.pos_gl_entry(si, pos, 50)
|
||||
|
||||
def test_pos_change_amount(self):
|
||||
set_perpetual_inventory()
|
||||
make_pos_profile()
|
||||
|
||||
self._insert_purchase_receipt()
|
||||
pos = copy.deepcopy(test_records[1])
|
||||
pos["is_pos"] = 1
|
||||
pos["update_stock"] = 1
|
||||
pos["payments"] = [{'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 300},
|
||||
{'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 340}]
|
||||
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")
|
||||
|
||||
si = frappe.copy_doc(pos)
|
||||
si.change_amount = 5.0
|
||||
si.insert()
|
||||
si.submit()
|
||||
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)
|
||||
|
||||
self.assertEqual(si.grand_total, 630.0)
|
||||
self.assertEqual(si.write_off_amount, -5)
|
||||
pos.is_pos = 1
|
||||
pos.update_stock = 1
|
||||
|
||||
pos.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - TCP1', 'amount': 50})
|
||||
pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - TCP1', 'amount': 60})
|
||||
|
||||
pos.change_amount = 5.0
|
||||
pos.insert()
|
||||
pos.submit()
|
||||
|
||||
self.assertEqual(pos.grand_total, 100.0)
|
||||
self.assertEqual(pos.write_off_amount, -5)
|
||||
|
||||
def test_make_pos_invoice(self):
|
||||
from erpnext.accounts.doctype.sales_invoice.pos import make_invoice
|
||||
|
||||
set_perpetual_inventory()
|
||||
|
||||
make_pos_profile()
|
||||
self._insert_purchase_receipt()
|
||||
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)
|
||||
|
||||
pos = copy.deepcopy(test_records[1])
|
||||
pos["is_pos"] = 1
|
||||
pos["update_stock"] = 1
|
||||
pos["payments"] = [{'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 300},
|
||||
{'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 330}]
|
||||
pos.is_pos = 1
|
||||
pos.update_stock = 1
|
||||
|
||||
pos.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - TCP1', 'amount': 50})
|
||||
pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - TCP1', 'amount': 50})
|
||||
|
||||
taxes = get_taxes_and_charges()
|
||||
pos.taxes = []
|
||||
for tax in taxes:
|
||||
pos.append("taxes", tax)
|
||||
|
||||
invoice_data = [{'09052016142': pos}]
|
||||
si = make_invoice(invoice_data).get('invoice')
|
||||
@@ -733,16 +749,15 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
|
||||
sales_invoice = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': '09052016142', 'docstatus': 1})
|
||||
si = frappe.get_doc('Sales Invoice', sales_invoice[0].name)
|
||||
self.assertEqual(si.grand_total, 630.0)
|
||||
|
||||
self.pos_gl_entry(si, pos, 330)
|
||||
self.assertEqual(si.grand_total, 100)
|
||||
|
||||
self.pos_gl_entry(si, pos, 50)
|
||||
|
||||
def test_make_pos_invoice_in_draft(self):
|
||||
from erpnext.accounts.doctype.sales_invoice.pos import make_invoice
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
|
||||
set_perpetual_inventory()
|
||||
|
||||
allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock')
|
||||
if allow_negative_stock:
|
||||
frappe.db.set_value('Stock Settings', None, 'allow_negative_stock', 0)
|
||||
@@ -786,7 +801,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
si.name, as_dict=1)[0]
|
||||
self.assertTrue(sle)
|
||||
self.assertEqual([sle.item_code, sle.warehouse, sle.actual_qty],
|
||||
["_Test Item", "_Test Warehouse - _TC", -1.0])
|
||||
['_Test FG Item', 'Stores - TCP1', -1.0])
|
||||
|
||||
# check gl entries
|
||||
gl_entries = frappe.db.sql("""select account, debit, credit
|
||||
@@ -794,19 +809,19 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
order by account asc, debit asc, credit asc""", si.name, as_dict=1)
|
||||
self.assertTrue(gl_entries)
|
||||
|
||||
stock_in_hand = get_inventory_account('_Test Company')
|
||||
|
||||
stock_in_hand = get_inventory_account('_Test Company with perpetual inventory')
|
||||
expected_gl_entries = sorted([
|
||||
[si.debit_to, 630.0, 0.0],
|
||||
[pos["items"][0]["income_account"], 0.0, 500.0],
|
||||
[pos["taxes"][0]["account_head"], 0.0, 80.0],
|
||||
[pos["taxes"][1]["account_head"], 0.0, 50.0],
|
||||
[si.debit_to, 100.0, 0.0],
|
||||
[pos.items[0].income_account, 0.0, 89.09],
|
||||
['Round Off - TCP1', 0.0, 0.01],
|
||||
[pos.taxes[0].account_head, 0.0, 10.69],
|
||||
[pos.taxes[1].account_head, 0.0, 0.21],
|
||||
[stock_in_hand, 0.0, abs(sle.stock_value_difference)],
|
||||
[pos["items"][0]["expense_account"], abs(sle.stock_value_difference), 0.0],
|
||||
[si.debit_to, 0.0, 300.0],
|
||||
[pos.items[0].expense_account, abs(sle.stock_value_difference), 0.0],
|
||||
[si.debit_to, 0.0, 50.0],
|
||||
[si.debit_to, 0.0, cash_amount],
|
||||
["_Test Bank - _TC", 300.0, 0.0],
|
||||
["Cash - _TC", cash_amount, 0.0]
|
||||
["_Test Bank - TCP1", 50, 0.0],
|
||||
["Cash - TCP1", cash_amount, 0.0]
|
||||
])
|
||||
|
||||
for i, gle in enumerate(sorted(gl_entries, key=lambda gle: gle.account)):
|
||||
@@ -815,15 +830,14 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
self.assertEqual(expected_gl_entries[i][2], gle.credit)
|
||||
|
||||
si.cancel()
|
||||
frappe.delete_doc('Sales Invoice', si.name)
|
||||
gle = frappe.db.sql("""select * from `tabGL Entry`
|
||||
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
|
||||
|
||||
self.assertFalse(gle)
|
||||
|
||||
set_perpetual_inventory(0)
|
||||
|
||||
frappe.db.sql("delete from `tabPOS Profile`")
|
||||
si.delete()
|
||||
|
||||
def test_pos_si_without_payment(self):
|
||||
set_perpetual_inventory()
|
||||
@@ -1006,7 +1020,6 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"""
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
|
||||
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
|
||||
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
|
||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||
|
||||
se = make_serialized_item()
|
||||
@@ -1021,14 +1034,17 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
self.assertEqual(si.get("items")[0].serial_no, dn.get("items")[0].serial_no)
|
||||
|
||||
def test_return_sales_invoice(self):
|
||||
set_perpetual_inventory()
|
||||
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
|
||||
make_stock_entry(item_code="_Test Item", target="Stores - TCP1", qty=50, basic_rate=100)
|
||||
|
||||
actual_qty_0 = get_qty_after_transaction()
|
||||
actual_qty_0 = get_qty_after_transaction(item_code = "_Test Item", warehouse = "Stores - TCP1")
|
||||
|
||||
si = create_sales_invoice(qty=5, rate=500, update_stock=1)
|
||||
si = create_sales_invoice(qty = 5, rate=500, update_stock=1, company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1")
|
||||
|
||||
|
||||
actual_qty_1 = get_qty_after_transaction(item_code = "_Test Item", warehouse = "Stores - TCP1")
|
||||
|
||||
frappe.db.commit()
|
||||
|
||||
actual_qty_1 = get_qty_after_transaction()
|
||||
self.assertEqual(actual_qty_0 - 5, actual_qty_1)
|
||||
|
||||
# outgoing_rate
|
||||
@@ -1036,10 +1052,9 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"voucher_no": si.name}, "stock_value_difference") / 5
|
||||
|
||||
# return entry
|
||||
si1 = create_sales_invoice(is_return=1, return_against=si.name, qty=-2, rate=500, update_stock=1)
|
||||
|
||||
actual_qty_2 = get_qty_after_transaction()
|
||||
si1 = create_sales_invoice(is_return=1, return_against=si.name, qty=-2, rate=500, update_stock=1, company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1")
|
||||
|
||||
actual_qty_2 = get_qty_after_transaction(item_code = "_Test Item", warehouse = "Stores - TCP1")
|
||||
self.assertEqual(actual_qty_1 + 2, actual_qty_2)
|
||||
|
||||
incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
|
||||
@@ -1047,7 +1062,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
["incoming_rate", "stock_value_difference"])
|
||||
|
||||
self.assertEqual(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
|
||||
stock_in_hand_account = get_inventory_account('_Test Company', si1.items[0].warehouse)
|
||||
stock_in_hand_account = get_inventory_account('_Test Company with perpetual inventory', si1.items[0].warehouse)
|
||||
|
||||
# Check gl entry
|
||||
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice",
|
||||
@@ -1056,7 +1071,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
self.assertEqual(gle_warehouse_amount, stock_value_difference)
|
||||
|
||||
party_credited = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice",
|
||||
"voucher_no": si1.name, "account": "Debtors - _TC", "party": "_Test Customer"}, "credit")
|
||||
"voucher_no": si1.name, "account": "Debtors - TCP1", "party": "_Test Customer"}, "credit")
|
||||
|
||||
self.assertEqual(party_credited, 1000)
|
||||
|
||||
@@ -1064,7 +1079,6 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
self.assertFalse(si1.outstanding_amount)
|
||||
self.assertEqual(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"), 1500)
|
||||
|
||||
set_perpetual_inventory(0)
|
||||
|
||||
def test_discount_on_net_total(self):
|
||||
si = frappe.copy_doc(test_records[2])
|
||||
@@ -1522,6 +1536,8 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
self.assertEqual(si.total_taxes_and_charges, 577.05)
|
||||
self.assertEqual(si.grand_total, 1827.05)
|
||||
|
||||
|
||||
|
||||
def test_create_invoice_without_terms(self):
|
||||
si = create_sales_invoice(do_not_save=1)
|
||||
self.assertFalse(si.get('payment_schedule'))
|
||||
@@ -1831,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")
|
||||
@@ -1928,4 +1964,29 @@ def get_outstanding_amount(against_voucher_type, against_voucher, account, party
|
||||
if against_voucher_type == 'Purchase Invoice':
|
||||
bal = bal * -1
|
||||
|
||||
return bal
|
||||
return bal
|
||||
|
||||
def get_taxes_and_charges():
|
||||
return [{
|
||||
"account_head": "_Test Account Excise Duty - TCP1",
|
||||
"charge_type": "On Net Total",
|
||||
"cost_center": "Main - TCP1",
|
||||
"description": "Excise Duty",
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"idx": 1,
|
||||
"included_in_print_rate": 1,
|
||||
"parentfield": "taxes",
|
||||
"rate": 12
|
||||
},
|
||||
{
|
||||
"account_head": "_Test Account Education Cess - TCP1",
|
||||
"charge_type": "On Previous Row Amount",
|
||||
"cost_center": "Main - TCP1",
|
||||
"description": "Education Cess",
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"idx": 2,
|
||||
"included_in_print_rate": 1,
|
||||
"parentfield": "taxes",
|
||||
"rate": 2,
|
||||
"row_id": 1
|
||||
}]
|
||||
@@ -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,
|
||||
@@ -764,6 +768,7 @@
|
||||
"label": "Image"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "accounting_dimensions_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Accounting Dimensions"
|
||||
@@ -782,7 +787,8 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-06-28 17:30:12.156086",
|
||||
"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
|
||||
}
|
||||
@@ -16,11 +16,13 @@ frappe.ui.form.on('Share Transfer', {
|
||||
};
|
||||
};
|
||||
});
|
||||
if (frm.doc.docstatus == 1) {
|
||||
if (frm.doc.docstatus == 1 && frm.doc.equity_or_liability_account && frm.doc.asset_account) {
|
||||
frm.add_custom_button(__('Create Journal Entry'), function () {
|
||||
erpnext.share_transfer.make_jv(frm);
|
||||
});
|
||||
}
|
||||
|
||||
frm.toggle_reqd("asset_account", frm.doc.transfer_type != "Transfer");
|
||||
},
|
||||
no_of_shares: (frm) => {
|
||||
if (frm.doc.rate != undefined || frm.doc.rate != null){
|
||||
@@ -56,6 +58,10 @@ frappe.ui.form.on('Share Transfer', {
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
transfer_type: function(frm) {
|
||||
frm.toggle_reqd("asset_account", frm.doc.transfer_type != "Transfer");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,9 +13,9 @@ from frappe.utils import nowdate
|
||||
class ShareDontExists(ValidationError): pass
|
||||
|
||||
class ShareTransfer(Document):
|
||||
def before_submit(self):
|
||||
def on_submit(self):
|
||||
if self.transfer_type == 'Issue':
|
||||
shareholder = self.get_shareholder_doc(self.company)
|
||||
shareholder = self.get_company_shareholder()
|
||||
shareholder.append('share_balance', {
|
||||
'share_type': self.share_type,
|
||||
'from_no': self.from_no,
|
||||
@@ -28,7 +28,7 @@ class ShareTransfer(Document):
|
||||
})
|
||||
shareholder.save()
|
||||
|
||||
doc = frappe.get_doc('Shareholder', self.to_shareholder)
|
||||
doc = self.get_shareholder_doc(self.to_shareholder)
|
||||
doc.append('share_balance', {
|
||||
'share_type': self.share_type,
|
||||
'from_no': self.from_no,
|
||||
@@ -41,11 +41,11 @@ class ShareTransfer(Document):
|
||||
|
||||
elif self.transfer_type == 'Purchase':
|
||||
self.remove_shares(self.from_shareholder)
|
||||
self.remove_shares(self.get_shareholder_doc(self.company).name)
|
||||
self.remove_shares(self.get_company_shareholder().name)
|
||||
|
||||
elif self.transfer_type == 'Transfer':
|
||||
self.remove_shares(self.from_shareholder)
|
||||
doc = frappe.get_doc('Shareholder', self.to_shareholder)
|
||||
doc = self.get_shareholder_doc(self.to_shareholder)
|
||||
doc.append('share_balance', {
|
||||
'share_type': self.share_type,
|
||||
'from_no': self.from_no,
|
||||
@@ -56,137 +56,127 @@ class ShareTransfer(Document):
|
||||
})
|
||||
doc.save()
|
||||
|
||||
def on_cancel(self):
|
||||
if self.transfer_type == 'Issue':
|
||||
compnay_shareholder = self.get_company_shareholder()
|
||||
self.remove_shares(compnay_shareholder.name)
|
||||
self.remove_shares(self.to_shareholder)
|
||||
|
||||
elif self.transfer_type == 'Purchase':
|
||||
compnay_shareholder = self.get_company_shareholder()
|
||||
from_shareholder = self.get_shareholder_doc(self.from_shareholder)
|
||||
|
||||
from_shareholder.append('share_balance', {
|
||||
'share_type': self.share_type,
|
||||
'from_no': self.from_no,
|
||||
'to_no': self.to_no,
|
||||
'rate': self.rate,
|
||||
'amount': self.amount,
|
||||
'no_of_shares': self.no_of_shares
|
||||
})
|
||||
|
||||
from_shareholder.save()
|
||||
|
||||
compnay_shareholder.append('share_balance', {
|
||||
'share_type': self.share_type,
|
||||
'from_no': self.from_no,
|
||||
'to_no': self.to_no,
|
||||
'rate': self.rate,
|
||||
'amount': self.amount,
|
||||
'no_of_shares': self.no_of_shares
|
||||
})
|
||||
|
||||
compnay_shareholder.save()
|
||||
|
||||
elif self.transfer_type == 'Transfer':
|
||||
self.remove_shares(self.to_shareholder)
|
||||
from_shareholder = self.get_shareholder_doc(self.from_shareholder)
|
||||
from_shareholder.append('share_balance', {
|
||||
'share_type': self.share_type,
|
||||
'from_no': self.from_no,
|
||||
'to_no': self.to_no,
|
||||
'rate': self.rate,
|
||||
'amount': self.amount,
|
||||
'no_of_shares': self.no_of_shares
|
||||
})
|
||||
from_shareholder.save()
|
||||
|
||||
def validate(self):
|
||||
self.get_company_shareholder()
|
||||
self.basic_validations()
|
||||
self.folio_no_validation()
|
||||
|
||||
if self.transfer_type == 'Issue':
|
||||
if not self.get_shareholder_doc(self.company):
|
||||
shareholder = frappe.get_doc({
|
||||
'doctype': 'Shareholder',
|
||||
'title': self.company,
|
||||
'company': self.company,
|
||||
'is_company': 1
|
||||
})
|
||||
shareholder.insert()
|
||||
# validate share doesnt exist in company
|
||||
ret_val = self.share_exists(self.get_shareholder_doc(self.company).name)
|
||||
if ret_val != False:
|
||||
# validate share doesn't exist in company
|
||||
ret_val = self.share_exists(self.get_company_shareholder().name)
|
||||
if ret_val in ('Complete', 'Partial'):
|
||||
frappe.throw(_('The shares already exist'), frappe.DuplicateEntryError)
|
||||
else:
|
||||
# validate share exists with from_shareholder
|
||||
ret_val = self.share_exists(self.from_shareholder)
|
||||
if ret_val != True:
|
||||
if ret_val in ('Outside', 'Partial'):
|
||||
frappe.throw(_("The shares don't exist with the {0}")
|
||||
.format(self.from_shareholder), ShareDontExists)
|
||||
|
||||
def basic_validations(self):
|
||||
if self.transfer_type == 'Purchase':
|
||||
self.to_shareholder = ''
|
||||
if self.from_shareholder is None or self.from_shareholder is '':
|
||||
if not self.from_shareholder:
|
||||
frappe.throw(_('The field From Shareholder cannot be blank'))
|
||||
if self.from_folio_no is None or self.from_folio_no is '':
|
||||
if not self.from_folio_no:
|
||||
self.to_folio_no = self.autoname_folio(self.to_shareholder)
|
||||
if not self.asset_account:
|
||||
frappe.throw(_('The field Asset Account cannot be blank'))
|
||||
elif (self.transfer_type == 'Issue'):
|
||||
self.from_shareholder = ''
|
||||
if self.to_shareholder is None or self.to_shareholder == '':
|
||||
if not self.to_shareholder:
|
||||
frappe.throw(_('The field To Shareholder cannot be blank'))
|
||||
if self.to_folio_no is None or self.to_folio_no is '':
|
||||
if not self.to_folio_no:
|
||||
self.to_folio_no = self.autoname_folio(self.to_shareholder)
|
||||
if not self.asset_account:
|
||||
frappe.throw(_('The field Asset Account cannot be blank'))
|
||||
else:
|
||||
if self.from_shareholder is None or self.to_shareholder is None:
|
||||
if not self.from_shareholder or not self.to_shareholder:
|
||||
frappe.throw(_('The fields From Shareholder and To Shareholder cannot be blank'))
|
||||
if self.to_folio_no is None or self.to_folio_no is '':
|
||||
if not self.to_folio_no:
|
||||
self.to_folio_no = self.autoname_folio(self.to_shareholder)
|
||||
if not self.equity_or_liability_account:
|
||||
frappe.throw(_('The field Equity/Liability Account cannot be blank'))
|
||||
if self.from_shareholder == self.to_shareholder:
|
||||
frappe.throw(_('The seller and the buyer cannot be the same'))
|
||||
if self.no_of_shares != self.to_no - self.from_no + 1:
|
||||
frappe.throw(_('The number of shares and the share numbers are inconsistent'))
|
||||
if self.amount is None:
|
||||
if not self.amount:
|
||||
self.amount = self.rate * self.no_of_shares
|
||||
if self.amount != self.rate * self.no_of_shares:
|
||||
frappe.throw(_('There are inconsistencies between the rate, no of shares and the amount calculated'))
|
||||
|
||||
def share_exists(self, shareholder):
|
||||
# return True if exits,
|
||||
# False if completely doesn't exist,
|
||||
# 'partially exists' if partailly doesn't exist
|
||||
ret_val = self.recursive_share_check(shareholder, self.share_type,
|
||||
query = {
|
||||
'from_no': self.from_no,
|
||||
'to_no': self.to_no
|
||||
}
|
||||
)
|
||||
if all(boolean == True for boolean in ret_val):
|
||||
return True
|
||||
elif True in ret_val:
|
||||
return 'partially exists'
|
||||
else:
|
||||
return False
|
||||
|
||||
def recursive_share_check(self, shareholder, share_type, query):
|
||||
# query = {'from_no': share_starting_no, 'to_no': share_ending_no}
|
||||
# Recursive check if a given part of shares is held by the shareholder
|
||||
# return a list containing True and False
|
||||
# Eg. [True, False, True]
|
||||
# All True implies its completely inside
|
||||
# All False implies its completely outside
|
||||
# A mix implies its partially inside/outside
|
||||
does_share_exist = []
|
||||
doc = frappe.get_doc('Shareholder', shareholder)
|
||||
doc = self.get_shareholder_doc(shareholder)
|
||||
for entry in doc.share_balance:
|
||||
if entry.share_type != share_type or \
|
||||
entry.from_no > query['to_no'] or \
|
||||
entry.to_no < query['from_no']:
|
||||
if entry.share_type != self.share_type or \
|
||||
entry.from_no > self.to_no or \
|
||||
entry.to_no < self.from_no:
|
||||
continue # since query lies outside bounds
|
||||
elif entry.from_no <= query['from_no'] and entry.to_no >= query['to_no']:
|
||||
return [True] # absolute truth!
|
||||
elif entry.from_no >= query['from_no'] and entry.to_no <= query['to_no']:
|
||||
# split and check
|
||||
does_share_exist.extend(self.recursive_share_check(shareholder,
|
||||
share_type,
|
||||
{
|
||||
'from_no': query['from_no'],
|
||||
'to_no': entry.from_no - 1
|
||||
}
|
||||
))
|
||||
does_share_exist.append(True)
|
||||
does_share_exist.extend(self.recursive_share_check(shareholder,
|
||||
share_type,
|
||||
{
|
||||
'from_no': entry.to_no + 1,
|
||||
'to_no': query['to_no']
|
||||
}
|
||||
))
|
||||
elif query['from_no'] <= entry.from_no <= query['to_no'] and entry.to_no >= query['to_no']:
|
||||
does_share_exist.extend(self.recursive_share_check(shareholder,
|
||||
share_type,
|
||||
{
|
||||
'from_no': query['from_no'],
|
||||
'to_no': entry.from_no - 1
|
||||
}
|
||||
))
|
||||
elif query['from_no'] <= entry.to_no <= query['to_no'] and entry.from_no <= query['from_no']:
|
||||
does_share_exist.extend(self.recursive_share_check(shareholder,
|
||||
share_type,
|
||||
{
|
||||
'from_no': entry.to_no + 1,
|
||||
'to_no': query['to_no']
|
||||
}
|
||||
))
|
||||
elif entry.from_no <= self.from_no and entry.to_no >= self.to_no: #both inside
|
||||
return 'Complete' # absolute truth!
|
||||
elif entry.from_no <= self.from_no <= self.to_no:
|
||||
return 'Partial'
|
||||
elif entry.from_no <= self.to_no <= entry.to_no:
|
||||
return 'Partial'
|
||||
|
||||
does_share_exist.append(False)
|
||||
return does_share_exist
|
||||
return 'Outside'
|
||||
|
||||
def folio_no_validation(self):
|
||||
shareholders = ['from_shareholder', 'to_shareholder']
|
||||
shareholders = [shareholder for shareholder in shareholders if self.get(shareholder) is not '']
|
||||
for shareholder in shareholders:
|
||||
doc = frappe.get_doc('Shareholder', self.get(shareholder))
|
||||
doc = self.get_shareholder_doc(self.get(shareholder))
|
||||
if doc.company != self.company:
|
||||
frappe.throw(_('The shareholder does not belong to this company'))
|
||||
if doc.folio_no is '' or doc.folio_no is None:
|
||||
if not doc.folio_no:
|
||||
doc.folio_no = self.from_folio_no \
|
||||
if (shareholder == 'from_shareholder') else self.to_folio_no;
|
||||
if (shareholder == 'from_shareholder') else self.to_folio_no
|
||||
doc.save()
|
||||
else:
|
||||
if doc.folio_no and doc.folio_no != (self.from_folio_no if (shareholder == 'from_shareholder') else self.to_folio_no):
|
||||
@@ -194,24 +184,14 @@ class ShareTransfer(Document):
|
||||
|
||||
def autoname_folio(self, shareholder, is_company=False):
|
||||
if is_company:
|
||||
doc = self.get_shareholder_doc(shareholder)
|
||||
doc = self.get_company_shareholder()
|
||||
else:
|
||||
doc = frappe.get_doc('Shareholder' , shareholder)
|
||||
doc = self.get_shareholder_doc(shareholder)
|
||||
doc.folio_no = make_autoname('FN.#####')
|
||||
doc.save()
|
||||
return doc.folio_no
|
||||
|
||||
def remove_shares(self, shareholder):
|
||||
self.iterative_share_removal(shareholder, self.share_type,
|
||||
{
|
||||
'from_no': self.from_no,
|
||||
'to_no' : self.to_no
|
||||
},
|
||||
rate = self.rate,
|
||||
amount = self.amount
|
||||
)
|
||||
|
||||
def iterative_share_removal(self, shareholder, share_type, query, rate, amount):
|
||||
# query = {'from_no': share_starting_no, 'to_no': share_ending_no}
|
||||
# Shares exist for sure
|
||||
# Iterate over all entries and modify entry if in entry
|
||||
@@ -221,31 +201,31 @@ class ShareTransfer(Document):
|
||||
|
||||
for entry in current_entries:
|
||||
# use spaceage logic here
|
||||
if entry.share_type != share_type or \
|
||||
entry.from_no > query['to_no'] or \
|
||||
entry.to_no < query['from_no']:
|
||||
if entry.share_type != self.share_type or \
|
||||
entry.from_no > self.to_no or \
|
||||
entry.to_no < self.from_no:
|
||||
new_entries.append(entry)
|
||||
continue # since query lies outside bounds
|
||||
elif entry.from_no <= query['from_no'] and entry.to_no >= query['to_no']:
|
||||
elif entry.from_no <= self.from_no and entry.to_no >= self.to_no:
|
||||
#split
|
||||
if entry.from_no == query['from_no']:
|
||||
if entry.to_no == query['to_no']:
|
||||
if entry.from_no == self.from_no:
|
||||
if entry.to_no == self.to_no:
|
||||
pass #nothing to append
|
||||
else:
|
||||
new_entries.append(self.return_share_balance_entry(query['to_no']+1, entry.to_no, entry.rate))
|
||||
new_entries.append(self.return_share_balance_entry(self.to_no+1, entry.to_no, entry.rate))
|
||||
else:
|
||||
if entry.to_no == query['to_no']:
|
||||
new_entries.append(self.return_share_balance_entry(entry.from_no, query['from_no']-1, entry.rate))
|
||||
if entry.to_no == self.to_no:
|
||||
new_entries.append(self.return_share_balance_entry(entry.from_no, self.from_no-1, entry.rate))
|
||||
else:
|
||||
new_entries.append(self.return_share_balance_entry(entry.from_no, query['from_no']-1, entry.rate))
|
||||
new_entries.append(self.return_share_balance_entry(query['to_no']+1, entry.to_no, entry.rate))
|
||||
elif entry.from_no >= query['from_no'] and entry.to_no <= query['to_no']:
|
||||
new_entries.append(self.return_share_balance_entry(entry.from_no, self.from_no-1, entry.rate))
|
||||
new_entries.append(self.return_share_balance_entry(self.to_no+1, entry.to_no, entry.rate))
|
||||
elif entry.from_no >= self.from_no and entry.to_no <= self.to_no:
|
||||
# split and check
|
||||
pass #nothing to append
|
||||
elif query['from_no'] <= entry.from_no <= query['to_no'] and entry.to_no >= query['to_no']:
|
||||
new_entries.append(self.return_share_balance_entry(query['to_no']+1, entry.to_no, entry.rate))
|
||||
elif query['from_no'] <= entry.to_no <= query['to_no'] and entry.from_no <= query['from_no']:
|
||||
new_entries.append(self.return_share_balance_entry(entry.from_no, query['from_no']-1, entry.rate))
|
||||
elif self.from_no <= entry.from_no <= self.to_no and entry.to_no >= self.to_no:
|
||||
new_entries.append(self.return_share_balance_entry(self.to_no+1, entry.to_no, entry.rate))
|
||||
elif self.from_no <= entry.to_no <= self.to_no and entry.from_no <= self.from_no:
|
||||
new_entries.append(self.return_share_balance_entry(entry.from_no, self.from_no-1, entry.rate))
|
||||
else:
|
||||
new_entries.append(entry)
|
||||
|
||||
@@ -266,16 +246,34 @@ class ShareTransfer(Document):
|
||||
}
|
||||
|
||||
def get_shareholder_doc(self, shareholder):
|
||||
# Get Shareholder doc based on the Shareholder title
|
||||
doc = frappe.get_list('Shareholder',
|
||||
filters = [
|
||||
('Shareholder', 'title', '=', shareholder)
|
||||
]
|
||||
)
|
||||
if len(doc) == 1:
|
||||
return frappe.get_doc('Shareholder', doc[0]['name'])
|
||||
else: #It will necessarily by 0 indicating it doesn't exist
|
||||
return False
|
||||
# Get Shareholder doc based on the Shareholder name
|
||||
if shareholder:
|
||||
query_filters = {'name': shareholder}
|
||||
|
||||
name = frappe.db.get_value('Shareholder', {'name': shareholder}, 'name')
|
||||
|
||||
return frappe.get_doc('Shareholder', name)
|
||||
|
||||
def get_company_shareholder(self):
|
||||
# Get company doc or create one if not present
|
||||
company_shareholder = frappe.db.get_value('Shareholder',
|
||||
{
|
||||
'company': self.company,
|
||||
'is_company': 1
|
||||
}, 'name')
|
||||
|
||||
if company_shareholder:
|
||||
return frappe.get_doc('Shareholder', company_shareholder)
|
||||
else:
|
||||
shareholder = frappe.get_doc({
|
||||
'doctype': 'Shareholder',
|
||||
'title': self.company,
|
||||
'company': self.company,
|
||||
'is_company': 1
|
||||
})
|
||||
shareholder.insert()
|
||||
|
||||
return shareholder
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_jv_entry( company, account, amount, payment_account,\
|
||||
|
||||
@@ -15,67 +15,74 @@ class TestShareTransfer(unittest.TestCase):
|
||||
frappe.db.sql("delete from `tabShare Balance`")
|
||||
share_transfers = [
|
||||
{
|
||||
"doctype" : "Share Transfer",
|
||||
"transfer_type" : "Issue",
|
||||
"date" : "2018-01-01",
|
||||
"to_shareholder" : "SH-00001",
|
||||
"share_type" : "Equity",
|
||||
"from_no" : 1,
|
||||
"to_no" : 500,
|
||||
"no_of_shares" : 500,
|
||||
"rate" : 10,
|
||||
"company" : "_Test Company"
|
||||
"doctype": "Share Transfer",
|
||||
"transfer_type": "Issue",
|
||||
"date": "2018-01-01",
|
||||
"to_shareholder": "SH-00001",
|
||||
"share_type": "Equity",
|
||||
"from_no": 1,
|
||||
"to_no": 500,
|
||||
"no_of_shares": 500,
|
||||
"rate": 10,
|
||||
"company": "_Test Company",
|
||||
"asset_account": "Cash - _TC",
|
||||
"equity_or_liability_account": "Creditors - _TC"
|
||||
},
|
||||
{
|
||||
"doctype" : "Share Transfer",
|
||||
"transfer_type" : "Transfer",
|
||||
"date" : "2018-01-02",
|
||||
"from_shareholder" : "SH-00001",
|
||||
"to_shareholder" : "SH-00002",
|
||||
"share_type" : "Equity",
|
||||
"from_no" : 101,
|
||||
"to_no" : 200,
|
||||
"no_of_shares" : 100,
|
||||
"rate" : 15,
|
||||
"company" : "_Test Company"
|
||||
"doctype": "Share Transfer",
|
||||
"transfer_type": "Transfer",
|
||||
"date": "2018-01-02",
|
||||
"from_shareholder": "SH-00001",
|
||||
"to_shareholder": "SH-00002",
|
||||
"share_type": "Equity",
|
||||
"from_no": 101,
|
||||
"to_no": 200,
|
||||
"no_of_shares": 100,
|
||||
"rate": 15,
|
||||
"company": "_Test Company",
|
||||
"equity_or_liability_account": "Creditors - _TC"
|
||||
},
|
||||
{
|
||||
"doctype" : "Share Transfer",
|
||||
"transfer_type" : "Transfer",
|
||||
"date" : "2018-01-03",
|
||||
"from_shareholder" : "SH-00001",
|
||||
"to_shareholder" : "SH-00003",
|
||||
"share_type" : "Equity",
|
||||
"from_no" : 201,
|
||||
"to_no" : 500,
|
||||
"no_of_shares" : 300,
|
||||
"rate" : 20,
|
||||
"company" : "_Test Company"
|
||||
"doctype": "Share Transfer",
|
||||
"transfer_type": "Transfer",
|
||||
"date": "2018-01-03",
|
||||
"from_shareholder": "SH-00001",
|
||||
"to_shareholder": "SH-00003",
|
||||
"share_type": "Equity",
|
||||
"from_no": 201,
|
||||
"to_no": 500,
|
||||
"no_of_shares": 300,
|
||||
"rate": 20,
|
||||
"company": "_Test Company",
|
||||
"equity_or_liability_account": "Creditors - _TC"
|
||||
},
|
||||
{
|
||||
"doctype" : "Share Transfer",
|
||||
"transfer_type" : "Transfer",
|
||||
"date" : "2018-01-04",
|
||||
"from_shareholder" : "SH-00003",
|
||||
"to_shareholder" : "SH-00002",
|
||||
"share_type" : "Equity",
|
||||
"from_no" : 201,
|
||||
"to_no" : 400,
|
||||
"no_of_shares" : 200,
|
||||
"rate" : 15,
|
||||
"company" : "_Test Company"
|
||||
"doctype": "Share Transfer",
|
||||
"transfer_type": "Transfer",
|
||||
"date": "2018-01-04",
|
||||
"from_shareholder": "SH-00003",
|
||||
"to_shareholder": "SH-00002",
|
||||
"share_type": "Equity",
|
||||
"from_no": 201,
|
||||
"to_no": 400,
|
||||
"no_of_shares": 200,
|
||||
"rate": 15,
|
||||
"company": "_Test Company",
|
||||
"equity_or_liability_account": "Creditors - _TC"
|
||||
},
|
||||
{
|
||||
"doctype" : "Share Transfer",
|
||||
"transfer_type" : "Purchase",
|
||||
"date" : "2018-01-05",
|
||||
"from_shareholder" : "SH-00003",
|
||||
"share_type" : "Equity",
|
||||
"from_no" : 401,
|
||||
"to_no" : 500,
|
||||
"no_of_shares" : 100,
|
||||
"rate" : 25,
|
||||
"company" : "_Test Company"
|
||||
"doctype": "Share Transfer",
|
||||
"transfer_type": "Purchase",
|
||||
"date": "2018-01-05",
|
||||
"from_shareholder": "SH-00003",
|
||||
"share_type": "Equity",
|
||||
"from_no": 401,
|
||||
"to_no": 500,
|
||||
"no_of_shares": 100,
|
||||
"rate": 25,
|
||||
"company": "_Test Company",
|
||||
"asset_account": "Cash - _TC",
|
||||
"equity_or_liability_account": "Creditors - _TC"
|
||||
}
|
||||
]
|
||||
for d in share_transfers:
|
||||
@@ -84,30 +91,33 @@ class TestShareTransfer(unittest.TestCase):
|
||||
|
||||
def test_invalid_share_transfer(self):
|
||||
doc = frappe.get_doc({
|
||||
"doctype" : "Share Transfer",
|
||||
"transfer_type" : "Transfer",
|
||||
"date" : "2018-01-05",
|
||||
"from_shareholder" : "SH-00003",
|
||||
"to_shareholder" : "SH-00002",
|
||||
"share_type" : "Equity",
|
||||
"from_no" : 1,
|
||||
"to_no" : 100,
|
||||
"no_of_shares" : 100,
|
||||
"rate" : 15,
|
||||
"company" : "_Test Company"
|
||||
"doctype": "Share Transfer",
|
||||
"transfer_type": "Transfer",
|
||||
"date": "2018-01-05",
|
||||
"from_shareholder": "SH-00003",
|
||||
"to_shareholder": "SH-00002",
|
||||
"share_type": "Equity",
|
||||
"from_no": 1,
|
||||
"to_no": 100,
|
||||
"no_of_shares": 100,
|
||||
"rate": 15,
|
||||
"company": "_Test Company",
|
||||
"equity_or_liability_account": "Creditors - _TC"
|
||||
})
|
||||
self.assertRaises(ShareDontExists, doc.insert)
|
||||
|
||||
doc = frappe.get_doc({
|
||||
"doctype" : "Share Transfer",
|
||||
"transfer_type" : "Purchase",
|
||||
"date" : "2018-01-02",
|
||||
"from_shareholder" : "SH-00001",
|
||||
"share_type" : "Equity",
|
||||
"from_no" : 1,
|
||||
"to_no" : 200,
|
||||
"no_of_shares" : 200,
|
||||
"rate" : 15,
|
||||
"company" : "_Test Company"
|
||||
"doctype": "Share Transfer",
|
||||
"transfer_type": "Purchase",
|
||||
"date": "2018-01-02",
|
||||
"from_shareholder": "SH-00001",
|
||||
"share_type": "Equity",
|
||||
"from_no": 1,
|
||||
"to_no": 200,
|
||||
"no_of_shares": 200,
|
||||
"rate": 15,
|
||||
"company": "_Test Company",
|
||||
"asset_account": "Cash - _TC",
|
||||
"equity_or_liability_account": "Creditors - _TC"
|
||||
})
|
||||
self.assertRaises(ShareDontExists, doc.insert)
|
||||
|
||||
@@ -1,587 +1,163 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "naming_series:",
|
||||
"beta": 0,
|
||||
"creation": "2017-12-25 16:50:53.878430",
|
||||
"custom": 0,
|
||||
"description": "",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2017-12-25 16:50:53.878430",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"title",
|
||||
"column_break_2",
|
||||
"naming_series",
|
||||
"section_break_2",
|
||||
"folio_no",
|
||||
"column_break_4",
|
||||
"company",
|
||||
"is_company",
|
||||
"address_contacts",
|
||||
"address_html",
|
||||
"column_break_9",
|
||||
"contact_html",
|
||||
"section_break_3",
|
||||
"share_balance",
|
||||
"contact_list"
|
||||
],
|
||||
"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,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"label": "Title",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "ACC-SH-.YYYY.-",
|
||||
"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": 0
|
||||
},
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"options": "ACC-SH-.YYYY.-"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_2",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "section_break_2",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "folio_no",
|
||||
"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": "Folio no.",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"fieldname": "folio_no",
|
||||
"fieldtype": "Data",
|
||||
"label": "Folio no.",
|
||||
"read_only": 1,
|
||||
"unique": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"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": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "is_company",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Is Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"default": "0",
|
||||
"fieldname": "is_company",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"label": "Is Company",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "address_contacts",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Address and Contacts",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "fa fa-map-marker",
|
||||
"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": 0
|
||||
},
|
||||
"fieldname": "address_contacts",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Address and Contacts",
|
||||
"options": "fa fa-map-marker"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "address_html",
|
||||
"fieldtype": "HTML",
|
||||
"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": "Address HTML",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "address_html",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Address HTML",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "contact_html",
|
||||
"fieldtype": "HTML",
|
||||
"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": "Contact HTML",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "contact_html",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Contact HTML",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_3",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Share Balance",
|
||||
"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": 0
|
||||
},
|
||||
"fieldname": "section_break_3",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Share Balance"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "share_balance",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Share Balance",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Share Balance",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "share_balance",
|
||||
"fieldtype": "Table",
|
||||
"label": "Share Balance",
|
||||
"options": "Share Balance",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Hidden list maintaining the list of contacts linked to Shareholder",
|
||||
"fieldname": "contact_list",
|
||||
"fieldtype": "Code",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Contact List",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"description": "Hidden list maintaining the list of contacts linked to Shareholder",
|
||||
"fieldname": "contact_list",
|
||||
"fieldtype": "Code",
|
||||
"hidden": 1,
|
||||
"label": "Contact List",
|
||||
"read_only": 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-09-18 14:14:24.953014",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Shareholder",
|
||||
"name_case": "Title Case",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"modified": "2019-11-17 23:24:11.395882",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Shareholder",
|
||||
"name_case": "Title 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,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"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,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"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 User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"search_fields": "folio_no",
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "title",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
],
|
||||
"search_fields": "folio_no",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "title",
|
||||
"track_changes": 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
|
||||
|
||||
@@ -14,13 +14,13 @@ class TestShippingRule(unittest.TestCase):
|
||||
shipping_rule.name = test_records[0].get('name')
|
||||
shipping_rule.get("conditions")[0].from_value = 101
|
||||
self.assertRaises(FromGreaterThanToError, shipping_rule.insert)
|
||||
|
||||
|
||||
def test_many_zero_to_values(self):
|
||||
shipping_rule = frappe.copy_doc(test_records[0])
|
||||
shipping_rule.name = test_records[0].get('name')
|
||||
shipping_rule.get("conditions")[0].to_value = 0
|
||||
self.assertRaises(ManyBlankToValuesError, shipping_rule.insert)
|
||||
|
||||
|
||||
def test_overlapping_conditions(self):
|
||||
for range_a, range_b in [
|
||||
((50, 150), (0, 100)),
|
||||
@@ -38,6 +38,10 @@ class TestShippingRule(unittest.TestCase):
|
||||
self.assertRaises(OverlappingConditionError, shipping_rule.insert)
|
||||
|
||||
def create_shipping_rule(shipping_rule_type, shipping_rule_name):
|
||||
|
||||
if frappe.db.exists("Shipping Rule", shipping_rule_name):
|
||||
return frappe.get_doc("Shipping Rule", shipping_rule_name)
|
||||
|
||||
sr = frappe.new_doc("Shipping Rule")
|
||||
sr.account = "_Test Account Shipping Charges - _TC"
|
||||
sr.calculate_based_on = "Net Total"
|
||||
@@ -70,4 +74,4 @@ def create_shipping_rule(shipping_rule_type, shipping_rule_name):
|
||||
})
|
||||
sr.insert(ignore_permissions=True)
|
||||
sr.submit()
|
||||
return sr
|
||||
return sr
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@ from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils.data import nowdate, getdate, cint, add_days, date_diff, get_last_day, add_to_date, flt
|
||||
from erpnext.accounts.doctype.subscription_plan.subscription_plan import get_plan_rate
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
|
||||
|
||||
class Subscription(Document):
|
||||
@@ -241,6 +242,15 @@ class Subscription(Document):
|
||||
invoice.posting_date = self.current_invoice_start
|
||||
invoice.customer = self.customer
|
||||
|
||||
## Add dimesnions in invoice for subscription:
|
||||
accounting_dimensions = get_accounting_dimensions()
|
||||
|
||||
for dimension in accounting_dimensions:
|
||||
if self.get(dimension):
|
||||
invoice.update({
|
||||
dimension: self.get(dimension)
|
||||
})
|
||||
|
||||
# Subscription is better suited for service items. I won't update `update_stock`
|
||||
# for that reason
|
||||
items_list = self.get_items_from_plans(self.plans, prorate)
|
||||
@@ -328,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):
|
||||
"""
|
||||
@@ -338,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,612 +1,163 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:plan_name",
|
||||
"beta": 0,
|
||||
"creation": "2018-02-24 11:31:23.066506",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:plan_name",
|
||||
"creation": "2018-02-24 11:31:23.066506",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"plan_name",
|
||||
"currency",
|
||||
"column_break_3",
|
||||
"item",
|
||||
"section_break_5",
|
||||
"price_determination",
|
||||
"column_break_7",
|
||||
"cost",
|
||||
"price_list",
|
||||
"section_break_11",
|
||||
"billing_interval",
|
||||
"column_break_13",
|
||||
"billing_interval_count",
|
||||
"payment_plan_section",
|
||||
"payment_plan_id",
|
||||
"column_break_16",
|
||||
"payment_gateway",
|
||||
"accounting_dimensions_section",
|
||||
"dimension_col_break"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "plan_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Plan Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"fieldname": "plan_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Plan Name",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "currency",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Currency",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Currency",
|
||||
"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": 0
|
||||
},
|
||||
"fieldname": "currency",
|
||||
"fieldtype": "Link",
|
||||
"label": "Currency",
|
||||
"options": "Currency"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "item",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Item",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "item",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Item",
|
||||
"options": "Item",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"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_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fieldname": "price_determination",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Price Determination",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "\nFixed rate\nBased on price list",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "price_determination",
|
||||
"fieldtype": "Select",
|
||||
"label": "Price Determination",
|
||||
"options": "\nFixed rate\nBased on price list",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_7",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_7",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.price_determination==\"Fixed rate\"",
|
||||
"fieldname": "cost",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Cost",
|
||||
"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": 0
|
||||
},
|
||||
"depends_on": "eval:doc.price_determination==\"Fixed rate\"",
|
||||
"fieldname": "cost",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Cost"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.price_determination==\"Based on price list\"",
|
||||
"fieldname": "price_list",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Price List",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Price List",
|
||||
"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": 0
|
||||
},
|
||||
"depends_on": "eval:doc.price_determination==\"Based on price list\"",
|
||||
"fieldname": "price_list",
|
||||
"fieldtype": "Link",
|
||||
"label": "Price List",
|
||||
"options": "Price List"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_11",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"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": 0
|
||||
},
|
||||
"fieldname": "section_break_11",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Day",
|
||||
"fieldname": "billing_interval",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Billing Interval",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Day\nWeek\nMonth\nYear",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"default": "Day",
|
||||
"fieldname": "billing_interval",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Billing Interval",
|
||||
"options": "Day\nWeek\nMonth\nYear",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_13",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_13",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "1",
|
||||
"description": "Number of intervals for the interval field e.g if Interval is 'Days' and Billing Interval Count is 3, invoices will be generated every 3 days",
|
||||
"fieldname": "billing_interval_count",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Billing Interval Count",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"default": "1",
|
||||
"description": "Number of intervals for the interval field e.g if Interval is 'Days' and Billing Interval Count is 3, invoices will be generated every 3 days",
|
||||
"fieldname": "billing_interval_count",
|
||||
"fieldtype": "Int",
|
||||
"label": "Billing Interval Count",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "payment_plan_section",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payment Plan",
|
||||
"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": 0
|
||||
},
|
||||
"fieldname": "payment_plan_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Payment Plan"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "payment_plan_id",
|
||||
"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": "Payment Plan",
|
||||
"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": 0
|
||||
},
|
||||
"fieldname": "payment_plan_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Payment Plan"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_16",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_16",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "payment_gateway",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payment Gateway",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Payment Gateway Account",
|
||||
"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": 0
|
||||
"fieldname": "payment_gateway",
|
||||
"fieldtype": "Link",
|
||||
"label": "Payment Gateway",
|
||||
"options": "Payment Gateway Account"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "accounting_dimensions_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Accounting Dimensions"
|
||||
},
|
||||
{
|
||||
"fieldname": "dimension_col_break",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"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-06-20 16:59:54.082358",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Subscription Plan",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"modified": "2019-07-25 18:35:04.362556",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Subscription Plan",
|
||||
"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,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ class TestTaxWithholdingCategory(unittest.TestCase):
|
||||
#delete invoices to avoid clashing
|
||||
for d in invoices:
|
||||
d.cancel()
|
||||
frappe.delete_doc("Purchase Invoice", d.name)
|
||||
|
||||
def test_single_threshold_tds(self):
|
||||
invoices = []
|
||||
@@ -83,7 +82,6 @@ class TestTaxWithholdingCategory(unittest.TestCase):
|
||||
# delete invoices to avoid clashing
|
||||
for d in invoices:
|
||||
d.cancel()
|
||||
frappe.delete_doc("Purchase Invoice", d.name)
|
||||
|
||||
def test_single_threshold_tds_with_previous_vouchers(self):
|
||||
invoices = []
|
||||
@@ -102,7 +100,6 @@ class TestTaxWithholdingCategory(unittest.TestCase):
|
||||
# delete invoices to avoid clashing
|
||||
for d in invoices:
|
||||
d.cancel()
|
||||
frappe.delete_doc("Purchase Invoice", d.name)
|
||||
|
||||
def create_purchase_invoice(**args):
|
||||
# return sales invoice doc object
|
||||
|
||||
@@ -3,18 +3,22 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe, erpnext
|
||||
from frappe.utils import flt, cstr, cint
|
||||
from frappe.utils import flt, cstr, cint, comma_and
|
||||
from frappe import _
|
||||
from erpnext.accounts.utils import get_stock_and_account_balance
|
||||
from frappe.model.meta import get_field_precision
|
||||
from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
|
||||
|
||||
class ClosedAccountingPeriod(frappe.ValidationError): pass
|
||||
class StockAccountInvalidTransaction(frappe.ValidationError): pass
|
||||
class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass
|
||||
|
||||
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes', from_repost=False):
|
||||
if gl_map:
|
||||
if not cancel:
|
||||
validate_accounting_period(gl_map)
|
||||
gl_map = process_gl_map(gl_map, merge_entries)
|
||||
if gl_map and len(gl_map) > 1:
|
||||
save_entries(gl_map, adv_adj, update_outstanding, from_repost)
|
||||
@@ -23,6 +27,27 @@ def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, upd
|
||||
else:
|
||||
delete_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
|
||||
|
||||
def validate_accounting_period(gl_map):
|
||||
accounting_periods = frappe.db.sql(""" SELECT
|
||||
ap.name as name
|
||||
FROM
|
||||
`tabAccounting Period` ap, `tabClosed Document` cd
|
||||
WHERE
|
||||
ap.name = cd.parent
|
||||
AND ap.company = %(company)s
|
||||
AND cd.closed = 1
|
||||
AND cd.document_type = %(voucher_type)s
|
||||
AND %(date)s between ap.start_date and ap.end_date
|
||||
""", {
|
||||
'date': gl_map[0].posting_date,
|
||||
'company': gl_map[0].company,
|
||||
'voucher_type': gl_map[0].voucher_type
|
||||
}, as_dict=1)
|
||||
|
||||
if accounting_periods:
|
||||
frappe.throw(_("You can't create accounting entries in the closed accounting period {0}")
|
||||
.format(accounting_periods[0].name), ClosedAccountingPeriod)
|
||||
|
||||
def process_gl_map(gl_map, merge_entries=True):
|
||||
if merge_entries:
|
||||
gl_map = merge_similar_entries(gl_map)
|
||||
@@ -65,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
|
||||
@@ -92,10 +121,9 @@ def check_if_in_list(gle, gl_map, dimensions=None):
|
||||
|
||||
def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
|
||||
if not from_repost:
|
||||
validate_account_for_perpetual_inventory(gl_map)
|
||||
validate_cwip_accounts(gl_map)
|
||||
|
||||
round_off_debit_credit(gl_map)
|
||||
|
||||
for entry in gl_map:
|
||||
make_entry(entry, adv_adj, update_outstanding, from_repost)
|
||||
|
||||
@@ -103,6 +131,10 @@ def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
|
||||
if not from_repost:
|
||||
validate_expense_against_budget(entry)
|
||||
|
||||
if not from_repost:
|
||||
validate_account_for_perpetual_inventory(gl_map)
|
||||
|
||||
|
||||
def make_entry(args, adv_adj, update_outstanding, from_repost=False):
|
||||
args.update({"doctype": "GL Entry"})
|
||||
gle = frappe.get_doc(args)
|
||||
@@ -113,15 +145,67 @@ def make_entry(args, adv_adj, update_outstanding, from_repost=False):
|
||||
gle.submit()
|
||||
|
||||
def validate_account_for_perpetual_inventory(gl_map):
|
||||
if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)) \
|
||||
and gl_map[0].voucher_type=="Journal Entry":
|
||||
aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
|
||||
where account_type = 'Stock' and is_group=0""")]
|
||||
if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)):
|
||||
account_list = [gl_entries.account for gl_entries in gl_map]
|
||||
|
||||
aii_accounts = [d.name for d in frappe.get_all("Account",
|
||||
filters={'account_type': 'Stock', 'is_group': 0, 'company': gl_map[0].company})]
|
||||
|
||||
for account in account_list:
|
||||
if account not in aii_accounts:
|
||||
continue
|
||||
|
||||
account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(account,
|
||||
gl_map[0].posting_date, gl_map[0].company)
|
||||
|
||||
if gl_map[0].voucher_type=="Journal Entry":
|
||||
# In case of Journal Entry, there are no corresponding SL entries,
|
||||
# hence deducting currency amount
|
||||
account_bal -= flt(gl_map[0].debit) - flt(gl_map[0].credit)
|
||||
if account_bal == stock_bal:
|
||||
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
|
||||
.format(account), StockAccountInvalidTransaction)
|
||||
|
||||
# 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")
|
||||
|
||||
# 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) }]
|
||||
# }
|
||||
|
||||
# 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")])
|
||||
|
||||
if cwip_enabled and gl_map[0].voucher_type == "Journal Entry":
|
||||
cwip_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
|
||||
where account_type = 'Capital Work in Progress' and is_group=0""")]
|
||||
|
||||
for entry in gl_map:
|
||||
if entry.account in aii_accounts:
|
||||
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
|
||||
.format(entry.account), StockAccountInvalidTransaction)
|
||||
if entry.account in cwip_accounts:
|
||||
frappe.throw(
|
||||
_("Account: <b>{0}</b> is capital Work in progress and can not be updated by Journal Entry").format(entry.account))
|
||||
|
||||
def round_off_debit_credit(gl_map):
|
||||
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
|
||||
|
||||
@@ -139,15 +139,11 @@ erpnext.accounts.bankTransactionUpload = class bankTransactionUpload {
|
||||
}
|
||||
|
||||
make() {
|
||||
const me = this;
|
||||
frappe.upload.make({
|
||||
args: {
|
||||
method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement',
|
||||
allow_multiple: 0
|
||||
},
|
||||
no_socketio: true,
|
||||
sample_url: "e.g. http://example.com/somefile.csv",
|
||||
callback: function(attachment, r) {
|
||||
const me = this;
|
||||
new frappe.ui.FileUploader({
|
||||
method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement',
|
||||
allow_multiple: 0,
|
||||
on_success: function(attachment, r) {
|
||||
if (!r.exc && r.message) {
|
||||
me.data = r.message;
|
||||
me.setup_transactions_dom();
|
||||
@@ -533,9 +529,16 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
||||
frappe.db.get_doc(dt, event.value)
|
||||
.then(doc => {
|
||||
let displayed_docs = []
|
||||
let payment = []
|
||||
if (dt === "Payment Entry") {
|
||||
payment.currency = doc.payment_type == "Receive" ? doc.paid_to_account_currency : doc.paid_from_account_currency;
|
||||
payment.doctype = dt
|
||||
payment.posting_date = doc.posting_date;
|
||||
payment.party = doc.party;
|
||||
payment.reference_no = doc.reference_no;
|
||||
payment.reference_date = doc.reference_date;
|
||||
payment.paid_amount = doc.paid_amount;
|
||||
payment.name = doc.name;
|
||||
displayed_docs.push(payment);
|
||||
} else if (dt === "Journal Entry") {
|
||||
doc.accounts.forEach(payment => {
|
||||
@@ -568,11 +571,11 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
||||
|
||||
const details_wrapper = me.dialog.fields_dict.payment_details.$wrapper;
|
||||
details_wrapper.append(frappe.render_template("linked_payment_header"));
|
||||
displayed_docs.forEach(values => {
|
||||
details_wrapper.append(frappe.render_template("linked_payment_row", values));
|
||||
displayed_docs.forEach(payment => {
|
||||
details_wrapper.append(frappe.render_template("linked_payment_row", payment));
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,8 +124,6 @@ def check_matching_amount(bank_account, company, transaction):
|
||||
'txt': '%%%s%%' % amount
|
||||
}, as_dict=True)
|
||||
|
||||
frappe.errprint(journal_entries)
|
||||
|
||||
if transaction.credit > 0:
|
||||
sales_invoices = frappe.db.sql("""
|
||||
SELECT
|
||||
|
||||
@@ -816,8 +816,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
contact = me.contacts[data.name];
|
||||
if(reg.test(data.name.toLowerCase())
|
||||
|| reg.test(data.customer_name.toLowerCase())
|
||||
|| (contact && reg.test(contact["mobile_no"]))
|
||||
|| (contact && reg.test(contact["phone"]))
|
||||
|| (contact && reg.test(contact["mobile_no"]))
|
||||
|| (data.customer_group && reg.test(data.customer_group.toLowerCase()))){
|
||||
return data;
|
||||
}
|
||||
@@ -1121,7 +1121,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
if (key) {
|
||||
return $.grep(this.items_list, function (item) {
|
||||
if (search_status) {
|
||||
if (in_list(me.batch_no_data[item.item_code], me.search_item.$input.val())) {
|
||||
if (me.batch_no_data[item.item_code] &&
|
||||
in_list(me.batch_no_data[item.item_code], me.search_item.$input.val())) {
|
||||
search_status = false;
|
||||
return me.item_batch_no[item.item_code] = me.search_item.$input.val()
|
||||
} else if (me.serial_no_data[item.item_code]
|
||||
@@ -1129,7 +1130,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
search_status = false;
|
||||
me.item_serial_no[item.item_code] = [me.search_item.$input.val(), me.serial_no_data[item.item_code][me.search_item.$input.val()]]
|
||||
return true
|
||||
} else if (in_list(me.barcode_data[item.item_code], me.search_item.$input.val())) {
|
||||
} else if (me.barcode_data[item.item_code] &&
|
||||
in_list(me.barcode_data[item.item_code], me.search_item.$input.val())) {
|
||||
search_status = false;
|
||||
return true;
|
||||
} else if (reg.test(item.item_code.toLowerCase()) || (item.description && reg.test(item.description.toLowerCase())) ||
|
||||
@@ -1625,7 +1627,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
setTimeout(function () {
|
||||
w.print();
|
||||
w.close();
|
||||
}, 1000)
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
submit_invoice: function () {
|
||||
@@ -1682,6 +1684,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
$(this.wrapper).find('.pos-bill').css('pointer-events', pointer_events);
|
||||
$(this.wrapper).find('.pos-items-section').css('pointer-events', pointer_events);
|
||||
this.set_primary_action();
|
||||
|
||||
$(this.wrapper).find('#pos-item-disc').prop('disabled',
|
||||
this.pos_profile_data.allow_user_to_edit_discount ? false : true);
|
||||
|
||||
$(this.wrapper).find('#pos-item-price').prop('disabled',
|
||||
this.pos_profile_data.allow_user_to_edit_rate ? false : true);
|
||||
},
|
||||
|
||||
create_invoice: function () {
|
||||
@@ -1692,20 +1700,13 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
|
||||
if(this.si_docs) {
|
||||
this.si_docs.forEach((row) => {
|
||||
existing_pos_list.push(Object.keys(row));
|
||||
existing_pos_list.push(Object.keys(row)[0]);
|
||||
});
|
||||
}
|
||||
|
||||
if (this.frm.doc.offline_pos_name
|
||||
&& in_list(existing_pos_list, this.frm.doc.offline_pos_name)) {
|
||||
&& in_list(existing_pos_list, cstr(this.frm.doc.offline_pos_name))) {
|
||||
this.update_invoice()
|
||||
//to retrieve and set the default payment
|
||||
invoice_data[this.frm.doc.offline_pos_name] = this.frm.doc;
|
||||
invoice_data[this.frm.doc.offline_pos_name].payments[0].amount = this.frm.doc.net_total
|
||||
invoice_data[this.frm.doc.offline_pos_name].payments[0].base_amount = this.frm.doc.net_total
|
||||
|
||||
this.frm.doc.paid_amount = this.frm.doc.net_total
|
||||
this.frm.doc.outstanding_amount = 0
|
||||
} else if(!this.frm.doc.offline_pos_name) {
|
||||
this.frm.doc.offline_pos_name = frappe.datetime.now_datetime();
|
||||
this.frm.doc.posting_date = frappe.datetime.get_today();
|
||||
@@ -1762,18 +1763,11 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
this.si_docs = this.get_submitted_invoice() || [];
|
||||
this.email_queue_list = this.get_email_queue() || {};
|
||||
this.customers_list = this.get_customers_details() || {};
|
||||
if(this.customer_doc) {
|
||||
this.freeze = this.customer_doc.display
|
||||
}
|
||||
|
||||
freeze_screen = this.freeze_screen || false;
|
||||
|
||||
if ((this.si_docs.length || this.email_queue_list || this.customers_list) && !this.freeze) {
|
||||
this.freeze = true;
|
||||
|
||||
if (this.si_docs.length || this.email_queue_list || this.customers_list) {
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.sales_invoice.pos.make_invoice",
|
||||
freeze: freeze_screen,
|
||||
freeze: true,
|
||||
args: {
|
||||
doc_list: me.si_docs,
|
||||
email_queue_list: me.email_queue_list,
|
||||
@@ -1906,7 +1900,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
serial_no = me.item_serial_no[key][0];
|
||||
}
|
||||
|
||||
if (this.items[0].has_serial_no && serial_no == "") {
|
||||
if (this.items && this.items[0].has_serial_no && serial_no == "") {
|
||||
this.refresh();
|
||||
frappe.throw(__(repl("Error: Serial no is mandatory for item %(item)s", {
|
||||
'item': this.items[0].item_code
|
||||
|
||||
@@ -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):
|
||||
@@ -292,8 +297,11 @@ def validate_party_accounts(doc):
|
||||
|
||||
party_account_currency = frappe.db.get_value("Account", account.account, "account_currency", cache=True)
|
||||
existing_gle_currency = get_party_gle_currency(doc.doctype, doc.name, account.company)
|
||||
company_default_currency = frappe.get_cached_value('Company',
|
||||
frappe.db.get_default("Company"), "default_currency")
|
||||
if frappe.db.get_default("Company"):
|
||||
company_default_currency = frappe.get_cached_value('Company',
|
||||
frappe.db.get_default("Company"), "default_currency")
|
||||
else:
|
||||
company_default_currency = frappe.db.get_value('Company', account.company, "default_currency")
|
||||
|
||||
if existing_gle_currency and party_account_currency != existing_gle_currency:
|
||||
frappe.throw(_("Accounting entries have already been made in currency {0} for company {1}. Please select a receivable or payable account with currency {0}.").format(existing_gle_currency, account.company))
|
||||
@@ -365,7 +373,7 @@ def validate_due_date(posting_date, due_date, party_type, party, company=None, b
|
||||
.format(formatdate(default_due_date)))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_address_tax_category(tax_category, billing_address=None, shipping_address=None):
|
||||
def get_address_tax_category(tax_category=None, billing_address=None, shipping_address=None):
|
||||
addr_tax_category_from = frappe.db.get_single_value("Accounts Settings", "determine_address_tax_category_from")
|
||||
if addr_tax_category_from == "Shipping Address":
|
||||
if shipping_address:
|
||||
@@ -469,7 +477,9 @@ def get_timeline_data(doctype, name):
|
||||
# fetch and append data from Activity Log
|
||||
data += frappe.db.sql("""select {fields}
|
||||
from `tabActivity Log`
|
||||
where reference_doctype={doctype} and reference_name={name}
|
||||
where (reference_doctype="{doctype}" and reference_name="{name}")
|
||||
or (timeline_doctype in ("{doctype}") and timeline_name="{name}")
|
||||
or (reference_doctype in ("Quotation", "Opportunity") and timeline_name="{name}")
|
||||
and status!='Success' and creation > {after}
|
||||
{group_by} order by creation desc
|
||||
""".format(doctype=frappe.db.escape(doctype), name=frappe.db.escape(name), fields=fields,
|
||||
@@ -605,4 +615,4 @@ def get_partywise_advanced_payment_amount(party_type, posting_date = None):
|
||||
.format(("credit") if party_type == "Customer" else "debit", cond) , party_type)
|
||||
|
||||
if data:
|
||||
return frappe._dict(data)
|
||||
return frappe._dict(data)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user