Compare commits
1288 Commits
add-einvoi
...
version-11
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
927d14e021 | ||
|
|
7bb5313190 | ||
|
|
1d6bb3953d | ||
|
|
78d0a11d09 | ||
|
|
ccf62886e4 | ||
|
|
40747e1b49 | ||
|
|
87f8d66b79 | ||
|
|
d075399ecd | ||
|
|
c4ff9c72dd | ||
|
|
97ccb0eec2 | ||
|
|
2382312d41 | ||
|
|
348d10cad8 | ||
|
|
47f030b1bf | ||
|
|
7e4f8fa04d | ||
|
|
652181600d | ||
|
|
e4f300c903 | ||
|
|
d839c46f10 | ||
|
|
6d45dfd6e8 | ||
|
|
5caa40857d | ||
|
|
78b7f69e0c | ||
|
|
8d9b58d801 | ||
|
|
a611cc5916 | ||
|
|
c6466c7d97 | ||
|
|
b35db7e819 | ||
|
|
44875482ac | ||
|
|
f06cc233a8 | ||
|
|
fdd93cba03 | ||
|
|
10f53f04d7 | ||
|
|
884dc28af6 | ||
|
|
a506930b63 | ||
|
|
f6836c1d89 | ||
|
|
3e2fe12c9d | ||
|
|
5b2ca9e133 | ||
|
|
f8dc7b32d5 | ||
|
|
0393cb5c43 | ||
|
|
4206b52bdc | ||
|
|
9e66c86d6f | ||
|
|
ec46b4d4c6 | ||
|
|
39c71e26b9 | ||
|
|
77285317c0 | ||
|
|
a95c09bef6 | ||
|
|
6b901d0c1a | ||
|
|
8a7ccd9874 | ||
|
|
2f2e748b7a | ||
|
|
549ab68eb0 | ||
|
|
0b9bf4d0ac | ||
|
|
1c5df5dede | ||
|
|
41d2357dc4 | ||
|
|
af79714f40 | ||
|
|
8a5f31da34 | ||
|
|
47a7e3422b | ||
|
|
9efb087e22 | ||
|
|
3d58dd6aa5 | ||
|
|
ac7966cd7e | ||
|
|
61ddb508d4 | ||
|
|
d973fb8823 | ||
|
|
a649414419 | ||
|
|
270f23b966 | ||
|
|
4d745a39e0 | ||
|
|
5e0b5cb283 | ||
|
|
69358cfd40 | ||
|
|
ad1ba2bb76 | ||
|
|
c44abd2f78 | ||
|
|
0bcada8f3c | ||
|
|
a6b110a7d3 | ||
|
|
b4ce43306b | ||
|
|
85a9f55fa7 | ||
|
|
596c0d2060 | ||
|
|
723421f375 | ||
|
|
f9297416f2 | ||
|
|
a8d2916e61 | ||
|
|
0f70f20ec5 | ||
|
|
73d9d8fec9 | ||
|
|
c4756e938f | ||
|
|
faa5d90f1b | ||
|
|
3b37a109c5 | ||
|
|
ab4aa53f52 | ||
|
|
3483426fe7 | ||
|
|
3039094737 | ||
|
|
e21602d432 | ||
|
|
6067ef3c49 | ||
|
|
b78128a7fe | ||
|
|
c8cbb87168 | ||
|
|
aed8aeb83a | ||
|
|
fa47445e11 | ||
|
|
0220acf100 | ||
|
|
0fe8f8e6d9 | ||
|
|
f87b766a26 | ||
|
|
2262e5d443 | ||
|
|
b9cad8d891 | ||
|
|
dafdc6035a | ||
|
|
c8369c10ff | ||
|
|
08b8ed5ca6 | ||
|
|
6cefdb40d1 | ||
|
|
3ad65ec57d | ||
|
|
364332bcfe | ||
|
|
9965f443ee | ||
|
|
d87d644dc2 | ||
|
|
eeab3128aa | ||
|
|
7b2cec8da2 | ||
|
|
6e3cbd8698 | ||
|
|
b5e1f846ce | ||
|
|
f06b31aab4 | ||
|
|
f8502317a9 | ||
|
|
9c7a33405d | ||
|
|
0ee46a624c | ||
|
|
5485d4c435 | ||
|
|
fb2d4884b3 | ||
|
|
3b38a9e418 | ||
|
|
437d3e37d6 | ||
|
|
1b9a55e766 | ||
|
|
a5353a8d04 | ||
|
|
e1bc0a1028 | ||
|
|
92116abd92 | ||
|
|
e5731b3d0f | ||
|
|
a36c4326c3 | ||
|
|
5a0a4bdcff | ||
|
|
d2dc889849 | ||
|
|
dbcdf7e225 | ||
|
|
7fdef64152 | ||
|
|
b2be301988 | ||
|
|
68db5a6792 | ||
|
|
f232965392 | ||
|
|
2ff7197752 | ||
|
|
1d3b5b0437 | ||
|
|
8280d32967 | ||
|
|
4a79072c71 | ||
|
|
721a00cd22 | ||
|
|
8ce7893bf0 | ||
|
|
0f87282aef | ||
|
|
de51217a80 | ||
|
|
bc01dafbba | ||
|
|
a985bfc29a | ||
|
|
08dbb13451 | ||
|
|
170dd37b86 | ||
|
|
b1744972e0 | ||
|
|
7aa993b14b | ||
|
|
ad89cb0ef3 | ||
|
|
a185b51f0d | ||
|
|
1ff81bca7d | ||
|
|
b02db3c3e8 | ||
|
|
d1d835347e | ||
|
|
ba245553f0 | ||
|
|
112902a9c4 | ||
|
|
3f4cdcc7a4 | ||
|
|
91f81b07d9 | ||
|
|
66e92041b9 | ||
|
|
f2dc89c7a0 | ||
|
|
10b226af10 | ||
|
|
115887a886 | ||
|
|
a1f5c22da7 | ||
|
|
712c01d5bd | ||
|
|
bd4e296336 | ||
|
|
b52d81ef6a | ||
|
|
15432c76a4 | ||
|
|
dd3cd6e2ba | ||
|
|
5889a29656 | ||
|
|
0e7ca6ada7 | ||
|
|
5a2ea528e8 | ||
|
|
8957093439 | ||
|
|
507c435dee | ||
|
|
8889edad72 | ||
|
|
e27d1aebd5 | ||
|
|
ef567eac37 | ||
|
|
f8e0a2204e | ||
|
|
baecc7fd31 | ||
|
|
529b465337 | ||
|
|
675e2670b2 | ||
|
|
3919fd10ad | ||
|
|
b4e61e19bb | ||
|
|
85be3ec796 | ||
|
|
aa3d6ed11e | ||
|
|
382735ad2f | ||
|
|
8d42b75e29 | ||
|
|
7e03e046ec | ||
|
|
bfddc8aba1 | ||
|
|
d0dafcc46f | ||
|
|
43a0161257 | ||
|
|
f8996b64f1 | ||
|
|
867443ea6d | ||
|
|
acdc230ef3 | ||
|
|
86232e4449 | ||
|
|
78c7f03731 | ||
|
|
65b99a5109 | ||
|
|
8ec290d5ec | ||
|
|
65a259eb81 | ||
|
|
47420578ae | ||
|
|
35d8cd9f10 | ||
|
|
1e55ac6a4f | ||
|
|
ce60dc3ea3 | ||
|
|
ff7a5d18d1 | ||
|
|
5a15dcc060 | ||
|
|
cec6c87e09 | ||
|
|
b2870b9426 | ||
|
|
e27600066c | ||
|
|
5b8c624b34 | ||
|
|
9e8531d68e | ||
|
|
ebeb137351 | ||
|
|
8c7d28a41a | ||
|
|
d90b80af86 | ||
|
|
b62e17f7f2 | ||
|
|
5169dc1566 | ||
|
|
d3afecd1d9 | ||
|
|
ec56984e12 | ||
|
|
1c26623f22 | ||
|
|
02cb668f22 | ||
|
|
bd749dce18 | ||
|
|
737a504a35 | ||
|
|
c719f842bc | ||
|
|
0d19139acf | ||
|
|
80973bb8de | ||
|
|
a9a7e84873 | ||
|
|
b23da53fee | ||
|
|
78776c42fe | ||
|
|
2d9908d22f | ||
|
|
3b0695e0ca | ||
|
|
a9695f04de | ||
|
|
a2398775cd | ||
|
|
f2544ec7f2 | ||
|
|
778d7b9cbd | ||
|
|
2a3c62e7f6 | ||
|
|
5c576e4365 | ||
|
|
c57753a234 | ||
|
|
7cabcdd9a2 | ||
|
|
2b0c845cb8 | ||
|
|
71e51714f2 | ||
|
|
d37a30fc47 | ||
|
|
62767ced3e | ||
|
|
cf71643685 | ||
|
|
d225f5993b | ||
|
|
3dc8941be7 | ||
|
|
dbebec8fcc | ||
|
|
4111965d2e | ||
|
|
3ac54a0ba6 | ||
|
|
143f007272 | ||
|
|
3fc10a8da1 | ||
|
|
ed1e28b8fa | ||
|
|
71145c699f | ||
|
|
ea6d90988f | ||
|
|
6efe4acb1d | ||
|
|
ad2365502f | ||
|
|
9c428ebfba | ||
|
|
b53e4404dc | ||
|
|
0bc849975c | ||
|
|
690139ca11 | ||
|
|
c0a21ad96a | ||
|
|
8c9fd62775 | ||
|
|
0be054ae0f | ||
|
|
912cf9d555 | ||
|
|
7fe0a2023a | ||
|
|
cf191c0483 | ||
|
|
bb8d9f2a57 | ||
|
|
fa4577d18a | ||
|
|
993521d365 | ||
|
|
3372b7411d | ||
|
|
5dbfeb8557 | ||
|
|
f5d2337176 | ||
|
|
67aa7b8735 | ||
|
|
aea67c9843 | ||
|
|
f64aaf5e1c | ||
|
|
00f6fd827e | ||
|
|
ea2cdf8c12 | ||
|
|
29729c8d31 | ||
|
|
536e24c6a1 | ||
|
|
f178dc3b26 | ||
|
|
bc2f311a41 | ||
|
|
5c28aba872 | ||
|
|
f800050b71 | ||
|
|
fea996303f | ||
|
|
833e017111 | ||
|
|
fb4f73605a | ||
|
|
94dfcce434 | ||
|
|
18e5bc1976 | ||
|
|
7e54e6acb8 | ||
|
|
0e52951db8 | ||
|
|
1b050e2dfd | ||
|
|
5674e19e71 | ||
|
|
c49735ed15 | ||
|
|
d1c467e49c | ||
|
|
e14df31c05 | ||
|
|
9ff9f21af0 | ||
|
|
eba361b27d | ||
|
|
cc960806a9 | ||
|
|
75c47d64ff | ||
|
|
300307b22f | ||
|
|
43ebcb5876 | ||
|
|
f254d8c5ee | ||
|
|
8811a8c9b6 | ||
|
|
4f1b88ee0f | ||
|
|
51a7aa9c76 | ||
|
|
33ce5ce048 | ||
|
|
b4a570242e | ||
|
|
481977d368 | ||
|
|
479b2bbbd9 | ||
|
|
4faf57869d | ||
|
|
33eb38cc1b | ||
|
|
c6f72f7c90 | ||
|
|
d082a12411 | ||
|
|
096de8a0d5 | ||
|
|
5638d63866 | ||
|
|
a621466219 | ||
|
|
6155114bfd | ||
|
|
2ca33d4f51 | ||
|
|
f1618af76c | ||
|
|
9f7098115b | ||
|
|
55b8b4e374 | ||
|
|
7cb8c51b2d | ||
|
|
311fe5b3dc | ||
|
|
269868130f | ||
|
|
736eed01c2 | ||
|
|
e014b898bd | ||
|
|
1eb31210e0 | ||
|
|
8d72aa99aa | ||
|
|
3a4503b7a1 | ||
|
|
01952bbc15 | ||
|
|
1ca6365dee | ||
|
|
a7a810a25f | ||
|
|
e62fba062e | ||
|
|
60b7acc9b0 | ||
|
|
d7ddb0c14e | ||
|
|
8d84ffb276 | ||
|
|
784c3333d7 | ||
|
|
2227f54e66 | ||
|
|
c55657dca5 | ||
|
|
b6b2c48340 | ||
|
|
582c86a7b6 | ||
|
|
76668e9004 | ||
|
|
d0426a6127 | ||
|
|
4252575e84 | ||
|
|
f6dcd8ac91 | ||
|
|
6a9fb51dc5 | ||
|
|
70b93e2cd4 | ||
|
|
f4493674f7 | ||
|
|
dd5a818d6a | ||
|
|
e78dfb5df6 | ||
|
|
429d0dcda0 | ||
|
|
eb174e1afa | ||
|
|
4a6b5367ca | ||
|
|
3675e616bc | ||
|
|
f9d3df9531 | ||
|
|
081d312a11 | ||
|
|
355e832b02 | ||
|
|
6b65e2b168 | ||
|
|
57041084d1 | ||
|
|
cf4c7b406a | ||
|
|
edb3cdbb59 | ||
|
|
55025d4dc9 | ||
|
|
6f7a5e525d | ||
|
|
342c77c851 | ||
|
|
94f4d81b70 | ||
|
|
74f31c6677 | ||
|
|
7589b9f822 | ||
|
|
b761169976 | ||
|
|
537c3a79ab | ||
|
|
0510988b3e | ||
|
|
79c389a48f | ||
|
|
239779dad0 | ||
|
|
37a7ab9d0e | ||
|
|
17ea15eb91 | ||
|
|
ddaf81051e | ||
|
|
d06f3882e9 | ||
|
|
523994c2cf | ||
|
|
00219ab7f0 | ||
|
|
0c4f1e5e67 | ||
|
|
29e3cfd60f | ||
|
|
95058eac21 | ||
|
|
4b963be8c4 | ||
|
|
a4434b1a50 | ||
|
|
d3dc241878 | ||
|
|
012e617c55 | ||
|
|
bee135c8c6 | ||
|
|
8a19cd1096 | ||
|
|
5b14ca081c | ||
|
|
4fbf03c760 | ||
|
|
503d1d3291 | ||
|
|
e2108d75dc | ||
|
|
9a009a1d1c | ||
|
|
61211486bc | ||
|
|
42fd7451bf | ||
|
|
70a1c1bdac | ||
|
|
eb6d74217c | ||
|
|
172a8f1cea | ||
|
|
164057fa5b | ||
|
|
3c21ac6bb6 | ||
|
|
ad2585e1b7 | ||
|
|
09fe604452 | ||
|
|
28d836cfea | ||
|
|
8005f350ae | ||
|
|
3168ae7dcc | ||
|
|
447b8dab96 | ||
|
|
6408949d43 | ||
|
|
5fe2272861 | ||
|
|
7165a5d1f8 | ||
|
|
2ec21fa9fb | ||
|
|
a162f560dd | ||
|
|
c3c168a70d | ||
|
|
b5ac3b8a53 | ||
|
|
30452a8bcd | ||
|
|
36676effd9 | ||
|
|
f31ff74a75 | ||
|
|
4298cc1cdb | ||
|
|
abe5a5ae30 | ||
|
|
9daaeaed07 | ||
|
|
926150bccb | ||
|
|
e46d10676e | ||
|
|
631e8bb9dd | ||
|
|
13d6f4b291 | ||
|
|
bc72fdff7a | ||
|
|
e8148112fc | ||
|
|
a1dd861096 | ||
|
|
aeb0b008fa | ||
|
|
4c711ed62c | ||
|
|
7620742299 | ||
|
|
8a5bd02662 | ||
|
|
565936442d | ||
|
|
a8e1c90035 | ||
|
|
a953b68a17 | ||
|
|
c9c48d3736 | ||
|
|
d1d679843e | ||
|
|
c2b7084ee8 | ||
|
|
07bbe8568f | ||
|
|
2a58b6c20b | ||
|
|
196bf2104f | ||
|
|
a33145e6d9 | ||
|
|
6161d3362d | ||
|
|
fac8ed0630 | ||
|
|
3279ad55f6 | ||
|
|
9bdb04d7ca | ||
|
|
89270ef2c0 | ||
|
|
c0ea006571 | ||
|
|
de3b79cce8 | ||
|
|
f326d5c9a1 | ||
|
|
e112ac2345 | ||
|
|
ad1719bbe4 | ||
|
|
f2c464dda8 | ||
|
|
2b64b38a6e | ||
|
|
dcbafecf58 | ||
|
|
20229b915c | ||
|
|
7a1a0fb5fb | ||
|
|
fddef7bd5c | ||
|
|
804854f051 | ||
|
|
bdb48f34ed | ||
|
|
986b5115da | ||
|
|
b37f4a157c | ||
|
|
f650b287ef | ||
|
|
1866cebd14 | ||
|
|
bb5bf06e0c | ||
|
|
ecf8e20462 | ||
|
|
5a0bc043aa | ||
|
|
a2c9c9505c | ||
|
|
f6060fa5f2 | ||
|
|
b4cf29391b | ||
|
|
a6a6f69e26 | ||
|
|
db38c02aee | ||
|
|
e107d430eb | ||
|
|
0c849ac0f3 | ||
|
|
6b86bb462b | ||
|
|
80cfc88abb | ||
|
|
3c425584a7 | ||
|
|
af561becc6 | ||
|
|
0ef08618c9 | ||
|
|
373d90f802 | ||
|
|
ceaedd0f95 | ||
|
|
fd7c4e9822 | ||
|
|
26878d907e | ||
|
|
ae3c21046b | ||
|
|
f01baaa56f | ||
|
|
ac534c64bc | ||
|
|
6e8e42ca7c | ||
|
|
7d3d99a9b8 | ||
|
|
9a858a9824 | ||
|
|
5792d6037c | ||
|
|
75310637da | ||
|
|
6fa4697efb | ||
|
|
63e83cc005 | ||
|
|
68d7d6e223 | ||
|
|
7ee97b6128 | ||
|
|
49fadcbaf2 | ||
|
|
e6ab86e185 | ||
|
|
35fe0a6cbd | ||
|
|
d287fe4dae | ||
|
|
683d987432 | ||
|
|
37d0c75f04 | ||
|
|
6940a6cd47 | ||
|
|
34867ced92 | ||
|
|
5c482e907e | ||
|
|
3ebc13f228 | ||
|
|
b5882aaa6c | ||
|
|
7543916da6 | ||
|
|
11d02c028f | ||
|
|
a72ef5eceb | ||
|
|
3e9ddf23e1 | ||
|
|
6fc6f385fe | ||
|
|
ba62173561 | ||
|
|
709f21692c | ||
|
|
4dd48f46f3 | ||
|
|
e59836e3da | ||
|
|
cc80be449d | ||
|
|
29433f2b1b | ||
|
|
bdeaf4880f | ||
|
|
53e3674924 | ||
|
|
6f2f8ae85e | ||
|
|
48474a2d4e | ||
|
|
3e6df7f0bb | ||
|
|
47bca7f651 | ||
|
|
fb59d770ba | ||
|
|
ad99934b4c | ||
|
|
2a0be68cb3 | ||
|
|
a7da7226ac | ||
|
|
505332e680 | ||
|
|
ada3330403 | ||
|
|
e0143e081c | ||
|
|
84d3d544ef | ||
|
|
30c9c56d6c | ||
|
|
dfe0a9002a | ||
|
|
3eea9e3967 | ||
|
|
69051c4197 | ||
|
|
5b5156356a | ||
|
|
fdd1422d31 | ||
|
|
c82253e479 | ||
|
|
b059c6f630 | ||
|
|
f03522ad9e | ||
|
|
42e62bd1b4 | ||
|
|
2ff9c385c3 | ||
|
|
804b80ac7b | ||
|
|
25eff13d35 | ||
|
|
415c90d9d0 | ||
|
|
97a49185c5 | ||
|
|
e68d4c897b | ||
|
|
76640cbad6 | ||
|
|
c2e5e569a0 | ||
|
|
d5384a110d | ||
|
|
4e9f1a08fe | ||
|
|
e20e38d530 | ||
|
|
79f2779574 | ||
|
|
23251d9e4d | ||
|
|
e2652b9cc5 | ||
|
|
beca677276 | ||
|
|
1202dc1dd3 | ||
|
|
e2ddc82637 | ||
|
|
f269b66f39 | ||
|
|
850284abee | ||
|
|
b3dec74c6a | ||
|
|
a6a6171225 | ||
|
|
cf77740ab1 | ||
|
|
836aa5a1e6 | ||
|
|
453d484a96 | ||
|
|
3957880370 | ||
|
|
840bfa87e8 | ||
|
|
b2c43ee2d9 | ||
|
|
10878c4d0e | ||
|
|
f80be2d1f4 | ||
|
|
7cb940b179 | ||
|
|
01c85e0420 | ||
|
|
41f36a6d92 | ||
|
|
2aff5384ec | ||
|
|
e592891121 | ||
|
|
e263a10fdd | ||
|
|
db8b6c59bc | ||
|
|
e1f3da2c2d | ||
|
|
ae255d6328 | ||
|
|
c283329581 | ||
|
|
f85e344ed4 | ||
|
|
aece8056f8 | ||
|
|
5d6ccafac9 | ||
|
|
1bd60ac343 | ||
|
|
ee22706182 | ||
|
|
013ae1172a | ||
|
|
069276473f | ||
|
|
a8289d4fd5 | ||
|
|
2ed653f433 | ||
|
|
b724e080b0 | ||
|
|
9de95528ef | ||
|
|
3cab94f130 | ||
|
|
b2cf38bbf4 | ||
|
|
6c7bfb37c1 | ||
|
|
6edd2b7f9f | ||
|
|
b47caf6642 | ||
|
|
67476e7e09 | ||
|
|
3bafada5a6 | ||
|
|
0743610487 | ||
|
|
bc7d39a16b | ||
|
|
618146cc63 | ||
|
|
4acd39b6a4 | ||
|
|
72056c26a8 | ||
|
|
fbab41668d | ||
|
|
14b5c96c58 | ||
|
|
d48d5c7cbd | ||
|
|
3d59ab5c55 | ||
|
|
12cb0ea633 | ||
|
|
c5e959fe9c | ||
|
|
13d01dd690 | ||
|
|
4e94e26ef8 | ||
|
|
8738f2e1c9 | ||
|
|
508b3ab8de | ||
|
|
8f1f6a89f1 | ||
|
|
523d89a2d9 | ||
|
|
8d45d5c4a7 | ||
|
|
437edb1f01 | ||
|
|
ac57edf7d3 | ||
|
|
3a2fec1ffb | ||
|
|
2fc2d9b8ad | ||
|
|
e2cf17e106 | ||
|
|
839b653f6b | ||
|
|
e5c7f3e542 | ||
|
|
d2bbc3ef3e | ||
|
|
96b6cfd810 | ||
|
|
b3cf5f0caa | ||
|
|
072948e827 | ||
|
|
8ef80fb669 | ||
|
|
4de1083096 | ||
|
|
e5647f7441 | ||
|
|
f9318f82ae | ||
|
|
4f78d14471 | ||
|
|
d41771b4b1 | ||
|
|
0c7afb389d | ||
|
|
77ed46242f | ||
|
|
acbdeb833f | ||
|
|
2493d5e0d3 | ||
|
|
820d66b42e | ||
|
|
8fb018de47 | ||
|
|
7987b1a681 | ||
|
|
750526b138 | ||
|
|
6b5c365cb6 | ||
|
|
61cfa275f8 | ||
|
|
1a5c0b3ae2 | ||
|
|
740c954679 | ||
|
|
7319bcb577 | ||
|
|
3750a06d4f | ||
|
|
c79c8dae19 | ||
|
|
1e4e2c81e9 | ||
|
|
c8b1fbd9e6 | ||
|
|
dc24fe60be | ||
|
|
86b33b2a10 | ||
|
|
1450a7b408 | ||
|
|
f7af9b8745 | ||
|
|
87a09d2bb3 | ||
|
|
c5283903be | ||
|
|
cfd6ec0dcb | ||
|
|
a59aaf48f2 | ||
|
|
c40d832e5e | ||
|
|
23f901c29a | ||
|
|
c06d1ec73d | ||
|
|
2fc6d1d210 | ||
|
|
49c6c909f8 | ||
|
|
334106a6d0 | ||
|
|
ffd6b27f4b | ||
|
|
860b6bac75 | ||
|
|
9c3729b4ba | ||
|
|
1174e5a127 | ||
|
|
fe802a97a2 | ||
|
|
eba2455ad3 | ||
|
|
60f1750c96 | ||
|
|
6a198acd2f | ||
|
|
40968c78a8 | ||
|
|
e03892b130 | ||
|
|
844bbcdb1d | ||
|
|
63267d3616 | ||
|
|
d77cd79262 | ||
|
|
6e97f7fbd8 | ||
|
|
de04941ddb | ||
|
|
2de80fdc3e | ||
|
|
832884a7ea | ||
|
|
4bc86c7e9d | ||
|
|
cd2938e2d0 | ||
|
|
1d11ddc235 | ||
|
|
f37a09d9fe | ||
|
|
5ed80a5ba9 | ||
|
|
978bc1352e | ||
|
|
ab669ad055 | ||
|
|
443f9ed5f1 | ||
|
|
d72f4d7959 | ||
|
|
4c23c2ddec | ||
|
|
e0333c0756 | ||
|
|
066ae71581 | ||
|
|
2898c94f08 | ||
|
|
fc0df994b8 | ||
|
|
c5a4e423c6 | ||
|
|
98e5692a40 | ||
|
|
949f170b48 | ||
|
|
576e68eef0 | ||
|
|
63af463a9a | ||
|
|
b20eda9996 | ||
|
|
88832daae4 | ||
|
|
3aa2df29f5 | ||
|
|
42d0ee7431 | ||
|
|
bc293cf251 | ||
|
|
15e128f321 | ||
|
|
56757866f3 | ||
|
|
c3f3c156b1 | ||
|
|
62e8955b39 | ||
|
|
fad3789f64 | ||
|
|
a0b85d060b | ||
|
|
fd5d3f551b | ||
|
|
019014070d | ||
|
|
97f5dff656 | ||
|
|
0d28802485 | ||
|
|
254774f7a3 | ||
|
|
6f1e624465 | ||
|
|
2dcd03d17d | ||
|
|
ffcb7aa6ed | ||
|
|
9350b5a533 | ||
|
|
8cb2c7a89c | ||
|
|
50bdaa6d1a | ||
|
|
20a4cf1290 | ||
|
|
fc092d0df4 | ||
|
|
51bb2909c3 | ||
|
|
cab0cd55b3 | ||
|
|
4f579639c6 | ||
|
|
c5b68ef386 | ||
|
|
95dc4e4dc5 | ||
|
|
dc35138356 | ||
|
|
08617f7700 | ||
|
|
cfecf3c5b1 | ||
|
|
831100b657 | ||
|
|
f296a2f58a | ||
|
|
18a0120fc1 | ||
|
|
aae557e8a1 | ||
|
|
0f92c4b85b | ||
|
|
217df1761d | ||
|
|
d355741462 | ||
|
|
7b6ed4f16e | ||
|
|
c5a682e9d9 | ||
|
|
b4fa105555 | ||
|
|
e1aef6f0db | ||
|
|
6f35d2b52d | ||
|
|
197f57c050 | ||
|
|
c74fa7546b | ||
|
|
0261472ecd | ||
|
|
233ef8752d | ||
|
|
afd9e7546f | ||
|
|
8b1532d691 | ||
|
|
a887c29e06 | ||
|
|
7114b72be8 | ||
|
|
1c1a5958bc | ||
|
|
b7b5bcbd85 | ||
|
|
9638f0ef2b | ||
|
|
92ab345daf | ||
|
|
79dd4d707b | ||
|
|
a3a733fa91 | ||
|
|
7a9b014f72 | ||
|
|
61b4a98356 | ||
|
|
46db69b304 | ||
|
|
a0be41322d | ||
|
|
39d30718e2 | ||
|
|
05f29988f4 | ||
|
|
d7903de51c | ||
|
|
0e31cc9ff8 | ||
|
|
32280a11aa | ||
|
|
a2f9d2f89c | ||
|
|
5fc5355b96 | ||
|
|
30c73e6b35 | ||
|
|
7a6b88c791 | ||
|
|
9c42124fbc | ||
|
|
0378b15412 | ||
|
|
3f86369604 | ||
|
|
cc99d92116 | ||
|
|
f880975438 | ||
|
|
daa8db4d95 | ||
|
|
9ff39e2d1b | ||
|
|
9d70c5d13f | ||
|
|
a9a82919e7 | ||
|
|
723ed07642 | ||
|
|
86b531aea6 | ||
|
|
781a420593 | ||
|
|
08f709c2a2 | ||
|
|
a849f6e21e | ||
|
|
6ff8387d56 | ||
|
|
2af9ff9c33 | ||
|
|
01905cad2f | ||
|
|
31f5055287 | ||
|
|
ce9239af83 | ||
|
|
50de88417c | ||
|
|
2701f94491 | ||
|
|
58260e4f0a | ||
|
|
a01869bb20 | ||
|
|
3a92615f23 | ||
|
|
eca8db7405 | ||
|
|
58c4cfc0d7 | ||
|
|
ab52a4db75 | ||
|
|
c8d3a8c0f5 | ||
|
|
aab88eee3e | ||
|
|
d9f4c83567 | ||
|
|
b96dd366ce | ||
|
|
597ec83af7 | ||
|
|
e802bdd186 | ||
|
|
3a949bb298 | ||
|
|
13c9d041d9 | ||
|
|
1e920dd0d8 | ||
|
|
09536f402e | ||
|
|
581f26b7a0 | ||
|
|
0418a2f70a | ||
|
|
5e3338744c | ||
|
|
da3762700c | ||
|
|
2c9fccd8ba | ||
|
|
286c4fa640 | ||
|
|
a144e002db | ||
|
|
553dabaa08 | ||
|
|
55d0d32c77 | ||
|
|
1f93745eef | ||
|
|
e3a02dd5f6 | ||
|
|
153733414f | ||
|
|
ac535f0ce9 | ||
|
|
3886529787 | ||
|
|
d2cd713b89 | ||
|
|
6b378e1669 | ||
|
|
a4fc30bbe4 | ||
|
|
b4b0e4424d | ||
|
|
f3bdcc2a84 | ||
|
|
19901c14c9 | ||
|
|
714d686e50 | ||
|
|
094dc1dee6 | ||
|
|
cdcf424ba5 | ||
|
|
2a2b884e32 | ||
|
|
c1e00f4daa | ||
|
|
0a22aab6bb | ||
|
|
43c6d1a518 | ||
|
|
090219814e | ||
|
|
510dc60bf0 | ||
|
|
12d520a366 | ||
|
|
a06a527fe6 | ||
|
|
9a7681535f | ||
|
|
8e1a612b3b | ||
|
|
21085bf2be | ||
|
|
8e9413829d | ||
|
|
8208f878ff | ||
|
|
a7130649cd | ||
|
|
b2d9ffa4ca | ||
|
|
cc4f13a862 | ||
|
|
60681baf80 | ||
|
|
ea6049078a | ||
|
|
d83e8c56b2 | ||
|
|
e0ade62e38 | ||
|
|
c78b921412 | ||
|
|
9e9e415c5f | ||
|
|
0692e5eb78 | ||
|
|
3fa5eec07b | ||
|
|
ab1bf1af19 | ||
|
|
15e0861e82 | ||
|
|
aa493a25f8 | ||
|
|
1c2915f74b | ||
|
|
391b3b67cb | ||
|
|
0361c50503 | ||
|
|
517a3071cf | ||
|
|
0e30e705c5 | ||
|
|
940df7563b | ||
|
|
f390872944 | ||
|
|
cfd18d4e03 | ||
|
|
6c73439e7f | ||
|
|
2389e2c438 | ||
|
|
c2341ca8e3 | ||
|
|
3b810ea8da | ||
|
|
f85d6aeecd | ||
|
|
a13762b05f | ||
|
|
dd5a0a1f26 | ||
|
|
a6ad0b0ec8 | ||
|
|
077e20f7ae | ||
|
|
73c6d2e44c | ||
|
|
d7a13ceb10 | ||
|
|
6eadd6657d | ||
|
|
0c890a110d | ||
|
|
0f420baaba | ||
|
|
b32d96fc24 | ||
|
|
cfc9e18749 | ||
|
|
7178218821 | ||
|
|
25d6d08329 | ||
|
|
9bf4c754c8 | ||
|
|
79b02db156 | ||
|
|
e55dd7233d | ||
|
|
3ba969ad58 | ||
|
|
f93cb0a6ba | ||
|
|
e23cfd22ca | ||
|
|
9eef60754d | ||
|
|
0d1b022ea0 | ||
|
|
aca3772f7d | ||
|
|
569815b5ad | ||
|
|
80b696ce25 | ||
|
|
ab7570b7e5 | ||
|
|
c87f8c6f00 | ||
|
|
c5c4de885b | ||
|
|
a970bcc56d | ||
|
|
5e2d822509 | ||
|
|
6be1475882 | ||
|
|
43f05d1de1 | ||
|
|
26bb028ec4 | ||
|
|
1637f0aeaf | ||
|
|
353f64caf8 | ||
|
|
5afb00a7f4 | ||
|
|
b0ec0f545e | ||
|
|
7088513da9 | ||
|
|
8908d4ee8f | ||
|
|
8133970944 | ||
|
|
dac7ede911 | ||
|
|
b052498348 | ||
|
|
d62de6c8e5 | ||
|
|
d37cc9a5d0 | ||
|
|
c7062d8be7 | ||
|
|
1435e30ad5 | ||
|
|
3799aabc46 | ||
|
|
4b2901704c | ||
|
|
e5f7af9e9f | ||
|
|
6fc136fcb8 | ||
|
|
b2ff0bda32 | ||
|
|
ff42d7b5ed | ||
|
|
35a4cae2f6 | ||
|
|
a76cafecb0 | ||
|
|
715ecc31c8 | ||
|
|
09145674ec | ||
|
|
11eebddb79 | ||
|
|
7d7417af29 | ||
|
|
6edb6e0b09 | ||
|
|
e057575661 | ||
|
|
b7b5eeb92b | ||
|
|
85731053fd | ||
|
|
9f3eb9e077 | ||
|
|
5ac8dbfceb | ||
|
|
f4f2301e5b | ||
|
|
7888336524 | ||
|
|
b8c2e02c67 | ||
|
|
a9e9efbd23 | ||
|
|
2f175e6d85 | ||
|
|
df817a858b | ||
|
|
4a73059ed3 | ||
|
|
552615525c | ||
|
|
25e408fd2a | ||
|
|
375a6f67ae | ||
|
|
01095799e8 | ||
|
|
ead8d82a84 | ||
|
|
2c229c6403 | ||
|
|
5fb78a375d | ||
|
|
8fcad571f5 | ||
|
|
53d7e667dd | ||
|
|
7395716476 | ||
|
|
c068b6a885 | ||
|
|
02d28c5908 | ||
|
|
90d0d24d1a | ||
|
|
6aab14f9cf | ||
|
|
163dbdca34 | ||
|
|
dcc99a2644 | ||
|
|
f94951a51b | ||
|
|
f5297cf386 | ||
|
|
9f7fd16882 | ||
|
|
5296ab1f87 | ||
|
|
e42c14f2cb | ||
|
|
4ef10fd6c3 | ||
|
|
4c0d0e226b | ||
|
|
094caaa03e | ||
|
|
ce51553d29 | ||
|
|
f41fc21274 | ||
|
|
1f49b77529 | ||
|
|
a0012f8c48 | ||
|
|
4b1c3ad7ac | ||
|
|
a063803224 | ||
|
|
63c7fd90a5 | ||
|
|
c9c02c7c85 | ||
|
|
bc7ef1937e | ||
|
|
75b63c5b4c | ||
|
|
625191d20a | ||
|
|
1417c7e828 | ||
|
|
a4bbc68945 | ||
|
|
2d7a591c61 | ||
|
|
9ef79d6c6b | ||
|
|
448a5e1c9c | ||
|
|
7be75adc3f | ||
|
|
fafee7cf61 | ||
|
|
16aa23e454 | ||
|
|
a4d5c5414d | ||
|
|
b104e3595c | ||
|
|
5a06dd1ed1 | ||
|
|
27fe55efe1 | ||
|
|
9089b242ba | ||
|
|
98e511d236 | ||
|
|
93784d3804 | ||
|
|
d29fde0bf3 | ||
|
|
8326925fe8 | ||
|
|
a924b636a4 | ||
|
|
3526ed975c | ||
|
|
d0faec3cc0 | ||
|
|
661a5ce332 | ||
|
|
b289aa3548 | ||
|
|
4ed521162e | ||
|
|
8865d05b4c | ||
|
|
4df46737ef | ||
|
|
09ac547a80 | ||
|
|
c1bbaf07a4 | ||
|
|
73a081d806 | ||
|
|
e1df414f8b | ||
|
|
cefef3b62d | ||
|
|
bd4ee60d1e | ||
|
|
f6a9eec23a | ||
|
|
5742d0836e | ||
|
|
0555223797 | ||
|
|
de93efb304 | ||
|
|
6856033d3c | ||
|
|
0735165ef3 | ||
|
|
1aa5462f36 | ||
|
|
f83514418e | ||
|
|
3c13e8e8b9 | ||
|
|
de0955b8ed | ||
|
|
82af75b853 | ||
|
|
d3ce4f815d | ||
|
|
85bf9203ed | ||
|
|
e82ab87f1c | ||
|
|
db12f75681 | ||
|
|
3763169978 | ||
|
|
36a8c431f5 | ||
|
|
5a67431daa | ||
|
|
c4e92b3004 | ||
|
|
2d90e8a2de | ||
|
|
4dacb89da6 | ||
|
|
c552d74746 | ||
|
|
2697c2d869 | ||
|
|
4a950abf2e | ||
|
|
7f10f4eea1 | ||
|
|
5c93260eec | ||
|
|
485d9c133a | ||
|
|
891d9aeee9 | ||
|
|
51f0d6d409 | ||
|
|
80374be724 | ||
|
|
619bf561da | ||
|
|
13c15d0222 | ||
|
|
3d31bccaf6 | ||
|
|
3959bf34ee | ||
|
|
1897ed38df | ||
|
|
126c4efb2c | ||
|
|
9c923ae418 | ||
|
|
7d0bc2bd5a | ||
|
|
0c70ae44c3 | ||
|
|
024dc4a4c9 | ||
|
|
e3567ff31b | ||
|
|
97842ca804 | ||
|
|
d14799a9fa | ||
|
|
e534221245 | ||
|
|
4acfec901e | ||
|
|
a981a8a153 | ||
|
|
11e1c60cd3 | ||
|
|
fe7baae9f7 | ||
|
|
da64113b9a | ||
|
|
fb76cb7a78 | ||
|
|
1bd69b4490 | ||
|
|
62d51d82ea | ||
|
|
6ddc554965 | ||
|
|
5a6fc77751 | ||
|
|
733db826ec | ||
|
|
6643156df6 | ||
|
|
6022f2bcf8 | ||
|
|
b890492dc0 | ||
|
|
6ea108f01d | ||
|
|
628bed1f5a | ||
|
|
4c0e3aa097 | ||
|
|
631e334a3f | ||
|
|
8f4d92eba2 | ||
|
|
2f4193757e | ||
|
|
cba64988df | ||
|
|
17e6fce486 | ||
|
|
05fb3f2d75 | ||
|
|
af6360b273 | ||
|
|
043a47a9c0 | ||
|
|
23e424911c | ||
|
|
a5fbeaa3d3 | ||
|
|
8aeb4b04bd | ||
|
|
f3b07495f6 | ||
|
|
70f89462a8 | ||
|
|
bbc7f474c3 | ||
|
|
26fe30685a | ||
|
|
7bdd27f7e2 | ||
|
|
96ec4aeda0 | ||
|
|
cce65d41b8 | ||
|
|
a44d46e535 | ||
|
|
4f16d17d21 | ||
|
|
759bb0eb62 | ||
|
|
d7aa71aa70 | ||
|
|
32207ad722 | ||
|
|
8a32ad206a | ||
|
|
16bd2ed967 | ||
|
|
393b12a37f | ||
|
|
d1332f6c24 | ||
|
|
f36fa088f8 | ||
|
|
bb63103183 | ||
|
|
7760db7563 | ||
|
|
0ea1e67ce7 | ||
|
|
587b52dcd4 | ||
|
|
efcdf2fd42 | ||
|
|
010a05df48 | ||
|
|
58d565a882 | ||
|
|
b655b07f20 | ||
|
|
afb59fa5c0 | ||
|
|
cb4b86512d | ||
|
|
49f919a4fc | ||
|
|
4a9127f9a6 | ||
|
|
c4a670c8c8 | ||
|
|
a26e2c064a | ||
|
|
3889d0f0a0 | ||
|
|
4e81fb20b9 | ||
|
|
dfba52b834 | ||
|
|
f665e42e2a | ||
|
|
560cc66a36 | ||
|
|
d08953b72b | ||
|
|
34e4ac2398 | ||
|
|
3dbaa3c2d9 | ||
|
|
613d82e12f | ||
|
|
4f2fa173c9 | ||
|
|
d36e635e60 | ||
|
|
e86d21ea15 | ||
|
|
b6fda118b9 | ||
|
|
2c607e5562 | ||
|
|
95fce2395a | ||
|
|
0f0dcd9035 | ||
|
|
ce291c253b | ||
|
|
e85c6ad236 | ||
|
|
df16cdcf31 | ||
|
|
00303858df | ||
|
|
6f54a7b7d8 | ||
|
|
fba8bfc0d0 | ||
|
|
4db4f21d16 | ||
|
|
abf9ef0244 | ||
|
|
22ad81fb57 | ||
|
|
923c5462a2 | ||
|
|
753b3d1c28 | ||
|
|
b9046edb85 | ||
|
|
7932eba733 | ||
|
|
5ba9c82922 | ||
|
|
fc48ce7073 | ||
|
|
8b9a84b568 | ||
|
|
cc4e6a25f6 | ||
|
|
17923863de | ||
|
|
32efea5e38 | ||
|
|
87a2c1d27d | ||
|
|
c581d67bba | ||
|
|
1865e0df7c | ||
|
|
308ae1f155 | ||
|
|
2b54cee4aa | ||
|
|
ba47f89702 | ||
|
|
0ea32faf3d | ||
|
|
7be0736154 | ||
|
|
97bf12734a | ||
|
|
4bccd692e5 | ||
|
|
07f8e6bbfc | ||
|
|
15c7a05879 | ||
|
|
82e76b2c0c | ||
|
|
d6757b7af6 | ||
|
|
b380a02d09 | ||
|
|
64980fed59 | ||
|
|
7df8c0ef82 | ||
|
|
28fe73640b | ||
|
|
7cfe247b2e | ||
|
|
332b4171c0 | ||
|
|
e5544b8c86 | ||
|
|
38e5e7f616 | ||
|
|
a595346769 | ||
|
|
8dace802dc | ||
|
|
ac6259dfe8 | ||
|
|
f801cc953b | ||
|
|
c117048fde | ||
|
|
73fd508ccf | ||
|
|
7cc972969f | ||
|
|
734c32b970 | ||
|
|
fa862e6814 | ||
|
|
d333d2e6eb | ||
|
|
3b78a018aa | ||
|
|
cc581d21f0 | ||
|
|
dca60888ce | ||
|
|
b2465c7a69 | ||
|
|
14477c7f51 | ||
|
|
f0ee3d26a7 | ||
|
|
2e87202b3b | ||
|
|
1024b55f99 | ||
|
|
9ba7b678fe | ||
|
|
a8c8e6b78a | ||
|
|
ce107086e7 | ||
|
|
49d1449d2b | ||
|
|
2f6789e54d | ||
|
|
f2893e5701 | ||
|
|
870410c9d5 | ||
|
|
30bca30f20 | ||
|
|
80f1d5f63d | ||
|
|
76d4fa9f2b | ||
|
|
e17c9d9978 | ||
|
|
e8883e20cd | ||
|
|
af4d588f64 | ||
|
|
4f0a4a1a2d | ||
|
|
7f7a1b48ed | ||
|
|
f094662f5e | ||
|
|
e2fc03e561 | ||
|
|
3987b4b714 | ||
|
|
e889a58724 | ||
|
|
1638994436 | ||
|
|
ff99492481 | ||
|
|
a65af7a2f5 | ||
|
|
6ba48c58e8 | ||
|
|
3b4f481ca4 | ||
|
|
548e93b2d3 | ||
|
|
76eb9b32b3 | ||
|
|
0ac4cfa9b1 | ||
|
|
dc34393b8a | ||
|
|
023a865e1e | ||
|
|
d2a7ec1add | ||
|
|
564ee5399c | ||
|
|
2518a2ab16 | ||
|
|
df3e8853ae | ||
|
|
a0b7ff60b8 | ||
|
|
97383716e6 | ||
|
|
f788117b3e | ||
|
|
6784335e2c | ||
|
|
c5c9dc5f6d | ||
|
|
819e24ddde | ||
|
|
313ed4feeb | ||
|
|
5157fa9233 | ||
|
|
774b96495f | ||
|
|
ea4c2c9e7d | ||
|
|
b42bbf1b6f | ||
|
|
c768febac6 | ||
|
|
0449d30423 | ||
|
|
f17dfb0ebe | ||
|
|
13273412d1 | ||
|
|
f198b1d032 | ||
|
|
9512a43d44 | ||
|
|
50db128ff1 | ||
|
|
5eaf7d0517 | ||
|
|
760b01912a | ||
|
|
8fd90410f1 | ||
|
|
4c331206f1 | ||
|
|
f62e789173 | ||
|
|
02181c017a | ||
|
|
7fece8f431 | ||
|
|
bd7a165318 | ||
|
|
4114365017 | ||
|
|
aace25ac2b | ||
|
|
697f1186c0 | ||
|
|
55bee7a393 | ||
|
|
c151b58acd | ||
|
|
ef73452abe | ||
|
|
ff73090ad2 | ||
|
|
b63adcbac7 | ||
|
|
f492d5f61d | ||
|
|
4ac386d0fe | ||
|
|
4753bd4519 | ||
|
|
76815cf2be | ||
|
|
936d147b4b | ||
|
|
20090306f6 | ||
|
|
a1a7beb12e | ||
|
|
9f2847e86c | ||
|
|
44d8224a3b | ||
|
|
5ba438af80 | ||
|
|
3d6b51089c | ||
|
|
f817663f11 | ||
|
|
bf5ea691cf | ||
|
|
91578757ff | ||
|
|
48e206d983 | ||
|
|
bed6f4748e | ||
|
|
eac87b4764 | ||
|
|
ee2b523b31 | ||
|
|
88bd0674ed | ||
|
|
4ff2b0114f | ||
|
|
e7cc6649eb | ||
|
|
4d19d344b6 | ||
|
|
e7bc2beea0 | ||
|
|
cd416a3135 | ||
|
|
2a0e8e24ec | ||
|
|
c75300dc43 | ||
|
|
8d36b362d1 | ||
|
|
4c57fae726 | ||
|
|
2d1b5b0769 | ||
|
|
1d7646f31f | ||
|
|
1a19746904 | ||
|
|
e7fec6e659 | ||
|
|
c45e271b3e | ||
|
|
422d483baf | ||
|
|
c56f771c81 | ||
|
|
89923b84b1 | ||
|
|
c936f07a1e | ||
|
|
aea2fbf82d | ||
|
|
7a1ea42271 | ||
|
|
58438f4e5b | ||
|
|
f6d18e81e9 | ||
|
|
e8f3050e27 | ||
|
|
cbe63ec418 | ||
|
|
94899981d3 | ||
|
|
6a4dae3a9d | ||
|
|
57c6b49d1a | ||
|
|
eae7424984 | ||
|
|
e394cec194 | ||
|
|
818492387a | ||
|
|
31cb24f48d | ||
|
|
590d8d3d3e | ||
|
|
6025e498f2 | ||
|
|
09cad814cd | ||
|
|
c75a2b1eed |
@@ -1,14 +0,0 @@
|
||||
# Root editor config file
|
||||
root = true
|
||||
|
||||
# Common settings
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
charset = utf-8
|
||||
|
||||
# python, js indentation settings
|
||||
[{*.py,*.js}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
39
.eslintrc
39
.eslintrc
@@ -4,10 +4,6 @@
|
||||
"node": true,
|
||||
"es6": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 9,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"rules": {
|
||||
"indent": [
|
||||
@@ -15,14 +11,6 @@
|
||||
"tab",
|
||||
{ "SwitchCase": 1 }
|
||||
],
|
||||
"brace-style": [
|
||||
"error",
|
||||
"1tbs"
|
||||
],
|
||||
"space-unary-ops": [
|
||||
"error",
|
||||
{ "words": true }
|
||||
],
|
||||
"linebreak-style": [
|
||||
"error",
|
||||
"unix"
|
||||
@@ -52,17 +40,19 @@
|
||||
"no-control-regex": [
|
||||
"off"
|
||||
],
|
||||
"space-before-blocks": "warn",
|
||||
"keyword-spacing": "warn",
|
||||
"comma-spacing": "warn",
|
||||
"key-spacing": "warn"
|
||||
"spaced-comment": [
|
||||
"warn"
|
||||
],
|
||||
"no-trailing-spaces": [
|
||||
"warn"
|
||||
]
|
||||
},
|
||||
"root": true,
|
||||
"globals": {
|
||||
"frappe": true,
|
||||
"Vue": true,
|
||||
"erpnext": true,
|
||||
"hub": true,
|
||||
|
||||
"$": true,
|
||||
"jQuery": true,
|
||||
"moment": true,
|
||||
@@ -92,7 +82,6 @@
|
||||
"cur_page": true,
|
||||
"cur_list": true,
|
||||
"cur_tree": true,
|
||||
"cur_pos": true,
|
||||
"msg_dialog": true,
|
||||
"is_null": true,
|
||||
"in_list": true,
|
||||
@@ -144,18 +133,6 @@
|
||||
"get_server_fields": true,
|
||||
"set_multiple": true,
|
||||
"QUnit": true,
|
||||
"Chart": true,
|
||||
"Cypress": true,
|
||||
"cy": true,
|
||||
"describe": true,
|
||||
"expect": true,
|
||||
"it": true,
|
||||
"context": true,
|
||||
"before": true,
|
||||
"beforeEach": true,
|
||||
"onScan": true,
|
||||
"html2canvas": true,
|
||||
"extend_cscript": true,
|
||||
"localforage": true
|
||||
"Chart": true
|
||||
}
|
||||
}
|
||||
|
||||
37
.flake8
37
.flake8
@@ -1,37 +0,0 @@
|
||||
[flake8]
|
||||
ignore =
|
||||
E121,
|
||||
E126,
|
||||
E127,
|
||||
E128,
|
||||
E203,
|
||||
E225,
|
||||
E226,
|
||||
E231,
|
||||
E241,
|
||||
E251,
|
||||
E261,
|
||||
E265,
|
||||
E302,
|
||||
E303,
|
||||
E305,
|
||||
E402,
|
||||
E501,
|
||||
E741,
|
||||
W291,
|
||||
W292,
|
||||
W293,
|
||||
W391,
|
||||
W503,
|
||||
W504,
|
||||
F403,
|
||||
B007,
|
||||
B950,
|
||||
W191,
|
||||
E124, # closing bracket, irritating while writing QB code
|
||||
E131, # continuation line unaligned for hanging indent
|
||||
E123, # closing bracket does not match indentation of opening bracket's line
|
||||
E101, # ensured by use of black
|
||||
|
||||
max-line-length = 200
|
||||
exclude=.github/helper/semgrep_rules
|
||||
@@ -1,22 +0,0 @@
|
||||
# Since version 2.23 (released in August 2019), git-blame has a feature
|
||||
# to ignore or bypass certain commits.
|
||||
#
|
||||
# This file contains a list of commits that are not likely what you
|
||||
# are looking for in a blame, such as mass reformatting or renaming.
|
||||
# You can set this file as a default ignore file for blame by running
|
||||
# the following command.
|
||||
#
|
||||
# $ git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
|
||||
# This commit just changes spaces to tabs for indentation in some files
|
||||
5f473611bd6ed57703716244a054d3fb5ba9cd23
|
||||
|
||||
# Whitespace trimming throughout codebase
|
||||
9bb69e711a5da43aaf8c8ecb5601aeffd89dbe5a
|
||||
f0bcb753fb7ebbb64bb0d6906d431d002f0f7d8f
|
||||
|
||||
# imports cleanup
|
||||
4b2be2999f2203493b49bf74c5b440d49e38b5e3
|
||||
|
||||
# formatting with black
|
||||
c07713b860505211db2af685e2e950bf5dd7dd3a
|
||||
47
.github/ISSUE_TEMPLATE/bug_report.md
vendored
47
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,47 +0,0 @@
|
||||
---
|
||||
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.
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
5
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Community Forum
|
||||
url: https://discuss.erpnext.com/
|
||||
about: For general QnA, discussions and community help.
|
||||
28
.github/ISSUE_TEMPLATE/feature_request.md
vendored
28
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,28 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
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~~ => [stackoverflow](https://stackoverflow.com/questions/tagged/frappe) tagged under `frappe`
|
||||
|
||||
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,33 +1,2 @@
|
||||
<!--
|
||||
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 -->
|
||||
|
||||
73
.github/helper/.flake8_strict
vendored
73
.github/helper/.flake8_strict
vendored
@@ -1,73 +0,0 @@
|
||||
[flake8]
|
||||
ignore =
|
||||
B007,
|
||||
B009,
|
||||
B010,
|
||||
B950,
|
||||
E101,
|
||||
E111,
|
||||
E114,
|
||||
E116,
|
||||
E117,
|
||||
E121,
|
||||
E122,
|
||||
E123,
|
||||
E124,
|
||||
E125,
|
||||
E126,
|
||||
E127,
|
||||
E128,
|
||||
E131,
|
||||
E201,
|
||||
E202,
|
||||
E203,
|
||||
E211,
|
||||
E221,
|
||||
E222,
|
||||
E223,
|
||||
E224,
|
||||
E225,
|
||||
E226,
|
||||
E228,
|
||||
E231,
|
||||
E241,
|
||||
E242,
|
||||
E251,
|
||||
E261,
|
||||
E262,
|
||||
E265,
|
||||
E266,
|
||||
E271,
|
||||
E272,
|
||||
E273,
|
||||
E274,
|
||||
E301,
|
||||
E302,
|
||||
E303,
|
||||
E305,
|
||||
E306,
|
||||
E402,
|
||||
E501,
|
||||
E502,
|
||||
E701,
|
||||
E702,
|
||||
E703,
|
||||
E741,
|
||||
F403,
|
||||
W191,
|
||||
W291,
|
||||
W292,
|
||||
W293,
|
||||
W391,
|
||||
W503,
|
||||
W504,
|
||||
E711,
|
||||
E129,
|
||||
F841,
|
||||
E713,
|
||||
E712,
|
||||
B023
|
||||
|
||||
|
||||
max-line-length = 200
|
||||
exclude=.github/helper/semgrep_rules,test_*.py
|
||||
54
.github/helper/documentation.py
vendored
54
.github/helper/documentation.py
vendored
@@ -1,54 +0,0 @@
|
||||
import sys
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import requests
|
||||
|
||||
docs_repos = [
|
||||
"frappe_docs",
|
||||
"erpnext_documentation",
|
||||
"erpnext_com",
|
||||
"frappe_io",
|
||||
]
|
||||
|
||||
|
||||
def uri_validator(x):
|
||||
result = urlparse(x)
|
||||
return all([result.scheme, result.netloc, result.path])
|
||||
|
||||
def docs_link_exists(body):
|
||||
for line in body.splitlines():
|
||||
for word in line.split():
|
||||
if word.startswith('http') and uri_validator(word):
|
||||
parsed_url = urlparse(word)
|
||||
if parsed_url.netloc == "github.com":
|
||||
parts = parsed_url.path.split('/')
|
||||
if len(parts) == 5 and parts[1] == "frappe" and parts[2] in docs_repos:
|
||||
return True
|
||||
elif parsed_url.netloc == "docs.erpnext.com":
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pr = sys.argv[1]
|
||||
response = requests.get("https://api.github.com/repos/frappe/erpnext/pulls/{}".format(pr))
|
||||
|
||||
if response.ok:
|
||||
payload = response.json()
|
||||
title = (payload.get("title") or "").lower().strip()
|
||||
head_sha = (payload.get("head") or {}).get("sha")
|
||||
body = (payload.get("body") or "").lower()
|
||||
|
||||
if (title.startswith("feat")
|
||||
and head_sha
|
||||
and "no-docs" not in body
|
||||
and "backport" not in body
|
||||
):
|
||||
if docs_link_exists(body):
|
||||
print("Documentation Link Found. You're Awesome! 🎉")
|
||||
|
||||
else:
|
||||
print("Documentation Link Not Found! ⚠️")
|
||||
sys.exit(1)
|
||||
|
||||
else:
|
||||
print("Skipping documentation checks... 🏃")
|
||||
48
.github/helper/install.sh
vendored
48
.github/helper/install.sh
vendored
@@ -1,48 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Check for merge conflicts before proceeding
|
||||
python -m compileall -f "${GITHUB_WORKSPACE}"
|
||||
if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
|
||||
then echo "Found merge conflicts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd ~ || exit
|
||||
|
||||
sudo apt update && sudo apt install redis-server libcups2-dev
|
||||
|
||||
pip install frappe-bench
|
||||
|
||||
git clone https://github.com/frappe/frappe --branch "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}" --depth 1
|
||||
bench init --skip-assets --frappe-path ~/frappe --python "$(which python)" frappe-bench
|
||||
|
||||
mkdir ~/frappe-bench/sites/test_site
|
||||
cp -r "${GITHUB_WORKSPACE}/.github/helper/site_config.json" ~/frappe-bench/sites/test_site/
|
||||
|
||||
mysql --host 127.0.0.1 --port 3306 -u root -e "SET GLOBAL character_set_server = 'utf8mb4'"
|
||||
mysql --host 127.0.0.1 --port 3306 -u root -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"
|
||||
|
||||
mysql --host 127.0.0.1 --port 3306 -u root -e "CREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe'"
|
||||
mysql --host 127.0.0.1 --port 3306 -u root -e "CREATE DATABASE test_frappe"
|
||||
mysql --host 127.0.0.1 --port 3306 -u root -e "GRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost'"
|
||||
|
||||
mysql --host 127.0.0.1 --port 3306 -u root -e "UPDATE mysql.user SET Password=PASSWORD('travis') WHERE User='root'"
|
||||
mysql --host 127.0.0.1 --port 3306 -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 || exit
|
||||
|
||||
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 "${GITHUB_WORKSPACE}"
|
||||
bench start &> bench_run_logs.txt &
|
||||
bench --site test_site reinstall --yes
|
||||
@@ -1,63 +0,0 @@
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
# ruleid: frappe-modifying-but-not-comitting
|
||||
def on_submit(self):
|
||||
if self.value_of_goods == 0:
|
||||
frappe.throw(_('Value of goods cannot be 0'))
|
||||
self.status = 'Submitted'
|
||||
|
||||
|
||||
# ok: frappe-modifying-but-not-comitting
|
||||
def on_submit(self):
|
||||
if self.value_of_goods == 0:
|
||||
frappe.throw(_('Value of goods cannot be 0'))
|
||||
self.status = 'Submitted'
|
||||
self.db_set('status', 'Submitted')
|
||||
|
||||
# ok: frappe-modifying-but-not-comitting
|
||||
def on_submit(self):
|
||||
if self.value_of_goods == 0:
|
||||
frappe.throw(_('Value of goods cannot be 0'))
|
||||
x = "y"
|
||||
self.status = x
|
||||
self.db_set('status', x)
|
||||
|
||||
|
||||
# ok: frappe-modifying-but-not-comitting
|
||||
def on_submit(self):
|
||||
x = "y"
|
||||
self.status = x
|
||||
self.save()
|
||||
|
||||
# ruleid: frappe-modifying-but-not-comitting-other-method
|
||||
class DoctypeClass(Document):
|
||||
def on_submit(self):
|
||||
self.good_method()
|
||||
self.tainted_method()
|
||||
|
||||
def tainted_method(self):
|
||||
self.status = "uptate"
|
||||
|
||||
|
||||
# ok: frappe-modifying-but-not-comitting-other-method
|
||||
class DoctypeClass(Document):
|
||||
def on_submit(self):
|
||||
self.good_method()
|
||||
self.tainted_method()
|
||||
|
||||
def tainted_method(self):
|
||||
self.status = "update"
|
||||
self.db_set("status", "update")
|
||||
|
||||
# ok: frappe-modifying-but-not-comitting-other-method
|
||||
class DoctypeClass(Document):
|
||||
def on_submit(self):
|
||||
self.good_method()
|
||||
self.tainted_method()
|
||||
self.save()
|
||||
|
||||
def tainted_method(self):
|
||||
self.status = "uptate"
|
||||
151
.github/helper/semgrep_rules/frappe_correctness.yml
vendored
151
.github/helper/semgrep_rules/frappe_correctness.yml
vendored
@@ -1,151 +0,0 @@
|
||||
# This file specifies rules for correctness according to how frappe doctype data model works.
|
||||
|
||||
rules:
|
||||
- id: frappe-modifying-but-not-comitting
|
||||
patterns:
|
||||
- pattern: |
|
||||
def $METHOD(self, ...):
|
||||
...
|
||||
self.$ATTR = ...
|
||||
- pattern-not: |
|
||||
def $METHOD(self, ...):
|
||||
...
|
||||
self.$ATTR = ...
|
||||
...
|
||||
self.db_set(..., self.$ATTR, ...)
|
||||
- pattern-not: |
|
||||
def $METHOD(self, ...):
|
||||
...
|
||||
self.$ATTR = $SOME_VAR
|
||||
...
|
||||
self.db_set(..., $SOME_VAR, ...)
|
||||
- pattern-not: |
|
||||
def $METHOD(self, ...):
|
||||
...
|
||||
self.$ATTR = $SOME_VAR
|
||||
...
|
||||
self.save()
|
||||
- metavariable-regex:
|
||||
metavariable: '$ATTR'
|
||||
# this is negative look-ahead, add more attrs to ignore like (ignore|ignore_this_too|ignore_me)
|
||||
regex: '^(?!ignore_linked_doctypes|status_updater)(.*)$'
|
||||
- metavariable-regex:
|
||||
metavariable: "$METHOD"
|
||||
regex: "(on_submit|on_cancel)"
|
||||
message: |
|
||||
DocType modified in self.$METHOD. Please check if modification of self.$ATTR is commited to database.
|
||||
languages: [python]
|
||||
severity: ERROR
|
||||
|
||||
- id: frappe-modifying-but-not-comitting-other-method
|
||||
patterns:
|
||||
- pattern: |
|
||||
class $DOCTYPE(...):
|
||||
def $METHOD(self, ...):
|
||||
...
|
||||
self.$ANOTHER_METHOD()
|
||||
...
|
||||
|
||||
def $ANOTHER_METHOD(self, ...):
|
||||
...
|
||||
self.$ATTR = ...
|
||||
- pattern-not: |
|
||||
class $DOCTYPE(...):
|
||||
def $METHOD(self, ...):
|
||||
...
|
||||
self.$ANOTHER_METHOD()
|
||||
...
|
||||
|
||||
def $ANOTHER_METHOD(self, ...):
|
||||
...
|
||||
self.$ATTR = ...
|
||||
...
|
||||
self.db_set(..., self.$ATTR, ...)
|
||||
- pattern-not: |
|
||||
class $DOCTYPE(...):
|
||||
def $METHOD(self, ...):
|
||||
...
|
||||
self.$ANOTHER_METHOD()
|
||||
...
|
||||
|
||||
def $ANOTHER_METHOD(self, ...):
|
||||
...
|
||||
self.$ATTR = $SOME_VAR
|
||||
...
|
||||
self.db_set(..., $SOME_VAR, ...)
|
||||
- pattern-not: |
|
||||
class $DOCTYPE(...):
|
||||
def $METHOD(self, ...):
|
||||
...
|
||||
self.$ANOTHER_METHOD()
|
||||
...
|
||||
self.save()
|
||||
def $ANOTHER_METHOD(self, ...):
|
||||
...
|
||||
self.$ATTR = ...
|
||||
- metavariable-regex:
|
||||
metavariable: "$METHOD"
|
||||
regex: "(on_submit|on_cancel)"
|
||||
message: |
|
||||
self.$ANOTHER_METHOD is called from self.$METHOD, check if changes to self.$ATTR are commited to database.
|
||||
languages: [python]
|
||||
severity: ERROR
|
||||
|
||||
- id: frappe-print-function-in-doctypes
|
||||
pattern: print(...)
|
||||
message: |
|
||||
Did you mean to leave this print statement in? Consider using msgprint or logger instead of print statement.
|
||||
languages: [python]
|
||||
severity: WARNING
|
||||
paths:
|
||||
include:
|
||||
- "*/**/doctype/*"
|
||||
|
||||
- id: frappe-modifying-child-tables-while-iterating
|
||||
pattern-either:
|
||||
- pattern: |
|
||||
for $ROW in self.$TABLE:
|
||||
...
|
||||
self.remove(...)
|
||||
- pattern: |
|
||||
for $ROW in self.$TABLE:
|
||||
...
|
||||
self.append(...)
|
||||
message: |
|
||||
Child table being modified while iterating on it.
|
||||
languages: [python]
|
||||
severity: ERROR
|
||||
paths:
|
||||
include:
|
||||
- "*/**/doctype/*"
|
||||
|
||||
- id: frappe-same-key-assigned-twice
|
||||
pattern-either:
|
||||
- pattern: |
|
||||
{..., $X: $A, ..., $X: $B, ...}
|
||||
- pattern: |
|
||||
dict(..., ($X, $A), ..., ($X, $B), ...)
|
||||
- pattern: |
|
||||
_dict(..., ($X, $A), ..., ($X, $B), ...)
|
||||
message: |
|
||||
key `$X` is uselessly assigned twice. This could be a potential bug.
|
||||
languages: [python]
|
||||
severity: ERROR
|
||||
|
||||
|
||||
- id: frappe-manual-commit
|
||||
patterns:
|
||||
- pattern: frappe.db.commit()
|
||||
- pattern-not-inside: |
|
||||
try:
|
||||
...
|
||||
except ...:
|
||||
...
|
||||
message: |
|
||||
Manually commiting a transaction is highly discouraged. Read about the transaction model implemented by Frappe Framework before adding manual commits: https://frappeframework.com/docs/user/en/api/database#database-transaction-model If you think manual commit is required then add a comment explaining why and `// nosemgrep` on the same line.
|
||||
paths:
|
||||
exclude:
|
||||
- "**/patches/**"
|
||||
- "**/demo/**"
|
||||
languages: [python]
|
||||
severity: ERROR
|
||||
14
.github/helper/semgrep_rules/report.py
vendored
14
.github/helper/semgrep_rules/report.py
vendored
@@ -1,14 +0,0 @@
|
||||
from frappe import _
|
||||
|
||||
# ruleid: frappe-missing-translate-function-in-report-python
|
||||
{"label": "Field Label"}
|
||||
|
||||
# ruleid: frappe-missing-translate-function-in-report-python
|
||||
dict(label="Field Label")
|
||||
|
||||
|
||||
# ok: frappe-missing-translate-function-in-report-python
|
||||
{"label": _("Field Label")}
|
||||
|
||||
# ok: frappe-missing-translate-function-in-report-python
|
||||
dict(label=_("Field Label"))
|
||||
30
.github/helper/semgrep_rules/ux.py
vendored
30
.github/helper/semgrep_rules/ux.py
vendored
@@ -1,30 +0,0 @@
|
||||
import frappe
|
||||
from frappe import _, msgprint, throw
|
||||
|
||||
# ruleid: frappe-missing-translate-function-python
|
||||
throw("Error Occured")
|
||||
|
||||
# ruleid: frappe-missing-translate-function-python
|
||||
frappe.throw("Error Occured")
|
||||
|
||||
# ruleid: frappe-missing-translate-function-python
|
||||
frappe.msgprint("Useful message")
|
||||
|
||||
# ruleid: frappe-missing-translate-function-python
|
||||
msgprint("Useful message")
|
||||
|
||||
|
||||
# ok: frappe-missing-translate-function-python
|
||||
translatedmessage = _("Hello")
|
||||
|
||||
# ok: frappe-missing-translate-function-python
|
||||
throw(translatedmessage)
|
||||
|
||||
# ok: frappe-missing-translate-function-python
|
||||
msgprint(translatedmessage)
|
||||
|
||||
# ok: frappe-missing-translate-function-python
|
||||
msgprint(_("Helpful message"))
|
||||
|
||||
# ok: frappe-missing-translate-function-python
|
||||
frappe.throw(_("Error occured"))
|
||||
60
.github/helper/translation.py
vendored
60
.github/helper/translation.py
vendored
@@ -1,60 +0,0 @@
|
||||
import re
|
||||
import sys
|
||||
|
||||
errors_encounter = 0
|
||||
pattern = re.compile(r"_\(([\"']{,3})(?P<message>((?!\1).)*)\1(\s*,\s*context\s*=\s*([\"'])(?P<py_context>((?!\5).)*)\5)*(\s*,(\s*?.*?\n*?)*(,\s*([\"'])(?P<js_context>((?!\11).)*)\11)*)*\)")
|
||||
words_pattern = re.compile(r"_{1,2}\([\"'`]{1,3}.*?[a-zA-Z]")
|
||||
start_pattern = re.compile(r"_{1,2}\([f\"'`]{1,3}")
|
||||
f_string_pattern = re.compile(r"_\(f[\"']")
|
||||
starts_with_f_pattern = re.compile(r"_\(f")
|
||||
|
||||
# skip first argument
|
||||
files = sys.argv[1:]
|
||||
files_to_scan = [_file for _file in files if _file.endswith(('.py', '.js'))]
|
||||
|
||||
for _file in files_to_scan:
|
||||
with open(_file, 'r') as f:
|
||||
print(f'Checking: {_file}')
|
||||
file_lines = f.readlines()
|
||||
for line_number, line in enumerate(file_lines, 1):
|
||||
if 'frappe-lint: disable-translate' in line:
|
||||
continue
|
||||
|
||||
start_matches = start_pattern.search(line)
|
||||
if start_matches:
|
||||
starts_with_f = starts_with_f_pattern.search(line)
|
||||
|
||||
if starts_with_f:
|
||||
has_f_string = f_string_pattern.search(line)
|
||||
if has_f_string:
|
||||
errors_encounter += 1
|
||||
print(f'\nF-strings are not supported for translations at line number {line_number}\n{line.strip()[:100]}')
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
|
||||
match = pattern.search(line)
|
||||
error_found = False
|
||||
|
||||
if not match and line.endswith((',\n', '[\n')):
|
||||
# concat remaining text to validate multiline pattern
|
||||
line = "".join(file_lines[line_number - 1:])
|
||||
line = line[start_matches.start() + 1:]
|
||||
match = pattern.match(line)
|
||||
|
||||
if not match:
|
||||
error_found = True
|
||||
print(f'\nTranslation syntax error at line number {line_number}\n{line.strip()[:100]}')
|
||||
|
||||
if not error_found and not words_pattern.search(line):
|
||||
error_found = True
|
||||
print(f'\nTranslation is useless because it has no words at line number {line_number}\n{line.strip()[:100]}')
|
||||
|
||||
if error_found:
|
||||
errors_encounter += 1
|
||||
|
||||
if errors_encounter > 0:
|
||||
print('\nVisit "https://frappeframework.com/docs/user/en/translations" to learn about valid translation strings.')
|
||||
sys.exit(1)
|
||||
else:
|
||||
print('\nGood To Go!')
|
||||
26
.github/workflows/backport.yml
vendored
26
.github/workflows/backport.yml
vendored
@@ -1,26 +0,0 @@
|
||||
name: Backport
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- closed
|
||||
- labeled
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "frappe/backport"
|
||||
path: ./actions
|
||||
ref: develop
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run backport
|
||||
uses: ./actions/backport
|
||||
with:
|
||||
token: ${{secrets.BACKPORT_BOT_TOKEN}}
|
||||
labelsToAdd: "backport"
|
||||
title: "{{originalTitle}}"
|
||||
2
.github/workflows/docker-release.yml
vendored
2
.github/workflows/docker-release.yml
vendored
@@ -11,4 +11,4 @@ jobs:
|
||||
- name: curl
|
||||
run: |
|
||||
apk add curl bash
|
||||
curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${{ secrets.CI_PAT }}" https://api.github.com/repos/frappe/frappe_docker/actions/workflows/build_stable.yml/dispatches -d '{"ref":"main"}'
|
||||
curl -s -X POST -H "Content-Type: application/json" -H "Accept: application/json" -H "Travis-API-Version: 3" -H "Authorization: token ${{ secrets.TRAVIS_CI_TOKEN }}" -d '{"request":{"branch":"master"}}' https://api.travis-ci.com/repo/frappe%2Ffrappe_docker/requests
|
||||
|
||||
25
.github/workflows/docs-checker.yml
vendored
25
.github/workflows/docs-checker.yml
vendored
@@ -1,25 +0,0 @@
|
||||
name: 'Documentation Required'
|
||||
on:
|
||||
pull_request:
|
||||
types: [ opened, synchronize, reopened, edited ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: 'Setup Environment'
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.6
|
||||
|
||||
- name: 'Clone repo'
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Validate Docs
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
run: |
|
||||
pip install requests --quiet
|
||||
python $GITHUB_WORKSPACE/.github/helper/documentation.py $PR_NUMBER
|
||||
31
.github/workflows/linters.yml
vendored
31
.github/workflows/linters.yml
vendored
@@ -1,31 +0,0 @@
|
||||
name: Linters
|
||||
|
||||
on:
|
||||
pull_request: { }
|
||||
|
||||
jobs:
|
||||
|
||||
linters:
|
||||
name: linters
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
- name: Install and Run Pre-commit
|
||||
uses: pre-commit/action@v2.0.3
|
||||
|
||||
- name: Download Semgrep rules
|
||||
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules
|
||||
|
||||
- uses: returntocorp/semgrep-action@v1
|
||||
env:
|
||||
SEMGREP_TIMEOUT: 120
|
||||
with:
|
||||
config: >-
|
||||
r/python.lang.correctness
|
||||
./frappe-semgrep-rules/rules
|
||||
90
.github/workflows/patch.yml
vendored
90
.github/workflows/patch.yml
vendored
@@ -1,90 +0,0 @@
|
||||
name: Patch
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.js'
|
||||
- '**.md'
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
concurrency:
|
||||
group: patch-mariadb-v13-${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-18.04
|
||||
timeout-minutes: 60
|
||||
|
||||
name: Patch Test
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mariadb:10.3
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: YES
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.7
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 12
|
||||
check-latest: true
|
||||
|
||||
- name: Add to Hosts
|
||||
run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- uses: actions/cache@v2
|
||||
id: yarn-cache
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Install
|
||||
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
|
||||
|
||||
- name: Run Patch Tests
|
||||
run: |
|
||||
cd ~/frappe-bench/
|
||||
wget https://erpnext.com/files/v10-erpnext.sql.gz
|
||||
bench --site test_site --force restore ~/frappe-bench/v10-erpnext.sql.gz
|
||||
bench --site test_site migrate
|
||||
31
.github/workflows/release.yml
vendored
31
.github/workflows/release.yml
vendored
@@ -1,31 +0,0 @@
|
||||
name: Generate Semantic Release
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- version-13
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Entire Repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: Setup Node.js v14
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14
|
||||
- name: Setup dependencies
|
||||
run: |
|
||||
npm install @semantic-release/git @semantic-release/exec --no-save
|
||||
- name: Create Release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
GIT_AUTHOR_NAME: "Frappe PR Bot"
|
||||
GIT_AUTHOR_EMAIL: "developers@frappe.io"
|
||||
GIT_COMMITTER_NAME: "Frappe PR Bot"
|
||||
GIT_COMMITTER_EMAIL: "developers@frappe.io"
|
||||
run: npx semantic-release
|
||||
100
.github/workflows/server-tests.yml
vendored
100
.github/workflows/server-tests.yml
vendored
@@ -1,100 +0,0 @@
|
||||
name: Server
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.js'
|
||||
- '**.md'
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ develop ]
|
||||
paths-ignore:
|
||||
- '**.js'
|
||||
- '**.md'
|
||||
|
||||
concurrency:
|
||||
group: server-mariadb-v13-${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-18.04
|
||||
timeout-minutes: 60
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
container: [1, 2]
|
||||
|
||||
name: Python Unit Tests
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mariadb:10.3
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: YES
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.7
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 12
|
||||
check-latest: true
|
||||
|
||||
- name: Add to Hosts
|
||||
run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- uses: actions/cache@v2
|
||||
id: yarn-cache
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Install
|
||||
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
|
||||
|
||||
- name: Run Tests
|
||||
run: 'cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --total-builds 2 --build-number ${{ matrix.container }}'
|
||||
env:
|
||||
TYPE: server
|
||||
CI_BUILD_ID: ${{ github.run_id }}
|
||||
ORCHESTRATOR_URL: http://test-orchestrator.frappe.io
|
||||
22
.github/workflows/translation_linter.yml
vendored
22
.github/workflows/translation_linter.yml
vendored
@@ -1,22 +0,0 @@
|
||||
name: Frappe Linter
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- develop
|
||||
- version-12-hotfix
|
||||
- version-11-hotfix
|
||||
jobs:
|
||||
check_translation:
|
||||
name: Translation Syntax Check
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup python3
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.6
|
||||
- name: Validating Translation Syntax
|
||||
run: |
|
||||
git fetch origin $GITHUB_BASE_REF:$GITHUB_BASE_REF -q
|
||||
files=$(git diff --name-only --diff-filter=d $GITHUB_BASE_REF)
|
||||
python $GITHUB_WORKSPACE/.github/helper/translation.py $files
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -12,6 +12,6 @@ erpnext/docs/current
|
||||
*.swo
|
||||
__pycache__
|
||||
*~
|
||||
.idea/
|
||||
.vscode/
|
||||
node_modules/
|
||||
.idea/
|
||||
58
.mergify.yml
58
.mergify.yml
@@ -1,58 +0,0 @@
|
||||
pull_request_rules:
|
||||
- name: Auto-close PRs on stable branch
|
||||
conditions:
|
||||
- and:
|
||||
- and:
|
||||
- author!=surajshetty3416
|
||||
- author!=gavindsouza
|
||||
- author!=rohitwaghchaure
|
||||
- author!=nabinhait
|
||||
- or:
|
||||
- base=version-13
|
||||
- base=version-12
|
||||
actions:
|
||||
close:
|
||||
comment:
|
||||
message: |
|
||||
@{{author}}, thanks for the contribution, but we do not accept pull requests on a stable branch. Please raise PR on an appropriate hotfix branch.
|
||||
https://github.com/frappe/erpnext/wiki/Pull-Request-Checklist#which-branch
|
||||
|
||||
- name: backport to version-13-hotfix
|
||||
conditions:
|
||||
- label="backport version-13-hotfix"
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- version-13-hotfix
|
||||
assignees:
|
||||
- "{{ author }}"
|
||||
|
||||
- name: backport to version-13-pre-release
|
||||
conditions:
|
||||
- label="backport version-13-pre-release"
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- version-13-pre-release
|
||||
assignees:
|
||||
- "{{ author }}"
|
||||
|
||||
- name: backport to version-12-hotfix
|
||||
conditions:
|
||||
- label="backport version-12-hotfix"
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- version-12-hotfix
|
||||
assignees:
|
||||
- "{{ author }}"
|
||||
|
||||
- name: backport to version-12-pre-release
|
||||
conditions:
|
||||
- label="backport version-12-pre-release"
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- version-12-pre-release
|
||||
assignees:
|
||||
- "{{ author }}"
|
||||
@@ -1,45 +0,0 @@
|
||||
exclude: 'node_modules|.git'
|
||||
default_stages: [commit]
|
||||
fail_fast: false
|
||||
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.0.1
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
files: "erpnext.*"
|
||||
exclude: ".*json$|.*txt$|.*csv|.*md"
|
||||
- id: check-yaml
|
||||
- id: no-commit-to-branch
|
||||
args: ['--branch', 'develop']
|
||||
- id: check-merge-conflict
|
||||
- id: check-ast
|
||||
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.9.2
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies: [
|
||||
'flake8-bugbear',
|
||||
]
|
||||
args: ['--config', '.github/helper/.flake8_strict']
|
||||
exclude: ".*setup.py$"
|
||||
|
||||
- repo: https://github.com/adityahase/black
|
||||
rev: 9cb0a69f4d0030cdf687eddf314468b39ed54119
|
||||
hooks:
|
||||
- id: black
|
||||
additional_dependencies: ['click==8.0.4']
|
||||
|
||||
- repo: https://github.com/timothycrosley/isort
|
||||
rev: 5.9.1
|
||||
hooks:
|
||||
- id: isort
|
||||
exclude: ".*setup.py$"
|
||||
|
||||
|
||||
ci:
|
||||
autoupdate_schedule: weekly
|
||||
skip: []
|
||||
submodules: false
|
||||
24
.releaserc
24
.releaserc
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"branches": ["version-13"],
|
||||
"plugins": [
|
||||
"@semantic-release/commit-analyzer", {
|
||||
"preset": "angular",
|
||||
"releaseRules": [
|
||||
{"breaking": true, "release": false}
|
||||
]
|
||||
},
|
||||
"@semantic-release/release-notes-generator",
|
||||
[
|
||||
"@semantic-release/exec", {
|
||||
"prepareCmd": 'sed -ir -E "s/\"[0-9]+\.[0-9]+\.[0-9]+\"/\"${nextRelease.version}\"/" erpnext/__init__.py'
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/git", {
|
||||
"assets": ["erpnext/__init__.py"],
|
||||
"message": "chore(release): Bumped to Version ${nextRelease.version}\n\n${nextRelease.notes}"
|
||||
}
|
||||
],
|
||||
"@semantic-release/github"
|
||||
]
|
||||
}
|
||||
81
.travis.yml
Normal file
81
.travis.yml
Normal file
@@ -0,0 +1,81 @@
|
||||
dist: trusty
|
||||
|
||||
language: python
|
||||
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
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:
|
||||
- cd ~
|
||||
- nvm install 10
|
||||
|
||||
- git clone https://github.com/frappe/bench --depth 1
|
||||
- pip install -e ./bench
|
||||
|
||||
- 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
|
||||
|
||||
- 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 coverage==4.5.4
|
||||
- pip install python-coveralls
|
||||
- coveralls -b apps/erpnext -d ../../sites/.coverage
|
||||
@@ -1,6 +1,4 @@
|
||||
{
|
||||
"db_host": "127.0.0.1",
|
||||
"db_port": 3306,
|
||||
"db_name": "test_frappe",
|
||||
"db_password": "test_frappe",
|
||||
"auto_email_id": "test@example.com",
|
||||
@@ -11,6 +9,5 @@
|
||||
"root_login": "root",
|
||||
"root_password": "travis",
|
||||
"host_name": "http://test_site:8000",
|
||||
"install_apps": ["erpnext"],
|
||||
"throttle_user_limit": 100
|
||||
"install_apps": ["erpnext"]
|
||||
}
|
||||
33
CODEOWNERS
33
CODEOWNERS
@@ -1,33 +0,0 @@
|
||||
# Each line is a file pattern followed by one or more owners.
|
||||
|
||||
# These owners will be the default owners for everything in
|
||||
# the repo. Unless a later match takes precedence,
|
||||
|
||||
erpnext/accounts/ @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
|
||||
erpnext/assets/ @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
|
||||
erpnext/erpnext_integrations/ @nextchamp-saqib
|
||||
erpnext/loan_management/ @nextchamp-saqib @deepeshgarg007
|
||||
erpnext/regional @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
|
||||
erpnext/selling @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
|
||||
erpnext/support/ @nextchamp-saqib @deepeshgarg007
|
||||
pos* @nextchamp-saqib
|
||||
|
||||
erpnext/buying/ @rohitwaghchaure @s-aga-r
|
||||
erpnext/maintenance/ @rohitwaghchaure @s-aga-r
|
||||
erpnext/manufacturing/ @rohitwaghchaure @s-aga-r
|
||||
erpnext/quality_management/ @rohitwaghchaure @s-aga-r
|
||||
erpnext/stock/ @rohitwaghchaure @s-aga-r
|
||||
|
||||
|
||||
erpnext/healthcare/ @chillaranand
|
||||
erpnext/hr/ @ruchamahabal
|
||||
erpnext/non_profit/ @ruchamahabal
|
||||
erpnext/payroll @ruchamahabal
|
||||
erpnext/projects/ @ruchamahabal
|
||||
|
||||
erpnext/controllers @deepeshgarg007 @nextchamp-saqib @rohitwaghchaure @marination
|
||||
erpnext/patches/ @deepeshgarg007 @nextchamp-saqib @rohitwaghchaure
|
||||
erpnext/public/ @nextchamp-saqib @marination
|
||||
|
||||
.github/ @ankush
|
||||
requirements.txt @gavindsouza @ankush
|
||||
33
README.md
33
README.md
@@ -1,11 +1,11 @@
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/public/images/erpnext-logo.png" height="128">
|
||||
<img src="https://github.com/frappe/design/blob/master/logos/logo-2019/erpnext-logo.png" height="128">
|
||||
<h2>ERPNext</h2>
|
||||
<p align="center">
|
||||
<p>ERP made simple</p>
|
||||
</p>
|
||||
|
||||
[](https://github.com/frappe/erpnext/actions/workflows/ci-tests.yml)
|
||||
[](https://travis-ci.com/frappe/erpnext)
|
||||
[](https://www.codetriage.com/frappe/erpnext)
|
||||
[](https://coveralls.io/github/frappe/erpnext?branch=develop)
|
||||
|
||||
@@ -13,36 +13,15 @@
|
||||
|
||||
</div>
|
||||
|
||||
ERPNext as a monolith includes the following areas for managing businesses:
|
||||
Includes: Accounting, Inventory, Manufacturing, CRM, Sales, Purchase, Project Management, HRMS. Requires MariaDB.
|
||||
|
||||
1. [Accounting](https://erpnext.com/open-source-accounting)
|
||||
1. [Warehouse Management](https://erpnext.com/distribution/warehouse-management-system)
|
||||
1. [CRM](https://erpnext.com/open-source-crm)
|
||||
1. [Sales](https://erpnext.com/open-source-sales-purchase)
|
||||
1. [Purchase](https://erpnext.com/open-source-sales-purchase)
|
||||
1. [HRMS](https://erpnext.com/open-source-hrms)
|
||||
1. [Project Management](https://erpnext.com/open-source-projects)
|
||||
1. [Support](https://erpnext.com/open-source-help-desk-software)
|
||||
1. [Asset Management](https://erpnext.com/open-source-asset-management-software)
|
||||
1. [Quality Management](https://erpnext.com/docs/user/manual/en/quality-management)
|
||||
1. [Manufacturing](https://erpnext.com/open-source-manufacturing-erp-software)
|
||||
1. [Website Management](https://erpnext.com/open-source-website-builder-software)
|
||||
1. [Customize ERPNext](https://erpnext.com/docs/user/manual/en/customize-erpnext)
|
||||
1. [And More](https://erpnext.com/docs/user/manual/en/)
|
||||
|
||||
ERPNext requires MariaDB.
|
||||
|
||||
ERPNext is built on the [Frappe Framework](https://github.com/frappe/frappe), a full-stack web app framework built with Python & JavaScript.
|
||||
ERPNext is built on the [Frappe](https://github.com/frappe/frappe) Framework, a full-stack web app framework in Python & JavaScript.
|
||||
|
||||
- [User Guide](https://erpnext.com/docs/user)
|
||||
- [Discussion Forum](https://discuss.erpnext.com/)
|
||||
|
||||
---
|
||||
|
||||
### Containerized Installation
|
||||
|
||||
Use docker to deploy ERPNext in production or for development of [Frappe](https://github.com/frappe/frappe) apps. See https://github.com/frappe/frappe_docker for more details.
|
||||
|
||||
### Full Install
|
||||
|
||||
The Easy Way: our install script for bench will install all dependencies (e.g. MariaDB). See https://github.com/frappe/bench for more details.
|
||||
@@ -65,14 +44,12 @@ GNU/General Public License (see [license.txt](license.txt))
|
||||
|
||||
The ERPNext code is licensed as GNU General Public License (v3) and the Documentation is licensed as Creative Commons (CC-BY-SA-3.0) and the copyright is owned by Frappe Technologies Pvt Ltd (Frappe) and Contributors.
|
||||
|
||||
By contributing to ERPNext, you agree that your contributions will be licensed under its GNU General Public License (v3).
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
1. [Issue Guidelines](https://github.com/frappe/erpnext/wiki/Issue-Guidelines)
|
||||
1. [Report Security Vulnerabilities](https://erpnext.com/security)
|
||||
1. [Report Security Vulnerabilities](https://erpnext.com/report)
|
||||
1. [Pull Request Requirements](https://github.com/frappe/erpnext/wiki/Contribution-Guidelines)
|
||||
1. [Translations](https://translate.erpnext.com)
|
||||
1. [Chart of Accounts](https://charts.erpnext.com)
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# 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.
|
||||
11
cypress.json
11
cypress.json
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"baseUrl": "http://test_site:8000",
|
||||
"projectId": "da59y9",
|
||||
"adminPassword": "admin",
|
||||
"defaultCommandTimeout": 20000,
|
||||
"pageLoadTimeout": 15000,
|
||||
"retries": {
|
||||
"runMode": 2,
|
||||
"openMode": 2
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
context('Customer', () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
});
|
||||
it('Check Customer Group', () => {
|
||||
cy.visit(`app/customer/`);
|
||||
cy.get('.primary-action').click();
|
||||
cy.wait(500);
|
||||
cy.get('.custom-actions > .btn').click();
|
||||
cy.get_field('customer_group', 'Link').should('have.value', 'All Customer Groups');
|
||||
});
|
||||
});
|
||||
@@ -1,116 +0,0 @@
|
||||
context('Organizational Chart', () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit('/app/website');
|
||||
});
|
||||
|
||||
it('navigates to org chart', () => {
|
||||
cy.visit('/app');
|
||||
cy.visit('/app/organizational-chart');
|
||||
cy.url().should('include', '/organizational-chart');
|
||||
|
||||
cy.window().its('frappe.csrf_token').then(csrf_token => {
|
||||
return cy.request({
|
||||
url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'X-Frappe-CSRF-Token': csrf_token
|
||||
},
|
||||
timeout: 60000
|
||||
}).then(res => {
|
||||
expect(res.status).eq(200);
|
||||
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
|
||||
cy.get('@input')
|
||||
.clear({ force: true })
|
||||
.type('Test Org Chart{downarrow}{enter}', { force: true })
|
||||
.blur({ force: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders root nodes and loads children for the first expandable node', () => {
|
||||
// check rendered root nodes and the node name, title, connections
|
||||
cy.get('.hierarchy').find('.root-level ul.node-children').children()
|
||||
.should('have.length', 2)
|
||||
.first()
|
||||
.as('first-child');
|
||||
|
||||
cy.get('@first-child').get('.node-name').contains('Test Employee 1');
|
||||
cy.get('@first-child').get('.node-info').find('.node-title').contains('CEO');
|
||||
cy.get('@first-child').get('.node-info').find('.node-connections').contains('· 2 Connections');
|
||||
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
// children of 1st root visible
|
||||
cy.get(`div[data-parent="${employee_records.message[0]}"]`).as('child-node');
|
||||
cy.get('@child-node')
|
||||
.should('have.length', 1)
|
||||
.should('be.visible');
|
||||
cy.get('@child-node').get('.node-name').contains('Test Employee 3');
|
||||
|
||||
// connectors between first root node and immediate child
|
||||
cy.get(`path[data-parent="${employee_records.message[0]}"]`)
|
||||
.should('be.visible')
|
||||
.invoke('attr', 'data-child')
|
||||
.should('equal', employee_records.message[2]);
|
||||
});
|
||||
});
|
||||
|
||||
it('hides active nodes children and connectors on expanding sibling node', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
// click sibling
|
||||
cy.get(`#${employee_records.message[1]}`)
|
||||
.click()
|
||||
.should('have.class', 'active');
|
||||
|
||||
// child nodes and connectors hidden
|
||||
cy.get(`[data-parent="${employee_records.message[0]}"]`).should('not.be.visible');
|
||||
cy.get(`path[data-parent="${employee_records.message[0]}"]`).should('not.be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('collapses previous level nodes and refreshes connectors on expanding child node', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
// click child node
|
||||
cy.get(`#${employee_records.message[3]}`)
|
||||
.click()
|
||||
.should('have.class', 'active');
|
||||
|
||||
// previous level nodes: parent should be on active-path; other nodes should be collapsed
|
||||
cy.get(`#${employee_records.message[0]}`).should('have.class', 'collapsed');
|
||||
cy.get(`#${employee_records.message[1]}`).should('have.class', 'active-path');
|
||||
|
||||
// previous level connectors refreshed
|
||||
cy.get(`path[data-parent="${employee_records.message[1]}"]`)
|
||||
.should('have.class', 'collapsed-connector');
|
||||
|
||||
// child node's children and connectors rendered
|
||||
cy.get(`[data-parent="${employee_records.message[3]}"]`).should('be.visible');
|
||||
cy.get(`path[data-parent="${employee_records.message[3]}"]`).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('expands previous level nodes', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
cy.get(`#${employee_records.message[0]}`)
|
||||
.click()
|
||||
.should('have.class', 'active');
|
||||
|
||||
cy.get(`[data-parent="${employee_records.message[0]}"]`)
|
||||
.should('be.visible');
|
||||
|
||||
cy.get('ul.hierarchy').children().should('have.length', 2);
|
||||
cy.get(`#connectors`).children().should('have.length', 1);
|
||||
});
|
||||
});
|
||||
|
||||
it('edit node navigates to employee master', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
|
||||
.click();
|
||||
|
||||
cy.url().should('include', `/employee/${employee_records.message[0]}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,195 +0,0 @@
|
||||
context('Organizational Chart Mobile', () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit('/app/website');
|
||||
});
|
||||
|
||||
it('navigates to org chart', () => {
|
||||
cy.viewport(375, 667);
|
||||
cy.visit('/app');
|
||||
cy.visit('/app/organizational-chart');
|
||||
cy.url().should('include', '/organizational-chart');
|
||||
|
||||
cy.window().its('frappe.csrf_token').then(csrf_token => {
|
||||
return cy.request({
|
||||
url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'X-Frappe-CSRF-Token': csrf_token
|
||||
},
|
||||
timeout: 60000
|
||||
}).then(res => {
|
||||
expect(res.status).eq(200);
|
||||
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
|
||||
cy.get('@input')
|
||||
.clear({ force: true })
|
||||
.type('Test Org Chart{downarrow}{enter}', { force: true })
|
||||
.blur({ force: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders root nodes', () => {
|
||||
// check rendered root nodes and the node name, title, connections
|
||||
cy.get('.hierarchy-mobile').find('.root-level').children()
|
||||
.should('have.length', 2)
|
||||
.first()
|
||||
.as('first-child');
|
||||
|
||||
cy.get('@first-child').get('.node-name').contains('Test Employee 1');
|
||||
cy.get('@first-child').get('.node-info').find('.node-title').contains('CEO');
|
||||
cy.get('@first-child').get('.node-info').find('.node-connections').contains('· 2');
|
||||
});
|
||||
|
||||
it('expands root node', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
cy.get(`#${employee_records.message[1]}`)
|
||||
.click()
|
||||
.should('have.class', 'active');
|
||||
|
||||
// other root node removed
|
||||
cy.get(`#${employee_records.message[0]}`).should('not.exist');
|
||||
|
||||
// children of active root node
|
||||
cy.get('.hierarchy-mobile').find('.level').first().find('ul.node-children').children()
|
||||
.should('have.length', 2);
|
||||
|
||||
cy.get(`div[data-parent="${employee_records.message[1]}"]`).first().as('child-node');
|
||||
cy.get('@child-node').should('be.visible');
|
||||
|
||||
cy.get('@child-node')
|
||||
.get('.node-name')
|
||||
.contains('Test Employee 4');
|
||||
|
||||
// connectors between root node and immediate children
|
||||
cy.get(`path[data-parent="${employee_records.message[1]}"]`).as('connectors');
|
||||
cy.get('@connectors')
|
||||
.should('have.length', 2)
|
||||
.should('be.visible');
|
||||
|
||||
cy.get('@connectors')
|
||||
.first()
|
||||
.invoke('attr', 'data-child')
|
||||
.should('eq', employee_records.message[3]);
|
||||
});
|
||||
});
|
||||
|
||||
it('expands child node', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
cy.get(`#${employee_records.message[3]}`)
|
||||
.click()
|
||||
.should('have.class', 'active')
|
||||
.as('expanded_node');
|
||||
|
||||
// 2 levels on screen; 1 on active path; 1 collapsed
|
||||
cy.get('.hierarchy-mobile').children().should('have.length', 2);
|
||||
cy.get(`#${employee_records.message[1]}`).should('have.class', 'active-path');
|
||||
|
||||
// children of expanded node visible
|
||||
cy.get('@expanded_node')
|
||||
.next()
|
||||
.should('have.class', 'node-children')
|
||||
.as('node-children');
|
||||
|
||||
cy.get('@node-children').children().should('have.length', 1);
|
||||
cy.get('@node-children')
|
||||
.first()
|
||||
.get('.node-card')
|
||||
.should('have.class', 'active-child')
|
||||
.contains('Test Employee 7');
|
||||
|
||||
// orphan connectors removed
|
||||
cy.get(`#connectors`).children().should('have.length', 2);
|
||||
});
|
||||
});
|
||||
|
||||
it('renders sibling group', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
// sibling group visible for parent
|
||||
cy.get(`#${employee_records.message[1]}`)
|
||||
.next()
|
||||
.as('sibling_group');
|
||||
|
||||
cy.get('@sibling_group')
|
||||
.should('have.attr', 'data-parent', 'undefined')
|
||||
.should('have.class', 'node-group')
|
||||
.and('have.class', 'collapsed');
|
||||
|
||||
cy.get('@sibling_group').get('.avatar-group').children().as('siblings');
|
||||
cy.get('@siblings').should('have.length', 1);
|
||||
cy.get('@siblings')
|
||||
.first()
|
||||
.should('have.attr', 'title', 'Test Employee 1');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
it('expands previous level nodes', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
cy.get(`#${employee_records.message[6]}`)
|
||||
.click()
|
||||
.should('have.class', 'active');
|
||||
|
||||
// clicking on previous level node should remove all the nodes ahead
|
||||
// and expand that node
|
||||
cy.get(`#${employee_records.message[3]}`).click();
|
||||
cy.get(`#${employee_records.message[3]}`)
|
||||
.should('have.class', 'active')
|
||||
.should('not.have.class', 'active-path');
|
||||
|
||||
cy.get(`#${employee_records.message[6]}`).should('have.class', 'active-child');
|
||||
cy.get('.hierarchy-mobile').children().should('have.length', 2);
|
||||
cy.get(`#connectors`).children().should('have.length', 2);
|
||||
});
|
||||
});
|
||||
|
||||
it('expands sibling group', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
// sibling group visible for parent
|
||||
cy.get(`#${employee_records.message[6]}`).click();
|
||||
|
||||
cy.get(`#${employee_records.message[3]}`)
|
||||
.next()
|
||||
.click();
|
||||
|
||||
// siblings of parent should be visible
|
||||
cy.get('.hierarchy-mobile').prev().as('sibling_group');
|
||||
cy.get('@sibling_group')
|
||||
.should('exist')
|
||||
.should('have.class', 'sibling-group')
|
||||
.should('not.have.class', 'collapsed');
|
||||
|
||||
cy.get(`#${employee_records.message[1]}`)
|
||||
.should('be.visible')
|
||||
.should('have.class', 'active');
|
||||
|
||||
cy.get(`[data-parent="${employee_records.message[1]}"]`)
|
||||
.should('be.visible')
|
||||
.should('have.length', 2)
|
||||
.should('have.class', 'active-child');
|
||||
});
|
||||
});
|
||||
|
||||
it('goes to the respective level after clicking on non-collapsed sibling group', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(() => {
|
||||
// click on non-collapsed sibling group
|
||||
cy.get('.hierarchy-mobile')
|
||||
.prev()
|
||||
.click();
|
||||
|
||||
// should take you to that level
|
||||
cy.get('.hierarchy-mobile').find('li.level .node-card').should('have.length', 2);
|
||||
});
|
||||
});
|
||||
|
||||
it('edit node navigates to employee master', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
|
||||
.click();
|
||||
|
||||
cy.url().should('include', `/employee/${employee_records.message[0]}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
module.exports = () => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add("login", (email, password) => { ... });
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... });
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... });
|
||||
//
|
||||
//
|
||||
// -- This is will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... });
|
||||
|
||||
const slug = (name) => name.toLowerCase().replace(" ", "-");
|
||||
|
||||
Cypress.Commands.add("go_to_doc", (doctype, name) => {
|
||||
cy.visit(`/app/${slug(doctype)}/${encodeURIComponent(name)}`);
|
||||
});
|
||||
@@ -1,26 +0,0 @@
|
||||
// ***********************************************************
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands';
|
||||
import '../../../frappe/cypress/support/commands' // eslint-disable-line
|
||||
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
|
||||
Cypress.Cookies.defaults({
|
||||
preserve: 'sid'
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"baseUrl": "../node_modules",
|
||||
"types": [
|
||||
"cypress"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.*"
|
||||
]
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"extends": ["stylelint-config-recommended"],
|
||||
"plugins": ["stylelint-scss"],
|
||||
"rules": {
|
||||
"at-rule-no-unknown": null,
|
||||
"scss/at-rule-no-unknown": true,
|
||||
"no-descending-specificity": null
|
||||
}
|
||||
}
|
||||
@@ -1,60 +1,53 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
import inspect
|
||||
|
||||
import frappe
|
||||
|
||||
from erpnext.hooks import regional_overrides
|
||||
from frappe.utils import getdate
|
||||
|
||||
__version__ = "13.36.1"
|
||||
|
||||
__version__ = '11.1.77'
|
||||
|
||||
def get_default_company(user=None):
|
||||
"""Get default company for user"""
|
||||
'''Get default company for user'''
|
||||
from frappe.defaults import get_user_default_as_list
|
||||
|
||||
if not user:
|
||||
user = frappe.session.user
|
||||
|
||||
companies = get_user_default_as_list(user, "company")
|
||||
companies = get_user_default_as_list(user, 'company')
|
||||
if companies:
|
||||
default_company = companies[0]
|
||||
else:
|
||||
default_company = frappe.db.get_single_value("Global Defaults", "default_company")
|
||||
default_company = frappe.db.get_single_value('Global Defaults', 'default_company')
|
||||
|
||||
return default_company
|
||||
|
||||
|
||||
def get_default_currency():
|
||||
"""Returns the currency of the default company"""
|
||||
'''Returns the currency of the default company'''
|
||||
company = get_default_company()
|
||||
if company:
|
||||
return frappe.get_cached_value("Company", company, "default_currency")
|
||||
|
||||
return frappe.get_cached_value('Company', company, 'default_currency')
|
||||
|
||||
def get_default_cost_center(company):
|
||||
"""Returns the default cost center of the company"""
|
||||
'''Returns the default cost center of the company'''
|
||||
if not company:
|
||||
return None
|
||||
|
||||
if not frappe.flags.company_cost_center:
|
||||
frappe.flags.company_cost_center = {}
|
||||
if not company in frappe.flags.company_cost_center:
|
||||
frappe.flags.company_cost_center[company] = frappe.get_cached_value(
|
||||
"Company", company, "cost_center"
|
||||
)
|
||||
frappe.flags.company_cost_center[company] = frappe.get_cached_value('Company', company, 'cost_center')
|
||||
return frappe.flags.company_cost_center[company]
|
||||
|
||||
|
||||
def get_company_currency(company):
|
||||
"""Returns the default company currency"""
|
||||
'''Returns the default company currency'''
|
||||
if not frappe.flags.company_currency:
|
||||
frappe.flags.company_currency = {}
|
||||
if not company in frappe.flags.company_currency:
|
||||
frappe.flags.company_currency[company] = frappe.db.get_value(
|
||||
"Company", company, "default_currency", cache=True
|
||||
)
|
||||
frappe.flags.company_currency[company] = frappe.db.get_value('Company', company, 'default_currency', cache=True)
|
||||
return frappe.flags.company_currency[company]
|
||||
|
||||
|
||||
def set_perpetual_inventory(enable=1, company=None):
|
||||
if not company:
|
||||
company = "_Test Company" if frappe.flags.in_test else get_default_company()
|
||||
@@ -63,10 +56,9 @@ def set_perpetual_inventory(enable=1, company=None):
|
||||
company.enable_perpetual_inventory = enable
|
||||
company.save()
|
||||
|
||||
|
||||
def encode_company_abbr(name, company=None, abbr=None):
|
||||
"""Returns name encoded with company abbreviation"""
|
||||
company_abbr = abbr or frappe.get_cached_value("Company", company, "abbr")
|
||||
def encode_company_abbr(name, company):
|
||||
'''Returns name encoded with company abbreviation'''
|
||||
company_abbr = frappe.get_cached_value('Company', company, "abbr")
|
||||
parts = name.rsplit(" - ", 1)
|
||||
|
||||
if parts[-1].lower() != company_abbr.lower():
|
||||
@@ -74,73 +66,65 @@ def encode_company_abbr(name, company=None, abbr=None):
|
||||
|
||||
return " - ".join(parts)
|
||||
|
||||
|
||||
def is_perpetual_inventory_enabled(company):
|
||||
if not company:
|
||||
company = "_Test Company" if frappe.flags.in_test else get_default_company()
|
||||
|
||||
if not hasattr(frappe.local, "enable_perpetual_inventory"):
|
||||
if not hasattr(frappe.local, 'enable_perpetual_inventory'):
|
||||
frappe.local.enable_perpetual_inventory = {}
|
||||
|
||||
if not company in frappe.local.enable_perpetual_inventory:
|
||||
frappe.local.enable_perpetual_inventory[company] = (
|
||||
frappe.get_cached_value("Company", company, "enable_perpetual_inventory") or 0
|
||||
)
|
||||
frappe.local.enable_perpetual_inventory[company] = frappe.get_cached_value('Company',
|
||||
company, "enable_perpetual_inventory") or 0
|
||||
|
||||
return frappe.local.enable_perpetual_inventory[company]
|
||||
|
||||
|
||||
def get_default_finance_book(company=None):
|
||||
if not company:
|
||||
company = get_default_company()
|
||||
|
||||
if not hasattr(frappe.local, "default_finance_book"):
|
||||
if not hasattr(frappe.local, 'default_finance_book'):
|
||||
frappe.local.default_finance_book = {}
|
||||
|
||||
if not company in frappe.local.default_finance_book:
|
||||
frappe.local.default_finance_book[company] = frappe.get_cached_value(
|
||||
"Company", company, "default_finance_book"
|
||||
)
|
||||
frappe.local.default_finance_book[company] = frappe.get_cached_value('Company',
|
||||
company, "default_finance_book")
|
||||
|
||||
return frappe.local.default_finance_book[company]
|
||||
|
||||
|
||||
def get_party_account_type(party_type):
|
||||
if not hasattr(frappe.local, "party_account_types"):
|
||||
if not hasattr(frappe.local, 'party_account_types'):
|
||||
frappe.local.party_account_types = {}
|
||||
|
||||
if not party_type in frappe.local.party_account_types:
|
||||
frappe.local.party_account_types[party_type] = (
|
||||
frappe.db.get_value("Party Type", party_type, "account_type") or ""
|
||||
)
|
||||
frappe.local.party_account_types[party_type] = frappe.db.get_value("Party Type",
|
||||
party_type, "account_type") or ''
|
||||
|
||||
return frappe.local.party_account_types[party_type]
|
||||
|
||||
|
||||
def get_region(company=None):
|
||||
"""Return the default country based on flag, company or global settings
|
||||
'''Return the default country based on flag, company or global settings
|
||||
|
||||
You can also set global company flag in `frappe.flags.company`
|
||||
"""
|
||||
'''
|
||||
if company or frappe.flags.company:
|
||||
return frappe.get_cached_value("Company", company or frappe.flags.company, "country")
|
||||
return frappe.get_cached_value('Company',
|
||||
company or frappe.flags.company, 'country')
|
||||
elif frappe.flags.country:
|
||||
return frappe.flags.country
|
||||
else:
|
||||
return frappe.get_system_settings("country")
|
||||
|
||||
return frappe.get_system_settings('country')
|
||||
|
||||
def allow_regional(fn):
|
||||
"""Decorator to make a function regionally overridable
|
||||
'''Decorator to make a function regionally overridable
|
||||
|
||||
Example:
|
||||
@erpnext.allow_regional
|
||||
def myfunction():
|
||||
pass"""
|
||||
|
||||
pass'''
|
||||
def caller(*args, **kwargs):
|
||||
region = get_region()
|
||||
fn_name = inspect.getmodule(fn).__name__ + "." + fn.__name__
|
||||
fn_name = inspect.getmodule(fn).__name__ + '.' + fn.__name__
|
||||
if region in regional_overrides and fn_name in regional_overrides[region]:
|
||||
return frappe.get_attr(regional_overrides[region][fn_name])(*args, **kwargs)
|
||||
else:
|
||||
@@ -148,17 +132,16 @@ def allow_regional(fn):
|
||||
|
||||
return caller
|
||||
|
||||
def get_last_membership():
|
||||
'''Returns last membership if exists'''
|
||||
last_membership = frappe.get_all('Membership', 'name,to_date,membership_type',
|
||||
dict(member=frappe.session.user, paid=1), order_by='to_date desc', limit=1)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_last_membership(member):
|
||||
"""Returns last membership if exists"""
|
||||
last_membership = frappe.get_all(
|
||||
"Membership",
|
||||
"name,to_date,membership_type",
|
||||
dict(member=member, paid=1),
|
||||
order_by="to_date desc",
|
||||
limit=1,
|
||||
)
|
||||
return last_membership and last_membership[0]
|
||||
|
||||
if last_membership:
|
||||
return last_membership[0]
|
||||
def is_member():
|
||||
'''Returns true if the user is still a member'''
|
||||
last_membership = get_last_membership()
|
||||
if last_membership and getdate(last_membership.to_date) > getdate():
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
{
|
||||
"cards": [
|
||||
{
|
||||
"card": "Total Outgoing Bills"
|
||||
},
|
||||
{
|
||||
"card": "Total Incoming Bills"
|
||||
},
|
||||
{
|
||||
"card": "Total Incoming Payment"
|
||||
},
|
||||
{
|
||||
"card": "Total Outgoing Payment"
|
||||
}
|
||||
],
|
||||
"charts": [
|
||||
{
|
||||
"chart": "Profit and Loss",
|
||||
"width": "Full"
|
||||
},
|
||||
{
|
||||
"chart": "Incoming Bills (Purchase Invoice)",
|
||||
"width": "Half"
|
||||
},
|
||||
{
|
||||
"chart": "Outgoing Bills (Sales Invoice)",
|
||||
"width": "Half"
|
||||
},
|
||||
{
|
||||
"chart": "Accounts Receivable Ageing",
|
||||
"width": "Half"
|
||||
},
|
||||
{
|
||||
"chart": "Accounts Payable Ageing",
|
||||
"width": "Half"
|
||||
},
|
||||
{
|
||||
"chart": "Budget Variance",
|
||||
"width": "Full"
|
||||
},
|
||||
{
|
||||
"chart": "Bank Balance",
|
||||
"width": "Full"
|
||||
}
|
||||
],
|
||||
"creation": "2020-07-17 11:25:34.796608",
|
||||
"dashboard_name": "Accounts",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard",
|
||||
"idx": 0,
|
||||
"is_default": 0,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-22 13:07:34.540574",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts",
|
||||
"owner": "Administrator"
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
{
|
||||
"custom_fields": [
|
||||
{
|
||||
"_assign": null,
|
||||
"_comments": null,
|
||||
"_liked_by": null,
|
||||
"_user_tags": null,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"collapsible_depends_on": null,
|
||||
"columns": 0,
|
||||
"creation": "2018-12-28 22:29:21.828090",
|
||||
"default": null,
|
||||
"depends_on": null,
|
||||
"description": null,
|
||||
"docstatus": 0,
|
||||
"dt": "Address",
|
||||
"fetch_from": null,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "tax_category",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"hide_border": 0,
|
||||
"hide_days": 0,
|
||||
"hide_seconds": 0,
|
||||
"idx": 15,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_preview": 0,
|
||||
"in_standard_filter": 0,
|
||||
"insert_after": "fax",
|
||||
"label": "Tax Category",
|
||||
"length": 0,
|
||||
"mandatory_depends_on": null,
|
||||
"modified": "2018-12-28 22:29:21.828090",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Address-tax_category",
|
||||
"no_copy": 0,
|
||||
"options": "Tax Category",
|
||||
"owner": "Administrator",
|
||||
"parent": null,
|
||||
"parentfield": null,
|
||||
"parenttype": null,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": null,
|
||||
"read_only": 0,
|
||||
"read_only_depends_on": null,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0,
|
||||
"width": null
|
||||
},
|
||||
{
|
||||
"_assign": null,
|
||||
"_comments": null,
|
||||
"_liked_by": null,
|
||||
"_user_tags": null,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"collapsible_depends_on": null,
|
||||
"columns": 0,
|
||||
"creation": "2020-10-14 17:41:40.878179",
|
||||
"default": "0",
|
||||
"depends_on": null,
|
||||
"description": null,
|
||||
"docstatus": 0,
|
||||
"dt": "Address",
|
||||
"fetch_from": null,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "is_your_company_address",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"hide_border": 0,
|
||||
"hide_days": 0,
|
||||
"hide_seconds": 0,
|
||||
"idx": 20,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_preview": 0,
|
||||
"in_standard_filter": 0,
|
||||
"insert_after": "linked_with",
|
||||
"label": "Is Your Company Address",
|
||||
"length": 0,
|
||||
"mandatory_depends_on": null,
|
||||
"modified": "2020-10-14 17:41:40.878179",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Address-is_your_company_address",
|
||||
"no_copy": 0,
|
||||
"options": null,
|
||||
"owner": "Administrator",
|
||||
"parent": null,
|
||||
"parentfield": null,
|
||||
"parenttype": null,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": null,
|
||||
"read_only": 0,
|
||||
"read_only_depends_on": null,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0,
|
||||
"width": null
|
||||
}
|
||||
],
|
||||
"custom_perms": [],
|
||||
"doctype": "Address",
|
||||
"property_setters": [],
|
||||
"sync_on_migrate": 1
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.contacts.doctype.address.address import (
|
||||
Address,
|
||||
get_address_display,
|
||||
get_address_templates,
|
||||
)
|
||||
|
||||
|
||||
class ERPNextAddress(Address):
|
||||
def validate(self):
|
||||
self.validate_reference()
|
||||
super(ERPNextAddress, self).validate()
|
||||
|
||||
def link_address(self):
|
||||
"""Link address based on owner"""
|
||||
if self.is_your_company_address:
|
||||
return
|
||||
|
||||
return super(ERPNextAddress, self).link_address()
|
||||
|
||||
def validate_reference(self):
|
||||
if self.is_your_company_address and not [
|
||||
row for row in self.links if row.link_doctype == "Company"
|
||||
]:
|
||||
frappe.throw(
|
||||
_("Address needs to be linked to a Company. Please add a row for Company in the Links table."),
|
||||
title=_("Company Not Linked"),
|
||||
)
|
||||
|
||||
def on_update(self):
|
||||
"""
|
||||
After Address is updated, update the related 'Primary Address' on Customer.
|
||||
"""
|
||||
address_display = get_address_display(self.as_dict())
|
||||
filters = {"customer_primary_address": self.name}
|
||||
customers = frappe.db.get_all("Customer", filters=filters, as_list=True)
|
||||
for customer_name in customers:
|
||||
frappe.db.set_value("Customer", customer_name[0], "primary_address", address_display)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_shipping_address(company, address=None):
|
||||
filters = [
|
||||
["Dynamic Link", "link_doctype", "=", "Company"],
|
||||
["Dynamic Link", "link_name", "=", company],
|
||||
["Address", "is_your_company_address", "=", 1],
|
||||
]
|
||||
fields = ["*"]
|
||||
if address and frappe.db.get_value("Dynamic Link", {"parent": address, "link_name": company}):
|
||||
filters.append(["Address", "name", "=", address])
|
||||
if not address:
|
||||
filters.append(["Address", "is_shipping_address", "=", 1])
|
||||
|
||||
address = frappe.get_all("Address", filters=filters, fields=fields) or {}
|
||||
|
||||
if address:
|
||||
address_as_dict = address[0]
|
||||
name, address_template = get_address_templates(address_as_dict)
|
||||
return address_as_dict.get("name"), frappe.render_template(address_template, address_as_dict)
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"chart_name": "Accounts Payable Ageing",
|
||||
"chart_type": "Report",
|
||||
"creation": "2020-07-17 11:25:34.564015",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"report_date\":\"frappe.datetime.now_date()\"}",
|
||||
"filters_json": "{\"ageing_based_on\":\"Due Date\",\"range1\":30,\"range2\":60,\"range3\":90,\"range4\":120,\"group_by_party\":0,\"based_on_payment_terms\":0}",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-22 12:29:33.584419",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Payable Ageing",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"report_name": "Accounts Payable",
|
||||
"timeseries": 0,
|
||||
"type": "Donut",
|
||||
"use_report_chart": 1,
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"chart_name": "Accounts Receivable Ageing",
|
||||
"chart_type": "Report",
|
||||
"creation": "2020-07-17 11:25:34.535388",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"report_date\":\"frappe.datetime.now_date()\"}",
|
||||
"filters_json": "{\"ageing_based_on\":\"Due Date\",\"range1\":30,\"range2\":60,\"range3\":90,\"range4\":120,\"group_by_party\":0,\"based_on_payment_terms\":0,\"show_future_payments\":0,\"show_delivery_notes\":0,\"show_sales_person\":0}",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-22 12:28:42.743551",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Receivable Ageing",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"report_name": "Accounts Receivable",
|
||||
"timeseries": 0,
|
||||
"type": "Donut",
|
||||
"use_report_chart": 1,
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"chart_name": "Bank Balance",
|
||||
"chart_type": "Custom",
|
||||
"creation": "2020-07-17 11:25:34.620221",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"account\":\"locals[\\\":Company\\\"][frappe.defaults.get_user_default(\\\"Company\\\")][\\\"default_bank_account\\\"]\"}",
|
||||
"filters_json": "{}",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"last_synced_on": "2020-07-22 12:19:59.879476",
|
||||
"modified": "2020-07-22 12:21:48.780513",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Balance",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"source": "Account Balance Timeline",
|
||||
"time_interval": "Quarterly",
|
||||
"timeseries": 0,
|
||||
"timespan": "Last Year",
|
||||
"type": "Line",
|
||||
"use_report_chart": 0,
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"chart_name": "Budget Variance",
|
||||
"chart_type": "Report",
|
||||
"creation": "2020-07-17 11:25:34.593061",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_fiscal_year\":\"frappe.sys_defaults.fiscal_year\",\"to_fiscal_year\":\"frappe.sys_defaults.fiscal_year\"}",
|
||||
"filters_json": "{\"period\":\"Monthly\",\"budget_against\":\"Cost Center\",\"show_cumulative\":0}",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-22 12:24:49.144210",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Budget Variance",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"report_name": "Budget Variance Report",
|
||||
"timeseries": 0,
|
||||
"type": "Bar",
|
||||
"use_report_chart": 1,
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"based_on": "posting_date",
|
||||
"chart_name": "Incoming Bills (Purchase Invoice)",
|
||||
"chart_type": "Sum",
|
||||
"color": "#a83333",
|
||||
"creation": "2020-07-17 11:25:34.479703",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"document_type": "Purchase Invoice",
|
||||
"dynamic_filters_json": "",
|
||||
"filters_json": "[[\"Purchase Invoice\",\"docstatus\",\"=\",1]]",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"last_synced_on": "2020-07-21 17:37:30.727306",
|
||||
"modified": "2020-07-21 17:51:07.374917",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Incoming Bills (Purchase Invoice)",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"time_interval": "Monthly",
|
||||
"timeseries": 1,
|
||||
"timespan": "Last Year",
|
||||
"type": "Bar",
|
||||
"use_report_chart": 0,
|
||||
"value_based_on": "base_net_total",
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"based_on": "posting_date",
|
||||
"chart_name": "Outgoing Bills (Sales Invoice)",
|
||||
"chart_type": "Sum",
|
||||
"color": "#7b933d",
|
||||
"creation": "2020-07-17 11:25:34.507547",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"document_type": "Sales Invoice",
|
||||
"filters_json": "[[\"Sales Invoice\",\"docstatus\",\"=\",1]]",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"last_synced_on": "2020-07-21 17:37:31.574666",
|
||||
"modified": "2020-07-21 17:52:03.970530",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Outgoing Bills (Sales Invoice)",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"time_interval": "Monthly",
|
||||
"timeseries": 1,
|
||||
"timespan": "Last Year",
|
||||
"type": "Bar",
|
||||
"use_report_chart": 0,
|
||||
"value_based_on": "base_net_total",
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"chart_name": "Profit and Loss",
|
||||
"chart_type": "Report",
|
||||
"creation": "2020-07-17 11:25:34.448572",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_fiscal_year\":\"frappe.sys_defaults.fiscal_year\",\"to_fiscal_year\":\"frappe.sys_defaults.fiscal_year\"}",
|
||||
"filters_json": "{\"filter_based_on\":\"Fiscal Year\",\"period_start_date\":\"2020-04-01\",\"period_end_date\":\"2021-03-31\",\"periodicity\":\"Yearly\",\"include_default_book_entries\":1}",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-22 12:33:48.888943",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Profit and Loss",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"report_name": "Profit and Loss Statement",
|
||||
"timeseries": 0,
|
||||
"type": "Bar",
|
||||
"use_report_chart": 1,
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
frappe.provide('frappe.dashboards.chart_sources');
|
||||
|
||||
frappe.dashboards.chart_sources["Account Balance Timeline"] = {
|
||||
method: "erpnext.accounts.dashboard_chart_source.account_balance_timeline.account_balance_timeline.get",
|
||||
filters: [
|
||||
{
|
||||
fieldname: "company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
default: frappe.defaults.get_user_default("Company"),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "account",
|
||||
label: __("Account"),
|
||||
fieldtype: "Link",
|
||||
options: "Account",
|
||||
reqd: 1
|
||||
},
|
||||
]
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"creation": "2019-02-06 07:57:10.377718",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart Source",
|
||||
"idx": 0,
|
||||
"modified": "2019-04-09 18:30:49.943174",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account Balance Timeline",
|
||||
"owner": "Administrator",
|
||||
"source_name": "Account Balance Timeline",
|
||||
"timeseries": 1
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import add_to_date, formatdate, get_link_to_form, getdate, nowdate
|
||||
from frappe.utils.dashboard import cache_source
|
||||
from frappe.utils.dateutils import get_from_date_from_timespan, get_period_ending
|
||||
from frappe.utils.nestedset import get_descendants_of
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@cache_source
|
||||
def get(
|
||||
chart_name=None,
|
||||
chart=None,
|
||||
no_cache=None,
|
||||
filters=None,
|
||||
from_date=None,
|
||||
to_date=None,
|
||||
timespan=None,
|
||||
time_interval=None,
|
||||
heatmap_year=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 = frappe.parse_json(filters) or frappe.parse_json(chart.filters_json)
|
||||
|
||||
account = filters.get("account")
|
||||
company = filters.get("company")
|
||||
|
||||
if not account and chart_name:
|
||||
frappe.throw(
|
||||
_("Account is not set for the dashboard chart {0}").format(
|
||||
get_link_to_form("Dashboard Chart", chart_name)
|
||||
)
|
||||
)
|
||||
|
||||
if not frappe.db.exists("Account", account) and chart_name:
|
||||
frappe.throw(
|
||||
_("Account {0} does not exists in the dashboard chart {1}").format(
|
||||
account, get_link_to_form("Dashboard Chart", chart_name)
|
||||
)
|
||||
)
|
||||
|
||||
if not to_date:
|
||||
to_date = nowdate()
|
||||
if not from_date:
|
||||
if timegrain in ("Monthly", "Quarterly"):
|
||||
from_date = get_from_date_from_timespan(to_date, timespan)
|
||||
|
||||
# fetch dates to plot
|
||||
dates = get_dates_from_timegrain(from_date, to_date, timegrain)
|
||||
|
||||
# get all the entries for this account and its descendants
|
||||
gl_entries = get_gl_entries(account, get_period_ending(to_date, timegrain))
|
||||
|
||||
# compile balance values
|
||||
result = build_result(account, dates, gl_entries)
|
||||
|
||||
return {
|
||||
"labels": [formatdate(r[0].strftime("%Y-%m-%d")) for r in result],
|
||||
"datasets": [{"name": account, "values": [r[1] for r in result]}],
|
||||
}
|
||||
|
||||
|
||||
def build_result(account, dates, gl_entries):
|
||||
result = [[getdate(date), 0.0] for date in dates]
|
||||
root_type = frappe.db.get_value("Account", account, "root_type")
|
||||
|
||||
# start with the first date
|
||||
date_index = 0
|
||||
|
||||
# get balances in debit
|
||||
for entry in gl_entries:
|
||||
|
||||
# entry date is after the current pointer, so move the pointer forward
|
||||
while getdate(entry.posting_date) > result[date_index][0]:
|
||||
date_index += 1
|
||||
|
||||
result[date_index][1] += entry.debit - entry.credit
|
||||
|
||||
# if account type is credit, switch balances
|
||||
if root_type not in ("Asset", "Expense"):
|
||||
for r in result:
|
||||
r[1] = -1 * r[1]
|
||||
|
||||
# for balance sheet accounts, the totals are cumulative
|
||||
if root_type in ("Asset", "Liability", "Equity"):
|
||||
for i, r in enumerate(result):
|
||||
if i > 0:
|
||||
r[1] = r[1] + result[i - 1][1]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_gl_entries(account, to_date):
|
||||
child_accounts = get_descendants_of("Account", account, ignore_permissions=True)
|
||||
child_accounts.append(account)
|
||||
|
||||
return frappe.db.get_all(
|
||||
"GL Entry",
|
||||
fields=["posting_date", "debit", "credit"],
|
||||
filters=[
|
||||
dict(posting_date=("<", to_date)),
|
||||
dict(account=("in", child_accounts)),
|
||||
dict(voucher_type=("!=", "Period Closing Voucher")),
|
||||
],
|
||||
order_by="posting_date asc",
|
||||
)
|
||||
|
||||
|
||||
def get_dates_from_timegrain(from_date, to_date, timegrain):
|
||||
days = months = years = 0
|
||||
if "Daily" == timegrain:
|
||||
days = 1
|
||||
elif "Weekly" == timegrain:
|
||||
days = 7
|
||||
elif "Monthly" == timegrain:
|
||||
months = 1
|
||||
elif "Quarterly" == timegrain:
|
||||
months = 3
|
||||
|
||||
dates = [get_period_ending(from_date, timegrain)]
|
||||
while getdate(dates[-1]) < getdate(to_date):
|
||||
date = get_period_ending(
|
||||
add_to_date(dates[-1], years=years, months=months, days=days), timegrain
|
||||
)
|
||||
dates.append(date)
|
||||
return dates
|
||||
@@ -1,44 +1,26 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.email import sendmail_to_system_managers
|
||||
from frappe.utils import (
|
||||
add_days,
|
||||
add_months,
|
||||
cint,
|
||||
date_diff,
|
||||
flt,
|
||||
get_first_day,
|
||||
get_last_day,
|
||||
get_link_to_form,
|
||||
getdate,
|
||||
rounded,
|
||||
today,
|
||||
)
|
||||
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
|
||||
get_accounting_dimensions,
|
||||
)
|
||||
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt, get_last_day
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
|
||||
from frappe.email import sendmail_to_system_managers
|
||||
|
||||
def validate_service_stop_date(doc):
|
||||
"""Validates service_stop_date for Purchase Invoice and Sales Invoice"""
|
||||
''' Validates service_stop_date for Purchase Invoice and Sales Invoice '''
|
||||
|
||||
enable_check = (
|
||||
"enable_deferred_revenue" if doc.doctype == "Sales Invoice" else "enable_deferred_expense"
|
||||
)
|
||||
enable_check = "enable_deferred_revenue" \
|
||||
if doc.doctype=="Sales Invoice" else "enable_deferred_expense"
|
||||
|
||||
old_stop_dates = {}
|
||||
old_doc = frappe.db.get_all(
|
||||
"{0} Item".format(doc.doctype), {"parent": doc.name}, ["name", "service_stop_date"]
|
||||
)
|
||||
old_doc = frappe.db.get_all("{0} Item".format(doc.doctype),
|
||||
{"parent": doc.name}, ["name", "service_stop_date"])
|
||||
|
||||
for d in old_doc:
|
||||
old_stop_dates[d.name] = d.service_stop_date or ""
|
||||
|
||||
for item in doc.items:
|
||||
if not item.get(enable_check):
|
||||
continue
|
||||
if not item.get(enable_check): continue
|
||||
|
||||
if item.service_stop_date:
|
||||
if date_diff(item.service_stop_date, item.service_start_date) < 0:
|
||||
@@ -47,94 +29,45 @@ def validate_service_stop_date(doc):
|
||||
if date_diff(item.service_stop_date, item.service_end_date) > 0:
|
||||
frappe.throw(_("Service Stop Date cannot be after Service End Date"))
|
||||
|
||||
if (
|
||||
old_stop_dates
|
||||
and old_stop_dates.get(item.name)
|
||||
and item.service_stop_date != old_stop_dates.get(item.name)
|
||||
):
|
||||
frappe.throw(_("Cannot change Service Stop Date for item in row {0}").format(item.idx))
|
||||
if old_stop_dates and old_stop_dates.get(item.name) and item.service_stop_date!=old_stop_dates[item.name]:
|
||||
frappe.throw(_("Cannot change Service Stop Date for item in row {0}".format(item.idx)))
|
||||
|
||||
|
||||
def build_conditions(process_type, account, company):
|
||||
conditions = ""
|
||||
deferred_account = (
|
||||
"item.deferred_revenue_account" if process_type == "Income" else "item.deferred_expense_account"
|
||||
)
|
||||
|
||||
if account:
|
||||
conditions += "AND %s='%s'" % (deferred_account, account)
|
||||
elif company:
|
||||
conditions += f"AND p.company = {frappe.db.escape(company)}"
|
||||
|
||||
return conditions
|
||||
|
||||
|
||||
def convert_deferred_expense_to_expense(
|
||||
deferred_process, start_date=None, end_date=None, conditions=""
|
||||
):
|
||||
def convert_deferred_expense_to_expense(start_date=None, end_date=None):
|
||||
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
|
||||
|
||||
if not start_date:
|
||||
start_date = add_months(today(), -1)
|
||||
if not end_date:
|
||||
end_date = add_days(today(), -1)
|
||||
|
||||
# check for the purchase invoice for which GL entries has to be done
|
||||
invoices = frappe.db.sql_list(
|
||||
"""
|
||||
select distinct item.parent
|
||||
from `tabPurchase Invoice Item` item, `tabPurchase Invoice` p
|
||||
where item.service_start_date<=%s and item.service_end_date>=%s
|
||||
and item.enable_deferred_expense = 1 and item.parent=p.name
|
||||
and item.docstatus = 1 and ifnull(item.amount, 0) > 0
|
||||
{0}
|
||||
""".format(
|
||||
conditions
|
||||
),
|
||||
(end_date, start_date),
|
||||
) # nosec
|
||||
invoices = frappe.db.sql_list('''
|
||||
select distinct parent from `tabPurchase Invoice Item`
|
||||
where service_start_date<=%s and service_end_date>=%s
|
||||
and enable_deferred_expense = 1 and docstatus = 1 and ifnull(amount, 0) > 0
|
||||
''', (end_date, start_date))
|
||||
|
||||
# For each invoice, book deferred expense
|
||||
for invoice in invoices:
|
||||
doc = frappe.get_doc("Purchase Invoice", invoice)
|
||||
book_deferred_income_or_expense(doc, deferred_process, end_date)
|
||||
book_deferred_income_or_expense(doc, end_date)
|
||||
|
||||
if frappe.flags.deferred_accounting_error:
|
||||
send_mail(deferred_process)
|
||||
|
||||
|
||||
def convert_deferred_revenue_to_income(
|
||||
deferred_process, start_date=None, end_date=None, conditions=""
|
||||
):
|
||||
def convert_deferred_revenue_to_income(start_date=None, end_date=None):
|
||||
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
|
||||
|
||||
if not start_date:
|
||||
start_date = add_months(today(), -1)
|
||||
if not end_date:
|
||||
end_date = add_days(today(), -1)
|
||||
|
||||
# check for the sales invoice for which GL entries has to be done
|
||||
invoices = frappe.db.sql_list(
|
||||
"""
|
||||
select distinct item.parent
|
||||
from `tabSales Invoice Item` item, `tabSales Invoice` p
|
||||
where item.service_start_date<=%s and item.service_end_date>=%s
|
||||
and item.enable_deferred_revenue = 1 and item.parent=p.name
|
||||
and item.docstatus = 1 and ifnull(item.amount, 0) > 0
|
||||
{0}
|
||||
""".format(
|
||||
conditions
|
||||
),
|
||||
(end_date, start_date),
|
||||
) # nosec
|
||||
invoices = frappe.db.sql_list('''
|
||||
select distinct parent from `tabSales Invoice Item`
|
||||
where service_start_date<=%s and service_end_date>=%s
|
||||
and enable_deferred_revenue = 1 and docstatus = 1 and ifnull(amount, 0) > 0
|
||||
''', (end_date, start_date))
|
||||
|
||||
for invoice in invoices:
|
||||
doc = frappe.get_doc("Sales Invoice", invoice)
|
||||
book_deferred_income_or_expense(doc, deferred_process, end_date)
|
||||
|
||||
if frappe.flags.deferred_accounting_error:
|
||||
send_mail(deferred_process)
|
||||
|
||||
book_deferred_income_or_expense(doc, end_date)
|
||||
|
||||
def get_booking_dates(doc, item, posting_date=None):
|
||||
if not posting_date:
|
||||
@@ -142,37 +75,13 @@ def get_booking_dates(doc, item, posting_date=None):
|
||||
|
||||
last_gl_entry = False
|
||||
|
||||
deferred_account = (
|
||||
"deferred_revenue_account" if doc.doctype == "Sales Invoice" else "deferred_expense_account"
|
||||
)
|
||||
deferred_account = "deferred_revenue_account" if doc.doctype=="Sales Invoice" else "deferred_expense_account"
|
||||
|
||||
prev_gl_entry = frappe.db.sql(
|
||||
"""
|
||||
prev_gl_entry = frappe.db.sql('''
|
||||
select name, posting_date from `tabGL Entry` where company=%s and account=%s and
|
||||
voucher_type=%s and voucher_no=%s and voucher_detail_no=%s
|
||||
and is_cancelled = 0
|
||||
order by posting_date desc limit 1
|
||||
""",
|
||||
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name),
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
prev_gl_via_je = frappe.db.sql(
|
||||
"""
|
||||
SELECT p.name, p.posting_date FROM `tabJournal Entry` p, `tabJournal Entry Account` c
|
||||
WHERE p.name = c.parent and p.company=%s and c.account=%s
|
||||
and c.reference_type=%s and c.reference_name=%s
|
||||
and c.reference_detail_no=%s and c.docstatus < 2 order by posting_date desc limit 1
|
||||
""",
|
||||
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name),
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
if prev_gl_via_je:
|
||||
if (not prev_gl_entry) or (
|
||||
prev_gl_entry and prev_gl_entry[0].posting_date < prev_gl_via_je[0].posting_date
|
||||
):
|
||||
prev_gl_entry = prev_gl_via_je
|
||||
''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
|
||||
|
||||
if prev_gl_entry:
|
||||
start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
|
||||
@@ -195,95 +104,7 @@ def get_booking_dates(doc, item, posting_date=None):
|
||||
else:
|
||||
return None, None, None
|
||||
|
||||
|
||||
def calculate_monthly_amount(
|
||||
doc, item, last_gl_entry, start_date, end_date, total_days, total_booking_days, account_currency
|
||||
):
|
||||
amount, base_amount = 0, 0
|
||||
|
||||
if not last_gl_entry:
|
||||
total_months = (
|
||||
(item.service_end_date.year - item.service_start_date.year) * 12
|
||||
+ (item.service_end_date.month - item.service_start_date.month)
|
||||
+ 1
|
||||
)
|
||||
|
||||
prorate_factor = flt(date_diff(item.service_end_date, item.service_start_date)) / flt(
|
||||
date_diff(get_last_day(item.service_end_date), get_first_day(item.service_start_date))
|
||||
)
|
||||
|
||||
actual_months = rounded(total_months * prorate_factor, 1)
|
||||
|
||||
already_booked_amount, already_booked_amount_in_account_currency = get_already_booked_amount(
|
||||
doc, item
|
||||
)
|
||||
base_amount = flt(item.base_net_amount / actual_months, item.precision("base_net_amount"))
|
||||
|
||||
if base_amount + already_booked_amount > item.base_net_amount:
|
||||
base_amount = item.base_net_amount - already_booked_amount
|
||||
|
||||
if account_currency == doc.company_currency:
|
||||
amount = base_amount
|
||||
else:
|
||||
amount = flt(item.net_amount / actual_months, item.precision("net_amount"))
|
||||
if amount + already_booked_amount_in_account_currency > item.net_amount:
|
||||
amount = item.net_amount - already_booked_amount_in_account_currency
|
||||
|
||||
if not (get_first_day(start_date) == start_date and get_last_day(end_date) == end_date):
|
||||
partial_month = flt(date_diff(end_date, start_date)) / flt(
|
||||
date_diff(get_last_day(end_date), get_first_day(start_date))
|
||||
)
|
||||
|
||||
base_amount = rounded(partial_month, 1) * base_amount
|
||||
amount = rounded(partial_month, 1) * amount
|
||||
else:
|
||||
already_booked_amount, already_booked_amount_in_account_currency = get_already_booked_amount(
|
||||
doc, item
|
||||
)
|
||||
base_amount = flt(
|
||||
item.base_net_amount - already_booked_amount, item.precision("base_net_amount")
|
||||
)
|
||||
if account_currency == doc.company_currency:
|
||||
amount = base_amount
|
||||
else:
|
||||
amount = flt(
|
||||
item.net_amount - already_booked_amount_in_account_currency, item.precision("net_amount")
|
||||
)
|
||||
|
||||
return amount, base_amount
|
||||
|
||||
|
||||
def calculate_amount(doc, item, last_gl_entry, total_days, total_booking_days, account_currency):
|
||||
amount, base_amount = 0, 0
|
||||
if not last_gl_entry:
|
||||
base_amount = flt(
|
||||
item.base_net_amount * total_booking_days / flt(total_days), item.precision("base_net_amount")
|
||||
)
|
||||
if account_currency == doc.company_currency:
|
||||
amount = base_amount
|
||||
else:
|
||||
amount = flt(
|
||||
item.net_amount * total_booking_days / flt(total_days), item.precision("net_amount")
|
||||
)
|
||||
else:
|
||||
already_booked_amount, already_booked_amount_in_account_currency = get_already_booked_amount(
|
||||
doc, item
|
||||
)
|
||||
|
||||
base_amount = flt(
|
||||
item.base_net_amount - already_booked_amount, item.precision("base_net_amount")
|
||||
)
|
||||
if account_currency == doc.company_currency:
|
||||
amount = base_amount
|
||||
else:
|
||||
amount = flt(
|
||||
item.net_amount - already_booked_amount_in_account_currency, item.precision("net_amount")
|
||||
)
|
||||
|
||||
return amount, base_amount
|
||||
|
||||
|
||||
def get_already_booked_amount(doc, item):
|
||||
if doc.doctype == "Sales Invoice":
|
||||
total_credit_debit, total_credit_debit_currency = "debit", "debit_in_account_currency"
|
||||
deferred_account = "deferred_revenue_account"
|
||||
@@ -291,63 +112,39 @@ def get_already_booked_amount(doc, item):
|
||||
total_credit_debit, total_credit_debit_currency = "credit", "credit_in_account_currency"
|
||||
deferred_account = "deferred_expense_account"
|
||||
|
||||
gl_entries_details = frappe.db.sql(
|
||||
"""
|
||||
select sum({0}) as total_credit, sum({1}) as total_credit_in_account_currency, voucher_detail_no
|
||||
from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s
|
||||
and is_cancelled = 0
|
||||
group by voucher_detail_no
|
||||
""".format(
|
||||
total_credit_debit, total_credit_debit_currency
|
||||
),
|
||||
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name),
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
journal_entry_details = frappe.db.sql(
|
||||
"""
|
||||
SELECT sum(c.{0}) as total_credit, sum(c.{1}) as total_credit_in_account_currency, reference_detail_no
|
||||
FROM `tabJournal Entry` p , `tabJournal Entry Account` c WHERE p.name = c.parent and
|
||||
p.company = %s and c.account=%s and c.reference_type=%s and c.reference_name=%s and c.reference_detail_no=%s
|
||||
and p.docstatus < 2 group by reference_detail_no
|
||||
""".format(
|
||||
total_credit_debit, total_credit_debit_currency
|
||||
),
|
||||
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name),
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
already_booked_amount = gl_entries_details[0].total_credit if gl_entries_details else 0
|
||||
already_booked_amount += journal_entry_details[0].total_credit if journal_entry_details else 0
|
||||
|
||||
if doc.currency == doc.company_currency:
|
||||
already_booked_amount_in_account_currency = already_booked_amount
|
||||
amount, base_amount = 0, 0
|
||||
if not last_gl_entry:
|
||||
base_amount = flt(item.base_net_amount*total_booking_days/flt(total_days), item.precision("base_net_amount"))
|
||||
if account_currency==doc.company_currency:
|
||||
amount = base_amount
|
||||
else:
|
||||
amount = flt(item.net_amount*total_booking_days/flt(total_days), item.precision("net_amount"))
|
||||
else:
|
||||
already_booked_amount_in_account_currency = (
|
||||
gl_entries_details[0].total_credit_in_account_currency if gl_entries_details else 0
|
||||
)
|
||||
already_booked_amount_in_account_currency += (
|
||||
journal_entry_details[0].total_credit_in_account_currency if journal_entry_details else 0
|
||||
)
|
||||
gl_entries_details = frappe.db.sql('''
|
||||
select sum({0}) as total_credit, sum({1}) as total_credit_in_account_currency, voucher_detail_no
|
||||
from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s
|
||||
group by voucher_detail_no
|
||||
'''.format(total_credit_debit, total_credit_debit_currency),
|
||||
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
|
||||
already_booked_amount = gl_entries_details[0].total_credit if gl_entries_details else 0
|
||||
base_amount = flt(item.base_net_amount - already_booked_amount, item.precision("base_net_amount"))
|
||||
if account_currency==doc.company_currency:
|
||||
amount = base_amount
|
||||
else:
|
||||
already_booked_amount_in_account_currency = gl_entries_details[0].total_credit_in_account_currency if gl_entries_details else 0
|
||||
amount = flt(item.net_amount - already_booked_amount_in_account_currency, item.precision("net_amount"))
|
||||
|
||||
return already_booked_amount, already_booked_amount_in_account_currency
|
||||
return amount, base_amount
|
||||
|
||||
def book_deferred_income_or_expense(doc, posting_date=None):
|
||||
enable_check = "enable_deferred_revenue" \
|
||||
if doc.doctype=="Sales Invoice" else "enable_deferred_expense"
|
||||
|
||||
def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
|
||||
enable_check = (
|
||||
"enable_deferred_revenue" if doc.doctype == "Sales Invoice" else "enable_deferred_expense"
|
||||
)
|
||||
|
||||
accounts_frozen_upto = frappe.get_cached_value("Accounts Settings", "None", "acc_frozen_upto")
|
||||
|
||||
def _book_deferred_revenue_or_expense(
|
||||
item, via_journal_entry, submit_journal_entry, book_deferred_entries_based_on
|
||||
):
|
||||
def _book_deferred_revenue_or_expense(item):
|
||||
start_date, end_date, last_gl_entry = get_booking_dates(doc, item, posting_date=posting_date)
|
||||
if not (start_date and end_date):
|
||||
return
|
||||
if not (start_date and end_date): return
|
||||
|
||||
account_currency = get_account_currency(item.expense_account or item.income_account)
|
||||
account_currency = get_account_currency(item.expense_account)
|
||||
if doc.doctype == "Sales Invoice":
|
||||
against, project = doc.customer, doc.project
|
||||
credit_account, debit_account = item.income_account, item.deferred_revenue_account
|
||||
@@ -358,305 +155,61 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
|
||||
total_days = date_diff(item.service_end_date, item.service_start_date) + 1
|
||||
total_booking_days = date_diff(end_date, start_date) + 1
|
||||
|
||||
if book_deferred_entries_based_on == "Months":
|
||||
amount, base_amount = calculate_monthly_amount(
|
||||
doc,
|
||||
item,
|
||||
last_gl_entry,
|
||||
start_date,
|
||||
end_date,
|
||||
total_days,
|
||||
total_booking_days,
|
||||
account_currency,
|
||||
)
|
||||
else:
|
||||
amount, base_amount = calculate_amount(
|
||||
doc, item, last_gl_entry, total_days, total_booking_days, account_currency
|
||||
)
|
||||
amount, base_amount = calculate_amount(doc, item, last_gl_entry,
|
||||
total_days, total_booking_days, account_currency)
|
||||
|
||||
if not amount:
|
||||
return
|
||||
|
||||
# check if books nor frozen till endate:
|
||||
if accounts_frozen_upto and (end_date) <= getdate(accounts_frozen_upto):
|
||||
end_date = get_last_day(add_days(accounts_frozen_upto, 1))
|
||||
|
||||
if via_journal_entry:
|
||||
book_revenue_via_journal_entry(
|
||||
doc,
|
||||
credit_account,
|
||||
debit_account,
|
||||
amount,
|
||||
base_amount,
|
||||
end_date,
|
||||
project,
|
||||
account_currency,
|
||||
item.cost_center,
|
||||
item,
|
||||
deferred_process,
|
||||
submit_journal_entry,
|
||||
)
|
||||
else:
|
||||
make_gl_entries(
|
||||
doc,
|
||||
credit_account,
|
||||
debit_account,
|
||||
against,
|
||||
amount,
|
||||
base_amount,
|
||||
end_date,
|
||||
project,
|
||||
account_currency,
|
||||
item.cost_center,
|
||||
item,
|
||||
deferred_process,
|
||||
)
|
||||
|
||||
# Returned in case of any errors because it tries to submit the same record again and again in case of errors
|
||||
if frappe.flags.deferred_accounting_error:
|
||||
return
|
||||
make_gl_entries(doc, credit_account, debit_account, against,
|
||||
amount, base_amount, end_date, project, account_currency, item.cost_center, item.name)
|
||||
|
||||
if getdate(end_date) < getdate(posting_date) and not last_gl_entry:
|
||||
_book_deferred_revenue_or_expense(
|
||||
item, via_journal_entry, submit_journal_entry, book_deferred_entries_based_on
|
||||
)
|
||||
_book_deferred_revenue_or_expense(item)
|
||||
|
||||
via_journal_entry = cint(
|
||||
frappe.db.get_singles_value("Accounts Settings", "book_deferred_entries_via_journal_entry")
|
||||
)
|
||||
submit_journal_entry = cint(
|
||||
frappe.db.get_singles_value("Accounts Settings", "submit_journal_entries")
|
||||
)
|
||||
book_deferred_entries_based_on = frappe.db.get_singles_value(
|
||||
"Accounts Settings", "book_deferred_entries_based_on"
|
||||
)
|
||||
|
||||
for item in doc.get("items"):
|
||||
for item in doc.get('items'):
|
||||
if item.get(enable_check):
|
||||
_book_deferred_revenue_or_expense(
|
||||
item, via_journal_entry, submit_journal_entry, book_deferred_entries_based_on
|
||||
)
|
||||
_book_deferred_revenue_or_expense(item)
|
||||
|
||||
|
||||
def process_deferred_accounting(posting_date=None):
|
||||
"""Converts deferred income/expense into income/expense
|
||||
Executed via background jobs on every month end"""
|
||||
|
||||
if not posting_date:
|
||||
posting_date = today()
|
||||
|
||||
if not cint(
|
||||
frappe.db.get_singles_value(
|
||||
"Accounts Settings", "automatically_process_deferred_accounting_entry"
|
||||
)
|
||||
):
|
||||
return
|
||||
|
||||
start_date = add_months(today(), -1)
|
||||
end_date = add_days(today(), -1)
|
||||
|
||||
companies = frappe.get_all("Company")
|
||||
|
||||
for company in companies:
|
||||
for record_type in ("Income", "Expense"):
|
||||
doc = frappe.get_doc(
|
||||
dict(
|
||||
doctype="Process Deferred Accounting",
|
||||
company=company.name,
|
||||
posting_date=posting_date,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
type=record_type,
|
||||
)
|
||||
)
|
||||
|
||||
doc.insert()
|
||||
doc.submit()
|
||||
|
||||
|
||||
def make_gl_entries(
|
||||
doc,
|
||||
credit_account,
|
||||
debit_account,
|
||||
against,
|
||||
amount,
|
||||
base_amount,
|
||||
posting_date,
|
||||
project,
|
||||
account_currency,
|
||||
cost_center,
|
||||
item,
|
||||
deferred_process=None,
|
||||
):
|
||||
def make_gl_entries(doc, credit_account, debit_account, against,
|
||||
amount, base_amount, posting_date, project, account_currency, cost_center, voucher_detail_no):
|
||||
# GL Entry for crediting the amount in the deferred expense
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
|
||||
if amount == 0:
|
||||
return
|
||||
if amount == 0: return
|
||||
|
||||
gl_entries = []
|
||||
gl_entries.append(
|
||||
doc.get_gl_dict(
|
||||
{
|
||||
"account": credit_account,
|
||||
"against": against,
|
||||
"credit": base_amount,
|
||||
"credit_in_account_currency": amount,
|
||||
"cost_center": cost_center,
|
||||
"voucher_detail_no": item.name,
|
||||
"posting_date": posting_date,
|
||||
"project": project,
|
||||
"against_voucher_type": "Process Deferred Accounting",
|
||||
"against_voucher": deferred_process,
|
||||
},
|
||||
account_currency,
|
||||
item=item,
|
||||
)
|
||||
doc.get_gl_dict({
|
||||
"account": credit_account,
|
||||
"against": against,
|
||||
"credit": base_amount,
|
||||
"credit_in_account_currency": amount,
|
||||
"cost_center": cost_center,
|
||||
"voucher_detail_no": voucher_detail_no,
|
||||
'posting_date': posting_date,
|
||||
'project': project
|
||||
}, account_currency)
|
||||
)
|
||||
# GL Entry to debit the amount from the expense
|
||||
gl_entries.append(
|
||||
doc.get_gl_dict(
|
||||
{
|
||||
"account": debit_account,
|
||||
"against": against,
|
||||
"debit": base_amount,
|
||||
"debit_in_account_currency": amount,
|
||||
"cost_center": cost_center,
|
||||
"voucher_detail_no": item.name,
|
||||
"posting_date": posting_date,
|
||||
"project": project,
|
||||
"against_voucher_type": "Process Deferred Accounting",
|
||||
"against_voucher": deferred_process,
|
||||
},
|
||||
account_currency,
|
||||
item=item,
|
||||
)
|
||||
doc.get_gl_dict({
|
||||
"account": debit_account,
|
||||
"against": against,
|
||||
"debit": base_amount,
|
||||
"debit_in_account_currency": amount,
|
||||
"cost_center": cost_center,
|
||||
"voucher_detail_no": voucher_detail_no,
|
||||
'posting_date': posting_date,
|
||||
'project': project
|
||||
}, account_currency)
|
||||
)
|
||||
|
||||
if gl_entries:
|
||||
try:
|
||||
make_gl_entries(gl_entries, cancel=(doc.docstatus == 2), merge_entries=True)
|
||||
frappe.db.commit()
|
||||
except Exception as e:
|
||||
if frappe.flags.in_test:
|
||||
traceback = frappe.get_traceback()
|
||||
frappe.log_error(
|
||||
title=_("Error while processing deferred accounting for Invoice {0}").format(doc.name),
|
||||
message=traceback,
|
||||
)
|
||||
raise e
|
||||
else:
|
||||
frappe.db.rollback()
|
||||
traceback = frappe.get_traceback()
|
||||
frappe.log_error(
|
||||
title=_("Error while processing deferred accounting for Invoice {0}").format(doc.name),
|
||||
message=traceback,
|
||||
)
|
||||
frappe.flags.deferred_accounting_error = True
|
||||
|
||||
|
||||
def send_mail(deferred_process):
|
||||
title = _("Error while processing deferred accounting for {0}").format(deferred_process)
|
||||
link = get_link_to_form("Process Deferred Accounting", deferred_process)
|
||||
content = _("Deferred accounting failed for some invoices:") + "\n"
|
||||
content += _(
|
||||
"Please check Process Deferred Accounting {0} and submit manually after resolving errors."
|
||||
).format(link)
|
||||
sendmail_to_system_managers(title, content)
|
||||
|
||||
|
||||
def book_revenue_via_journal_entry(
|
||||
doc,
|
||||
credit_account,
|
||||
debit_account,
|
||||
amount,
|
||||
base_amount,
|
||||
posting_date,
|
||||
project,
|
||||
account_currency,
|
||||
cost_center,
|
||||
item,
|
||||
deferred_process=None,
|
||||
submit="No",
|
||||
):
|
||||
|
||||
if amount == 0:
|
||||
return
|
||||
|
||||
journal_entry = frappe.new_doc("Journal Entry")
|
||||
journal_entry.posting_date = posting_date
|
||||
journal_entry.company = doc.company
|
||||
journal_entry.voucher_type = (
|
||||
"Deferred Revenue" if doc.doctype == "Sales Invoice" else "Deferred Expense"
|
||||
)
|
||||
journal_entry.process_deferred_accounting = deferred_process
|
||||
|
||||
debit_entry = {
|
||||
"account": credit_account,
|
||||
"credit": base_amount,
|
||||
"credit_in_account_currency": amount,
|
||||
"account_currency": account_currency,
|
||||
"reference_name": doc.name,
|
||||
"reference_type": doc.doctype,
|
||||
"reference_detail_no": item.name,
|
||||
"cost_center": cost_center,
|
||||
"project": project,
|
||||
}
|
||||
|
||||
credit_entry = {
|
||||
"account": debit_account,
|
||||
"debit": base_amount,
|
||||
"debit_in_account_currency": amount,
|
||||
"account_currency": account_currency,
|
||||
"reference_name": doc.name,
|
||||
"reference_type": doc.doctype,
|
||||
"reference_detail_no": item.name,
|
||||
"cost_center": cost_center,
|
||||
"project": project,
|
||||
}
|
||||
|
||||
for dimension in get_accounting_dimensions():
|
||||
debit_entry.update({dimension: item.get(dimension)})
|
||||
|
||||
credit_entry.update({dimension: item.get(dimension)})
|
||||
|
||||
journal_entry.append("accounts", debit_entry)
|
||||
journal_entry.append("accounts", credit_entry)
|
||||
|
||||
try:
|
||||
journal_entry.save()
|
||||
|
||||
if submit:
|
||||
journal_entry.submit()
|
||||
|
||||
frappe.db.commit()
|
||||
except Exception:
|
||||
frappe.db.rollback()
|
||||
traceback = frappe.get_traceback()
|
||||
frappe.log_error(
|
||||
title=_("Error while processing deferred accounting for Invoice {0}").format(doc.name),
|
||||
message=traceback,
|
||||
)
|
||||
|
||||
frappe.flags.deferred_accounting_error = True
|
||||
|
||||
|
||||
def get_deferred_booking_accounts(doctype, voucher_detail_no, dr_or_cr):
|
||||
|
||||
if doctype == "Sales Invoice":
|
||||
credit_account, debit_account = frappe.db.get_value(
|
||||
"Sales Invoice Item",
|
||||
{"name": voucher_detail_no},
|
||||
["income_account", "deferred_revenue_account"],
|
||||
)
|
||||
else:
|
||||
credit_account, debit_account = frappe.db.get_value(
|
||||
"Purchase Invoice Item",
|
||||
{"name": voucher_detail_no},
|
||||
["deferred_expense_account", "expense_account"],
|
||||
)
|
||||
|
||||
if dr_or_cr == "Debit":
|
||||
return debit_account
|
||||
else:
|
||||
return credit_account
|
||||
except:
|
||||
frappe.db.rollback()
|
||||
title = _("Error while processing deferred accounting for {0}").format(doc.name)
|
||||
traceback = frappe.get_traceback()
|
||||
frappe.log_error(message=traceback , title=title)
|
||||
sendmail_to_system_managers(title, traceback)
|
||||
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
@@ -43,12 +43,12 @@ frappe.ui.form.on('Account', {
|
||||
frm.trigger('add_toolbar_buttons');
|
||||
}
|
||||
if (frm.has_perm('write')) {
|
||||
frm.add_custom_button(__('Merge Account'), function () {
|
||||
frm.trigger("merge_account");
|
||||
}, __('Actions'));
|
||||
frm.add_custom_button(__('Update Account Name / Number'), function () {
|
||||
frm.trigger("update_account_number");
|
||||
}, __('Actions'));
|
||||
});
|
||||
frm.add_custom_button(__('Merge Account'), function () {
|
||||
frm.trigger("merge_account");
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -59,12 +59,11 @@ frappe.ui.form.on('Account', {
|
||||
}
|
||||
},
|
||||
add_toolbar_buttons: function(frm) {
|
||||
frm.add_custom_button(__('Chart of Accounts'), () => {
|
||||
frappe.set_route("Tree", "Account");
|
||||
}, __('View'));
|
||||
frm.add_custom_button(__('Chart of Accounts'),
|
||||
function () { frappe.set_route("Tree", "Account"); });
|
||||
|
||||
if (frm.doc.is_group == 1) {
|
||||
frm.add_custom_button(__('Convert to Non-Group'), function () {
|
||||
frm.add_custom_button(__('Group to Non-Group'), function () {
|
||||
return frappe.call({
|
||||
doc: frm.doc,
|
||||
method: 'convert_group_to_ledger',
|
||||
@@ -72,11 +71,10 @@ frappe.ui.form.on('Account', {
|
||||
frm.refresh();
|
||||
}
|
||||
});
|
||||
}, __('Actions'));
|
||||
|
||||
});
|
||||
} else if (cint(frm.doc.is_group) == 0
|
||||
&& frappe.boot.user.can_read.indexOf("GL Entry") !== -1) {
|
||||
frm.add_custom_button(__('General Ledger'), function () {
|
||||
cur_frm.add_custom_button(__('Ledger'), function () {
|
||||
frappe.route_options = {
|
||||
"account": frm.doc.name,
|
||||
"from_date": frappe.sys_defaults.year_start_date,
|
||||
@@ -84,9 +82,9 @@ frappe.ui.form.on('Account', {
|
||||
"company": frm.doc.company
|
||||
};
|
||||
frappe.set_route("query-report", "General Ledger");
|
||||
}, __('View'));
|
||||
});
|
||||
|
||||
frm.add_custom_button(__('Convert to Group'), function () {
|
||||
frm.add_custom_button(__('Non-Group to Group'), function () {
|
||||
return frappe.call({
|
||||
doc: frm.doc,
|
||||
method: 'convert_ledger_to_group',
|
||||
@@ -94,7 +92,7 @@ frappe.ui.form.on('Account', {
|
||||
frm.refresh();
|
||||
}
|
||||
});
|
||||
}, __('Actions'));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,47 +1,35 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _, throw
|
||||
from frappe.utils import cint, cstr
|
||||
from frappe import throw, _
|
||||
from frappe.utils.nestedset import NestedSet, get_ancestors_of, get_descendants_of
|
||||
|
||||
import erpnext
|
||||
|
||||
|
||||
class RootNotEditable(frappe.ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class BalanceMismatchError(frappe.ValidationError):
|
||||
pass
|
||||
|
||||
class RootNotEditable(frappe.ValidationError): pass
|
||||
class BalanceMismatchError(frappe.ValidationError): pass
|
||||
|
||||
class Account(NestedSet):
|
||||
nsm_parent_field = "parent_account"
|
||||
|
||||
nsm_parent_field = 'parent_account'
|
||||
def on_update(self):
|
||||
if frappe.local.flags.ignore_update_nsm:
|
||||
if frappe.local.flags.ignore_on_update:
|
||||
return
|
||||
else:
|
||||
super(Account, self).on_update()
|
||||
|
||||
def onload(self):
|
||||
frozen_accounts_modifier = frappe.db.get_value(
|
||||
"Accounts Settings", "Accounts Settings", "frozen_accounts_modifier"
|
||||
)
|
||||
frozen_accounts_modifier = frappe.db.get_value("Accounts Settings", "Accounts Settings",
|
||||
"frozen_accounts_modifier")
|
||||
if not frozen_accounts_modifier or frozen_accounts_modifier in frappe.get_roles():
|
||||
self.set_onload("can_freeze_account", True)
|
||||
|
||||
def autoname(self):
|
||||
from erpnext.accounts.utils import get_autoname_with_number
|
||||
|
||||
self.name = get_autoname_with_number(self.account_number, self.account_name, None, self.company)
|
||||
|
||||
def validate(self):
|
||||
from erpnext.accounts.utils import validate_field_number
|
||||
|
||||
if frappe.local.flags.allow_unverified_charts:
|
||||
return
|
||||
self.validate_parent()
|
||||
@@ -58,33 +46,22 @@ class Account(NestedSet):
|
||||
def validate_parent(self):
|
||||
"""Fetch Parent Details and validate parent account"""
|
||||
if self.parent_account:
|
||||
par = frappe.db.get_value(
|
||||
"Account", self.parent_account, ["name", "is_group", "company"], as_dict=1
|
||||
)
|
||||
par = frappe.db.get_value("Account", self.parent_account,
|
||||
["name", "is_group", "company"], as_dict=1)
|
||||
if not par:
|
||||
throw(
|
||||
_("Account {0}: Parent account {1} does not exist").format(self.name, self.parent_account)
|
||||
)
|
||||
throw(_("Account {0}: Parent account {1} does not exist").format(self.name, self.parent_account))
|
||||
elif par.name == self.name:
|
||||
throw(_("Account {0}: You can not assign itself as parent account").format(self.name))
|
||||
elif not par.is_group:
|
||||
throw(
|
||||
_("Account {0}: Parent account {1} can not be a ledger").format(
|
||||
self.name, self.parent_account
|
||||
)
|
||||
)
|
||||
throw(_("Account {0}: Parent account {1} can not be a ledger").format(self.name, self.parent_account))
|
||||
elif par.company != self.company:
|
||||
throw(
|
||||
_("Account {0}: Parent account {1} does not belong to company: {2}").format(
|
||||
self.name, self.parent_account, self.company
|
||||
)
|
||||
)
|
||||
throw(_("Account {0}: Parent account {1} does not belong to company: {2}")
|
||||
.format(self.name, self.parent_account, self.company))
|
||||
|
||||
def set_root_and_report_type(self):
|
||||
if self.parent_account:
|
||||
par = frappe.db.get_value(
|
||||
"Account", self.parent_account, ["report_type", "root_type"], as_dict=1
|
||||
)
|
||||
par = frappe.db.get_value("Account", self.parent_account,
|
||||
["report_type", "root_type"], as_dict=1)
|
||||
|
||||
if par.report_type:
|
||||
self.report_type = par.report_type
|
||||
@@ -95,20 +72,15 @@ class Account(NestedSet):
|
||||
db_value = frappe.db.get_value("Account", self.name, ["report_type", "root_type"], as_dict=1)
|
||||
if db_value:
|
||||
if self.report_type != db_value.report_type:
|
||||
frappe.db.sql(
|
||||
"update `tabAccount` set report_type=%s where lft > %s and rgt < %s",
|
||||
(self.report_type, self.lft, self.rgt),
|
||||
)
|
||||
frappe.db.sql("update `tabAccount` set report_type=%s where lft > %s and rgt < %s",
|
||||
(self.report_type, self.lft, self.rgt))
|
||||
if self.root_type != db_value.root_type:
|
||||
frappe.db.sql(
|
||||
"update `tabAccount` set root_type=%s where lft > %s and rgt < %s",
|
||||
(self.root_type, self.lft, self.rgt),
|
||||
)
|
||||
frappe.db.sql("update `tabAccount` set root_type=%s where lft > %s and rgt < %s",
|
||||
(self.root_type, self.lft, self.rgt))
|
||||
|
||||
if self.root_type and not self.report_type:
|
||||
self.report_type = (
|
||||
"Balance Sheet" if self.root_type in ("Asset", "Liability", "Equity") else "Profit and Loss"
|
||||
)
|
||||
self.report_type = "Balance Sheet" \
|
||||
if self.root_type in ("Asset", "Liability", "Equity") else "Profit and Loss"
|
||||
|
||||
def validate_root_details(self):
|
||||
# does not exists parent
|
||||
@@ -117,44 +89,33 @@ class Account(NestedSet):
|
||||
throw(_("Root cannot be edited."), RootNotEditable)
|
||||
|
||||
if not self.parent_account and not self.is_group:
|
||||
frappe.throw(_("The root account {0} must be a group").format(frappe.bold(self.name)))
|
||||
frappe.throw(_("Root Account must be a group"))
|
||||
|
||||
def validate_root_company_and_sync_account_to_children(self):
|
||||
# ignore validation while creating new compnay or while syncing to child companies
|
||||
if (
|
||||
frappe.local.flags.ignore_root_company_validation or self.flags.ignore_root_company_validation
|
||||
):
|
||||
if frappe.local.flags.ignore_root_company_validation or self.flags.ignore_root_company_validation:
|
||||
return
|
||||
|
||||
ancestors = get_root_company(self.company)
|
||||
if ancestors:
|
||||
if frappe.get_value("Company", self.company, "allow_account_creation_against_child_company"):
|
||||
return
|
||||
if not frappe.db.get_value(
|
||||
"Account", {"account_name": self.account_name, "company": ancestors[0]}, "name"
|
||||
):
|
||||
frappe.throw(_("Please add the account to root level Company - {}").format(ancestors[0]))
|
||||
elif self.parent_account:
|
||||
descendants = get_descendants_of("Company", self.company)
|
||||
if not descendants:
|
||||
return
|
||||
parent_acc_name_map = {}
|
||||
parent_acc_name, parent_acc_number = frappe.db.get_value(
|
||||
"Account", self.parent_account, ["account_name", "account_number"]
|
||||
)
|
||||
filters = {
|
||||
"company": ["in", descendants],
|
||||
"account_name": parent_acc_name,
|
||||
}
|
||||
if parent_acc_number:
|
||||
filters["account_number"] = parent_acc_number
|
||||
|
||||
for d in frappe.db.get_values(
|
||||
"Account", filters=filters, fieldname=["company", "name"], as_dict=True
|
||||
):
|
||||
if not frappe.db.get_value("Account",
|
||||
{'account_name': self.account_name, 'company': ancestors[0]}, 'name'):
|
||||
frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
|
||||
else:
|
||||
descendants = get_descendants_of('Company', self.company)
|
||||
if not descendants: return
|
||||
|
||||
parent_acc_name_map = {}
|
||||
parent_acc_name = frappe.db.get_value('Account', self.parent_account, "account_name")
|
||||
for d in frappe.db.get_values('Account',
|
||||
{"company": ["in", descendants], "account_name": parent_acc_name},
|
||||
["company", "name"], as_dict=True):
|
||||
parent_acc_name_map[d["company"]] = d["name"]
|
||||
|
||||
if not parent_acc_name_map:
|
||||
return
|
||||
if not parent_acc_name_map: return
|
||||
|
||||
self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name)
|
||||
|
||||
@@ -175,92 +136,65 @@ class Account(NestedSet):
|
||||
def validate_frozen_accounts_modifier(self):
|
||||
old_value = frappe.db.get_value("Account", self.name, "freeze_account")
|
||||
if old_value and old_value != self.freeze_account:
|
||||
frozen_accounts_modifier = frappe.db.get_value(
|
||||
"Accounts Settings", None, "frozen_accounts_modifier"
|
||||
)
|
||||
if not frozen_accounts_modifier or frozen_accounts_modifier not in frappe.get_roles():
|
||||
throw(_("You are not authorized to set Frozen value"))
|
||||
frozen_accounts_modifier = frappe.db.get_value('Accounts Settings', None, 'frozen_accounts_modifier')
|
||||
if not frozen_accounts_modifier or \
|
||||
frozen_accounts_modifier not in frappe.get_roles():
|
||||
throw(_("You are not authorized to set Frozen value"))
|
||||
|
||||
def validate_balance_must_be_debit_or_credit(self):
|
||||
from erpnext.accounts.utils import get_balance_on
|
||||
|
||||
if not self.get("__islocal") and self.balance_must_be:
|
||||
account_balance = get_balance_on(self.name)
|
||||
|
||||
if account_balance > 0 and self.balance_must_be == "Credit":
|
||||
frappe.throw(
|
||||
_(
|
||||
"Account balance already in Debit, you are not allowed to set 'Balance Must Be' as 'Credit'"
|
||||
)
|
||||
)
|
||||
frappe.throw(_("Account balance already in Debit, you are not allowed to set 'Balance Must Be' as 'Credit'"))
|
||||
elif account_balance < 0 and self.balance_must_be == "Debit":
|
||||
frappe.throw(
|
||||
_(
|
||||
"Account balance already in Credit, you are not allowed to set 'Balance Must Be' as 'Debit'"
|
||||
)
|
||||
)
|
||||
frappe.throw(_("Account balance already in Credit, you are not allowed to set 'Balance Must Be' as 'Debit'"))
|
||||
|
||||
def validate_account_currency(self):
|
||||
if not self.account_currency:
|
||||
self.account_currency = frappe.get_cached_value("Company", self.company, "default_currency")
|
||||
self.account_currency = frappe.get_cached_value('Company', self.company, "default_currency")
|
||||
|
||||
gl_currency = frappe.db.get_value("GL Entry", {"account": self.name}, "account_currency")
|
||||
|
||||
if gl_currency and self.account_currency != gl_currency:
|
||||
elif self.account_currency != frappe.db.get_value("Account", self.name, "account_currency"):
|
||||
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:
|
||||
company_bold = frappe.bold(company)
|
||||
parent_acc_name_bold = frappe.bold(parent_acc_name)
|
||||
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_bold, parent_acc_name_bold),
|
||||
title=_("Account Not Found"),
|
||||
)
|
||||
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))
|
||||
|
||||
# validate if parent of child company account to be added is a group
|
||||
if frappe.db.get_value("Account", self.parent_account, "is_group") and not frappe.db.get_value(
|
||||
"Account", parent_acc_name_map[company], "is_group"
|
||||
):
|
||||
msg = _(
|
||||
"While creating account for Child Company {0}, parent account {1} found as a ledger account."
|
||||
).format(company_bold, parent_acc_name_bold)
|
||||
msg += "<br><br>"
|
||||
msg += _(
|
||||
"Please convert the parent account in corresponding child company to a group account."
|
||||
)
|
||||
frappe.throw(msg, title=_("Invalid Parent Account"))
|
||||
|
||||
filters = {"account_name": self.account_name, "company": company}
|
||||
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")
|
||||
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": erpnext.get_company_currency(company),
|
||||
"parent_account": parent_acc_name_map[company],
|
||||
}
|
||||
)
|
||||
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))
|
||||
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", "freeze_account", "balance_must_be"]:
|
||||
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))
|
||||
@@ -268,7 +202,6 @@ class Account(NestedSet):
|
||||
if parent_value_changed:
|
||||
doc.save()
|
||||
|
||||
@frappe.whitelist()
|
||||
def convert_group_to_ledger(self):
|
||||
if self.check_if_child_exists():
|
||||
throw(_("Account with child nodes cannot be converted to ledger"))
|
||||
@@ -279,12 +212,11 @@ class Account(NestedSet):
|
||||
self.save()
|
||||
return 1
|
||||
|
||||
@frappe.whitelist()
|
||||
def convert_ledger_to_group(self):
|
||||
if self.check_gle_exists():
|
||||
throw(_("Account with existing transaction can not be converted to group."))
|
||||
elif self.account_type and not self.flags.exclude_account_type_check:
|
||||
throw(_("Cannot convert to Group because Account Type is selected."))
|
||||
throw(_("Cannot covert to Group because Account Type is selected."))
|
||||
else:
|
||||
self.is_group = 1
|
||||
self.save()
|
||||
@@ -295,11 +227,8 @@ class Account(NestedSet):
|
||||
return frappe.db.get_value("GL Entry", {"account": self.name})
|
||||
|
||||
def check_if_child_exists(self):
|
||||
return frappe.db.sql(
|
||||
"""select name from `tabAccount` where parent_account = %s
|
||||
and docstatus != 2""",
|
||||
self.name,
|
||||
)
|
||||
return frappe.db.sql("""select name from `tabAccount` where parent_account = %s
|
||||
and docstatus != 2""", self.name)
|
||||
|
||||
def validate_mandatory(self):
|
||||
if not self.root_type:
|
||||
@@ -315,102 +244,53 @@ class Account(NestedSet):
|
||||
|
||||
super(Account, self).on_trash(True)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.validate_and_sanitize_search_inputs
|
||||
def get_parent_account(doctype, txt, searchfield, start, page_len, filters):
|
||||
return frappe.db.sql(
|
||||
"""select name from tabAccount
|
||||
return frappe.db.sql("""select name from tabAccount
|
||||
where is_group = 1 and docstatus != 2 and company = %s
|
||||
and %s like %s order by name limit %s, %s"""
|
||||
% ("%s", searchfield, "%s", "%s", "%s"),
|
||||
(filters["company"], "%%%s%%" % txt, start, page_len),
|
||||
as_list=1,
|
||||
)
|
||||
|
||||
and %s like %s order by name limit %s, %s""" %
|
||||
("%s", searchfield, "%s", "%s", "%s"),
|
||||
(filters["company"], "%%%s%%" % txt, start, page_len), as_list=1)
|
||||
|
||||
def get_account_currency(account):
|
||||
"""Helper function to get account currency"""
|
||||
if not account:
|
||||
return
|
||||
|
||||
def generator():
|
||||
account_currency, company = frappe.get_cached_value(
|
||||
"Account", account, ["account_currency", "company"]
|
||||
)
|
||||
account_currency, company = frappe.get_cached_value("Account", account, ["account_currency", "company"])
|
||||
if not account_currency:
|
||||
account_currency = frappe.get_cached_value("Company", company, "default_currency")
|
||||
account_currency = frappe.get_cached_value('Company', company, "default_currency")
|
||||
|
||||
return account_currency
|
||||
|
||||
return frappe.local_cache("account_currency", account, generator)
|
||||
|
||||
|
||||
def on_doctype_update():
|
||||
frappe.db.add_index("Account", ["lft", "rgt"])
|
||||
|
||||
|
||||
def get_account_autoname(account_number, account_name, company):
|
||||
# first validate if company exists
|
||||
company = frappe.get_cached_value("Company", company, ["abbr", "name"], as_dict=True)
|
||||
company = frappe.get_cached_value('Company', company, ["abbr", "name"], as_dict=True)
|
||||
if not company:
|
||||
frappe.throw(_("Company {0} does not exist").format(company))
|
||||
frappe.throw(_('Company {0} does not exist').format(company))
|
||||
|
||||
parts = [account_name.strip(), company.abbr]
|
||||
if cstr(account_number).strip():
|
||||
parts.insert(0, cstr(account_number).strip())
|
||||
return " - ".join(parts)
|
||||
|
||||
return ' - '.join(parts)
|
||||
|
||||
def validate_account_number(name, account_number, company):
|
||||
if account_number:
|
||||
account_with_same_number = frappe.db.get_value(
|
||||
"Account", {"account_number": account_number, "company": company, "name": ["!=", name]}
|
||||
)
|
||||
account_with_same_number = frappe.db.get_value("Account",
|
||||
{"account_number": account_number, "company": company, "name": ["!=", name]})
|
||||
if account_with_same_number:
|
||||
frappe.throw(
|
||||
_("Account Number {0} already used in account {1}").format(
|
||||
account_number, account_with_same_number
|
||||
)
|
||||
)
|
||||
|
||||
frappe.throw(_("Account Number {0} already used in account {1}")
|
||||
.format(account_number, account_with_same_number))
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_account_number(name, account_name, account_number=None, from_descendant=False):
|
||||
def update_account_number(name, account_name, account_number=None):
|
||||
|
||||
account = frappe.db.get_value("Account", name, "company", as_dict=True)
|
||||
if not account:
|
||||
return
|
||||
|
||||
old_acc_name, old_acc_number = frappe.db.get_value(
|
||||
"Account", name, ["account_name", "account_number"]
|
||||
)
|
||||
|
||||
# check if account exists in parent company
|
||||
ancestors = get_ancestors_of("Company", account.company)
|
||||
allow_independent_account_creation = frappe.get_value(
|
||||
"Company", account.company, "allow_account_creation_against_child_company"
|
||||
)
|
||||
|
||||
if ancestors and not allow_independent_account_creation:
|
||||
for ancestor in ancestors:
|
||||
if frappe.db.get_value("Account", {"account_name": old_acc_name, "company": ancestor}, "name"):
|
||||
# same account in parent company exists
|
||||
allow_child_account_creation = _("Allow Account Creation Against Child Company")
|
||||
|
||||
message = _("Account {0} exists in parent company {1}.").format(
|
||||
frappe.bold(old_acc_name), frappe.bold(ancestor)
|
||||
)
|
||||
message += "<br>"
|
||||
message += _("Renaming it is only allowed via parent company {0}, to avoid mismatch.").format(
|
||||
frappe.bold(ancestor)
|
||||
)
|
||||
message += "<br><br>"
|
||||
message += _("To overrule this, enable '{0}' in company {1}").format(
|
||||
allow_child_account_creation, frappe.bold(account.company)
|
||||
)
|
||||
|
||||
frappe.throw(message, title=_("Rename Not Allowed"))
|
||||
|
||||
if not account: return
|
||||
validate_account_number(name, account_number, account.company)
|
||||
if account_number:
|
||||
frappe.db.set_value("Account", name, "account_number", account_number.strip())
|
||||
@@ -418,63 +298,33 @@ def update_account_number(name, account_name, account_number=None, from_descenda
|
||||
frappe.db.set_value("Account", name, "account_number", "")
|
||||
frappe.db.set_value("Account", name, "account_name", account_name.strip())
|
||||
|
||||
if not from_descendant:
|
||||
# Update and rename in child company accounts as well
|
||||
descendants = get_descendants_of("Company", account.company)
|
||||
if descendants:
|
||||
sync_update_account_number_in_child(
|
||||
descendants, old_acc_name, account_name, account_number, old_acc_number
|
||||
)
|
||||
|
||||
new_name = get_account_autoname(account_number, account_name, account.company)
|
||||
if name != new_name:
|
||||
frappe.rename_doc("Account", name, new_name, force=1)
|
||||
return new_name
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def merge_account(old, new, is_group, root_type, company):
|
||||
# Validate properties before merging
|
||||
if not frappe.db.exists("Account", new):
|
||||
throw(_("Account {0} does not exist").format(new))
|
||||
|
||||
val = list(frappe.db.get_value("Account", new, ["is_group", "root_type", "company"]))
|
||||
val = list(frappe.db.get_value("Account", new,
|
||||
["is_group", "root_type", "company"]))
|
||||
|
||||
if val != [cint(is_group), root_type, company]:
|
||||
throw(
|
||||
_(
|
||||
"""Merging is only possible if following properties are same in both records. Is Group, Root Type, Company"""
|
||||
)
|
||||
)
|
||||
throw(_("""Merging is only possible if following properties are same in both records. Is Group, Root Type, Company"""))
|
||||
|
||||
if is_group and frappe.db.get_value("Account", new, "parent_account") == old:
|
||||
frappe.db.set_value(
|
||||
"Account", new, "parent_account", frappe.db.get_value("Account", old, "parent_account")
|
||||
)
|
||||
frappe.db.set_value("Account", new, "parent_account",
|
||||
frappe.db.get_value("Account", old, "parent_account"))
|
||||
|
||||
frappe.rename_doc("Account", old, new, merge=1, force=1)
|
||||
|
||||
return new
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_root_company(company):
|
||||
# return the topmost company in the hierarchy
|
||||
ancestors = get_ancestors_of("Company", company, "lft asc")
|
||||
ancestors = get_ancestors_of('Company', company, "lft asc")
|
||||
return [ancestors[0]] if ancestors else []
|
||||
|
||||
|
||||
def sync_update_account_number_in_child(
|
||||
descendants, old_acc_name, account_name, account_number=None, old_acc_number=None
|
||||
):
|
||||
filters = {
|
||||
"company": ["in", descendants],
|
||||
"account_name": old_acc_name,
|
||||
}
|
||||
if old_acc_number:
|
||||
filters["account_number"] = old_acc_number
|
||||
|
||||
for d in frappe.db.get_values(
|
||||
"Account", filters=filters, fieldname=["company", "name"], as_dict=True
|
||||
):
|
||||
update_account_number(d["name"], account_name, account_number, from_descendant=True)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
frappe.provide("frappe.treeview_settings")
|
||||
|
||||
frappe.treeview_settings["Account"] = {
|
||||
breadcrumb: "Accounts",
|
||||
title: __("Chart of Accounts"),
|
||||
breadcrumbs: "Accounts",
|
||||
title: __("Chart Of Accounts"),
|
||||
get_tree_root: false,
|
||||
filters: [
|
||||
{
|
||||
@@ -14,9 +14,6 @@ frappe.treeview_settings["Account"] = {
|
||||
on_change: function() {
|
||||
var me = frappe.treeview_settings['Account'].treeview;
|
||||
var company = me.page.fields_dict.company.get_value();
|
||||
if (!company) {
|
||||
frappe.throw(__("Please set a Company"));
|
||||
}
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.account.account.get_root_company",
|
||||
args: {
|
||||
@@ -45,50 +42,6 @@ frappe.treeview_settings["Account"] = {
|
||||
],
|
||||
root_label: "Accounts",
|
||||
get_tree_nodes: 'erpnext.accounts.utils.get_children',
|
||||
on_get_node: function(nodes, deep=false) {
|
||||
if (frappe.boot.user.can_read.indexOf("GL Entry") == -1) return;
|
||||
|
||||
let accounts = [];
|
||||
if (deep) {
|
||||
// in case of `get_all_nodes`
|
||||
accounts = nodes.reduce((acc, node) => [...acc, ...node.data], []);
|
||||
} else {
|
||||
accounts = nodes;
|
||||
}
|
||||
|
||||
const get_balances = frappe.call({
|
||||
method: 'erpnext.accounts.utils.get_account_balances',
|
||||
args: {
|
||||
accounts: accounts,
|
||||
company: cur_tree.args.company
|
||||
},
|
||||
});
|
||||
|
||||
get_balances.then(r => {
|
||||
if (!r.message || r.message.length == 0) return;
|
||||
|
||||
for (let account of r.message) {
|
||||
|
||||
const node = cur_tree.nodes && cur_tree.nodes[account.value];
|
||||
if (!node || node.is_root) continue;
|
||||
|
||||
// show Dr if positive since balance is calculated as debit - credit else show Cr
|
||||
const balance = account.balance_in_account_currency || account.balance;
|
||||
const dr_or_cr = balance > 0 ? "Dr": "Cr";
|
||||
const format = (value, currency) => format_currency(Math.abs(value), currency);
|
||||
|
||||
if (account.balance!==undefined) {
|
||||
node.parent && node.parent.find('.balance-area').remove();
|
||||
$('<span class="balance-area pull-right">'
|
||||
+ (account.balance_in_account_currency ?
|
||||
(format(account.balance_in_account_currency, account.account_currency) + " / ") : "")
|
||||
+ format(account.balance, account.company_currency)
|
||||
+ " " + dr_or_cr
|
||||
+ '</span>').insertBefore(node.$ul);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
add_tree_node: 'erpnext.accounts.utils.add_ac',
|
||||
menu_items:[
|
||||
{
|
||||
@@ -137,13 +90,13 @@ frappe.treeview_settings["Account"] = {
|
||||
frappe.set_route('List', 'Period Closing Voucher', {company: get_company()});
|
||||
}, __('View'));
|
||||
|
||||
|
||||
// make
|
||||
treeview.page.add_inner_button(__("Journal Entry"), function() {
|
||||
frappe.new_doc('Journal Entry', {company: get_company()});
|
||||
}, __('Create'));
|
||||
treeview.page.add_inner_button(__("Company"), function() {
|
||||
}, __('Make'));
|
||||
treeview.page.add_inner_button(__("New Company"), function() {
|
||||
frappe.new_doc('Company');
|
||||
}, __('Create'));
|
||||
}, __('Make'));
|
||||
|
||||
// financial statements
|
||||
for (let report of ['Trial Balance', 'General Ledger', 'Balance Sheet',
|
||||
@@ -164,7 +117,25 @@ frappe.treeview_settings["Account"] = {
|
||||
} else {
|
||||
treeview.new_node();
|
||||
}
|
||||
}, "add");
|
||||
}, "octicon octicon-plus");
|
||||
},
|
||||
onrender: function(node) {
|
||||
if(frappe.boot.user.can_read.indexOf("GL Entry") !== -1){
|
||||
|
||||
// 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 ?
|
||||
(format_currency(Math.abs(node.data.balance_in_account_currency),
|
||||
node.data.account_currency) + " / ") : "")
|
||||
+ format_currency(Math.abs(node.data.balance), node.data.company_currency)
|
||||
+ " " + dr_or_cr
|
||||
+ '</span>').insertBefore(node.$ul);
|
||||
}
|
||||
}
|
||||
},
|
||||
toolbar: [
|
||||
{
|
||||
@@ -176,7 +147,7 @@ frappe.treeview_settings["Account"] = {
|
||||
&& node.expandable && !node.hide_add;
|
||||
},
|
||||
click: function() {
|
||||
var me = frappe.views.trees['Account'];
|
||||
var me = frappe.treeview_settings['Account'].treeview;
|
||||
me.new_node();
|
||||
},
|
||||
btnClass: "hidden-xs"
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
import os
|
||||
|
||||
import frappe
|
||||
import frappe, os, json
|
||||
from frappe.utils import cstr
|
||||
from frappe.utils.nestedset import rebuild_tree
|
||||
from six import iteritems
|
||||
from unidecode import unidecode
|
||||
from six import iteritems
|
||||
from frappe.utils.nestedset import rebuild_tree
|
||||
|
||||
|
||||
def create_charts(
|
||||
company, chart_template=None, existing_company=None, custom_chart=None, from_coa_importer=None
|
||||
):
|
||||
chart = custom_chart or get_chart(chart_template, existing_company)
|
||||
def create_charts(company, chart_template=None, existing_company=None):
|
||||
chart = get_chart(chart_template, existing_company)
|
||||
if chart:
|
||||
accounts = []
|
||||
|
||||
@@ -23,41 +19,30 @@ def create_charts(
|
||||
if root_account:
|
||||
root_type = child.get("root_type")
|
||||
|
||||
if account_name not in [
|
||||
"account_name",
|
||||
"account_number",
|
||||
"account_type",
|
||||
"root_type",
|
||||
"is_group",
|
||||
"tax_rate",
|
||||
]:
|
||||
if account_name not in ["account_number", "account_type",
|
||||
"root_type", "is_group", "tax_rate"]:
|
||||
|
||||
account_number = cstr(child.get("account_number")).strip()
|
||||
account_name, account_name_in_db = add_suffix_if_duplicate(
|
||||
account_name, account_number, accounts
|
||||
)
|
||||
account_name, account_name_in_db = add_suffix_if_duplicate(account_name,
|
||||
account_number, accounts)
|
||||
|
||||
is_group = identify_is_group(child)
|
||||
report_type = (
|
||||
"Balance Sheet" if root_type in ["Asset", "Liability", "Equity"] else "Profit and Loss"
|
||||
)
|
||||
report_type = "Balance Sheet" if root_type in ["Asset", "Liability", "Equity"] \
|
||||
else "Profit and Loss"
|
||||
|
||||
account = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Account",
|
||||
"account_name": child.get("account_name") if from_coa_importer else account_name,
|
||||
"company": company,
|
||||
"parent_account": parent,
|
||||
"is_group": is_group,
|
||||
"root_type": root_type,
|
||||
"report_type": report_type,
|
||||
"account_number": account_number,
|
||||
"account_type": child.get("account_type"),
|
||||
"account_currency": child.get("account_currency")
|
||||
or frappe.db.get_value("Company", company, "default_currency"),
|
||||
"tax_rate": child.get("tax_rate"),
|
||||
}
|
||||
)
|
||||
account = frappe.get_doc({
|
||||
"doctype": "Account",
|
||||
"account_name": account_name,
|
||||
"company": company,
|
||||
"parent_account": parent,
|
||||
"is_group": is_group,
|
||||
"root_type": root_type,
|
||||
"report_type": report_type,
|
||||
"account_number": account_number,
|
||||
"account_type": child.get("account_type"),
|
||||
"account_currency": frappe.db.get_value('Company', company, "default_currency"),
|
||||
"tax_rate": child.get("tax_rate")
|
||||
})
|
||||
|
||||
if root_account or frappe.local.flags.allow_unverified_charts:
|
||||
account.flags.ignore_mandatory = True
|
||||
@@ -72,15 +57,15 @@ def create_charts(
|
||||
|
||||
# Rebuild NestedSet HSM tree for Account Doctype
|
||||
# after all accounts are already inserted.
|
||||
frappe.local.flags.ignore_update_nsm = True
|
||||
frappe.local.flags.ignore_on_update = True
|
||||
_import_accounts(chart, None, None, root_account=True)
|
||||
rebuild_tree("Account", "parent_account")
|
||||
frappe.local.flags.ignore_update_nsm = False
|
||||
|
||||
frappe.local.flags.ignore_on_update = False
|
||||
|
||||
def add_suffix_if_duplicate(account_name, account_number, accounts):
|
||||
if account_number:
|
||||
account_name_in_db = unidecode(" - ".join([account_number, account_name.strip().lower()]))
|
||||
account_name_in_db = unidecode(" - ".join([account_number,
|
||||
account_name.strip().lower()]))
|
||||
else:
|
||||
account_name_in_db = unidecode(account_name.strip().lower())
|
||||
|
||||
@@ -90,37 +75,27 @@ def add_suffix_if_duplicate(account_name, account_number, accounts):
|
||||
|
||||
return account_name, account_name_in_db
|
||||
|
||||
|
||||
def identify_is_group(child):
|
||||
if child.get("is_group"):
|
||||
is_group = child.get("is_group")
|
||||
elif len(
|
||||
set(child.keys())
|
||||
- set(["account_name", "account_type", "root_type", "is_group", "tax_rate", "account_number"])
|
||||
):
|
||||
elif len(set(child.keys()) - set(["account_type", "root_type", "is_group", "tax_rate", "account_number"])):
|
||||
is_group = 1
|
||||
else:
|
||||
is_group = 0
|
||||
|
||||
return is_group
|
||||
|
||||
|
||||
def get_chart(chart_template, existing_company=None):
|
||||
chart = {}
|
||||
if existing_company:
|
||||
return get_account_tree_from_existing_company(existing_company)
|
||||
|
||||
elif chart_template == "Standard":
|
||||
from erpnext.accounts.doctype.account.chart_of_accounts.verified import (
|
||||
standard_chart_of_accounts,
|
||||
)
|
||||
|
||||
from erpnext.accounts.doctype.account.chart_of_accounts.verified import standard_chart_of_accounts
|
||||
return standard_chart_of_accounts.get()
|
||||
elif chart_template == "Standard with Numbers":
|
||||
from erpnext.accounts.doctype.account.chart_of_accounts.verified import (
|
||||
standard_chart_of_accounts_with_account_number,
|
||||
)
|
||||
|
||||
from erpnext.accounts.doctype.account.chart_of_accounts.verified \
|
||||
import standard_chart_of_accounts_with_account_number
|
||||
return standard_chart_of_accounts_with_account_number.get()
|
||||
else:
|
||||
folders = ("verified",)
|
||||
@@ -136,7 +111,6 @@ def get_chart(chart_template, existing_company=None):
|
||||
if chart and json.loads(chart).get("name") == chart_template:
|
||||
return json.loads(chart).get("tree")
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_charts_for_country(country, with_standard=False):
|
||||
charts = []
|
||||
@@ -144,10 +118,9 @@ def get_charts_for_country(country, with_standard=False):
|
||||
def _get_chart_name(content):
|
||||
if content:
|
||||
content = json.loads(content)
|
||||
if (
|
||||
content and content.get("disabled", "No") == "No"
|
||||
) or frappe.local.flags.allow_unverified_charts:
|
||||
charts.append(content["name"])
|
||||
if (content and content.get("disabled", "No") == "No") \
|
||||
or frappe.local.flags.allow_unverified_charts:
|
||||
charts.append(content["name"])
|
||||
|
||||
country_code = frappe.db.get_value("Country", country, "code")
|
||||
if country_code:
|
||||
@@ -174,21 +147,11 @@ def get_charts_for_country(country, with_standard=False):
|
||||
|
||||
|
||||
def get_account_tree_from_existing_company(existing_company):
|
||||
all_accounts = frappe.get_all(
|
||||
"Account",
|
||||
filters={"company": existing_company},
|
||||
fields=[
|
||||
"name",
|
||||
"account_name",
|
||||
"parent_account",
|
||||
"account_type",
|
||||
"is_group",
|
||||
"root_type",
|
||||
"tax_rate",
|
||||
"account_number",
|
||||
],
|
||||
order_by="lft, rgt",
|
||||
)
|
||||
all_accounts = frappe.get_all('Account',
|
||||
filters={'company': existing_company},
|
||||
fields = ["name", "account_name", "parent_account", "account_type",
|
||||
"is_group", "root_type", "tax_rate", "account_number"],
|
||||
order_by="lft, rgt")
|
||||
|
||||
account_tree = {}
|
||||
|
||||
@@ -197,7 +160,6 @@ def get_account_tree_from_existing_company(existing_company):
|
||||
build_account_tree(account_tree, None, all_accounts)
|
||||
return account_tree
|
||||
|
||||
|
||||
def build_account_tree(tree, parent, all_accounts):
|
||||
# find children
|
||||
parent_account = parent.name if parent else ""
|
||||
@@ -226,63 +188,47 @@ def build_account_tree(tree, parent, all_accounts):
|
||||
# call recursively to build a subtree for current account
|
||||
build_account_tree(tree[child.account_name], child, all_accounts)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def validate_bank_account(coa, bank_account):
|
||||
accounts = []
|
||||
chart = get_chart(coa)
|
||||
|
||||
if chart:
|
||||
|
||||
def _get_account_names(account_master):
|
||||
for account_name, child in iteritems(account_master):
|
||||
if account_name not in ["account_number", "account_type", "root_type", "is_group", "tax_rate"]:
|
||||
if account_name not in ["account_number", "account_type",
|
||||
"root_type", "is_group", "tax_rate"]:
|
||||
accounts.append(account_name)
|
||||
|
||||
_get_account_names(child)
|
||||
|
||||
_get_account_names(chart)
|
||||
|
||||
return bank_account in accounts
|
||||
|
||||
return (bank_account in accounts)
|
||||
|
||||
@frappe.whitelist()
|
||||
def build_tree_from_json(chart_template, chart_data=None, from_coa_importer=False):
|
||||
"""get chart template from its folder and parse the json to be rendered as tree"""
|
||||
chart = chart_data or get_chart(chart_template)
|
||||
def build_tree_from_json(chart_template):
|
||||
''' get chart template from its folder and parse the json to be rendered as tree '''
|
||||
chart = get_chart(chart_template)
|
||||
|
||||
# if no template selected, return as it is
|
||||
if not chart:
|
||||
return
|
||||
|
||||
accounts = []
|
||||
|
||||
def _import_accounts(children, parent):
|
||||
"""recursively called to form a parent-child based list of dict from chart template"""
|
||||
''' recursively called to form a parent-child based list of dict from chart template '''
|
||||
for account_name, child in iteritems(children):
|
||||
account = {}
|
||||
if account_name in [
|
||||
"account_name",
|
||||
"account_number",
|
||||
"account_type",
|
||||
"root_type",
|
||||
"is_group",
|
||||
"tax_rate",
|
||||
]:
|
||||
continue
|
||||
if account_name in ["account_number", "account_type",\
|
||||
"root_type", "is_group", "tax_rate"]: continue
|
||||
|
||||
if from_coa_importer:
|
||||
account_name = child["account_name"]
|
||||
|
||||
account["parent_account"] = parent
|
||||
account["expandable"] = True if identify_is_group(child) else False
|
||||
account["value"] = (
|
||||
(cstr(child.get("account_number")).strip() + " - " + account_name)
|
||||
if child.get("account_number")
|
||||
else account_name
|
||||
)
|
||||
account['parent_account'] = parent
|
||||
account['expandable'] = True if identify_is_group(child) else False
|
||||
account['value'] = (child.get('account_number') + ' - ' + account_name) \
|
||||
if child.get('account_number') else account_name
|
||||
accounts.append(account)
|
||||
_import_accounts(child, account["value"])
|
||||
_import_accounts(child, account['value'])
|
||||
|
||||
_import_accounts(chart, None)
|
||||
return accounts
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
"""
|
||||
Import chart of accounts from OpenERP sources
|
||||
"""
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import os, json
|
||||
import ast
|
||||
import json
|
||||
import os
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
import frappe
|
||||
from frappe.utils.csvutils import read_csv_content
|
||||
import frappe
|
||||
|
||||
from six import iteritems
|
||||
|
||||
path = "/Users/nabinhait/projects/odoo/addons"
|
||||
@@ -21,7 +21,6 @@ charts = {}
|
||||
all_account_types = []
|
||||
all_roots = {}
|
||||
|
||||
|
||||
def go():
|
||||
global accounts, charts
|
||||
default_account_types = get_default_account_types()
|
||||
@@ -36,16 +35,14 @@ def go():
|
||||
accounts, charts = {}, {}
|
||||
country_path = os.path.join(path, country_dir)
|
||||
manifest = ast.literal_eval(open(os.path.join(country_path, "__openerp__.py")).read())
|
||||
data_files = (
|
||||
manifest.get("data", []) + manifest.get("init_xml", []) + manifest.get("update_xml", [])
|
||||
)
|
||||
data_files = manifest.get("data", []) + manifest.get("init_xml", []) + \
|
||||
manifest.get("update_xml", [])
|
||||
files_path = [os.path.join(country_path, d) for d in data_files]
|
||||
xml_roots = get_xml_roots(files_path)
|
||||
csv_content = get_csv_contents(files_path)
|
||||
prefix = country_dir if csv_content else None
|
||||
account_types = get_account_types(
|
||||
xml_roots.get("account.account.type", []), csv_content.get("account.account.type", []), prefix
|
||||
)
|
||||
account_types = get_account_types(xml_roots.get("account.account.type", []),
|
||||
csv_content.get("account.account.type", []), prefix)
|
||||
account_types.update(default_account_types)
|
||||
|
||||
if xml_roots:
|
||||
@@ -58,15 +55,12 @@ def go():
|
||||
|
||||
create_all_roots_file()
|
||||
|
||||
|
||||
def get_default_account_types():
|
||||
default_types_root = []
|
||||
default_types_root.append(
|
||||
ET.parse(os.path.join(path, "account", "data", "data_account_type.xml")).getroot()
|
||||
)
|
||||
default_types_root.append(ET.parse(os.path.join(path, "account", "data",
|
||||
"data_account_type.xml")).getroot())
|
||||
return get_account_types(default_types_root, None, prefix="account")
|
||||
|
||||
|
||||
def get_xml_roots(files_path):
|
||||
xml_roots = frappe._dict()
|
||||
for filepath in files_path:
|
||||
@@ -75,69 +69,64 @@ def get_xml_roots(files_path):
|
||||
tree = ET.parse(filepath)
|
||||
root = tree.getroot()
|
||||
for node in root[0].findall("record"):
|
||||
if node.get("model") in [
|
||||
"account.account.template",
|
||||
"account.chart.template",
|
||||
"account.account.type",
|
||||
]:
|
||||
if node.get("model") in ["account.account.template",
|
||||
"account.chart.template", "account.account.type"]:
|
||||
xml_roots.setdefault(node.get("model"), []).append(root)
|
||||
break
|
||||
return xml_roots
|
||||
|
||||
|
||||
def get_csv_contents(files_path):
|
||||
csv_content = {}
|
||||
for filepath in files_path:
|
||||
fname = os.path.basename(filepath)
|
||||
for file_type in ["account.account.template", "account.account.type", "account.chart.template"]:
|
||||
for file_type in ["account.account.template", "account.account.type",
|
||||
"account.chart.template"]:
|
||||
if fname.startswith(file_type) and fname.endswith(".csv"):
|
||||
with open(filepath, "r") as csvfile:
|
||||
try:
|
||||
csv_content.setdefault(file_type, []).append(read_csv_content(csvfile.read()))
|
||||
csv_content.setdefault(file_type, [])\
|
||||
.append(read_csv_content(csvfile.read()))
|
||||
except Exception as e:
|
||||
continue
|
||||
return csv_content
|
||||
|
||||
|
||||
def get_account_types(root_list, csv_content, prefix=None):
|
||||
types = {}
|
||||
account_type_map = {
|
||||
"cash": "Cash",
|
||||
"bank": "Bank",
|
||||
"tr_cash": "Cash",
|
||||
"tr_bank": "Bank",
|
||||
"receivable": "Receivable",
|
||||
"tr_receivable": "Receivable",
|
||||
"account rec": "Receivable",
|
||||
"payable": "Payable",
|
||||
"tr_payable": "Payable",
|
||||
"equity": "Equity",
|
||||
"stocks": "Stock",
|
||||
"stock": "Stock",
|
||||
"tax": "Tax",
|
||||
"tr_tax": "Tax",
|
||||
"tax-out": "Tax",
|
||||
"tax-in": "Tax",
|
||||
"charges_personnel": "Chargeable",
|
||||
"fixed asset": "Fixed Asset",
|
||||
"cogs": "Cost of Goods Sold",
|
||||
'cash': 'Cash',
|
||||
'bank': 'Bank',
|
||||
'tr_cash': 'Cash',
|
||||
'tr_bank': 'Bank',
|
||||
'receivable': 'Receivable',
|
||||
'tr_receivable': 'Receivable',
|
||||
'account rec': 'Receivable',
|
||||
'payable': 'Payable',
|
||||
'tr_payable': 'Payable',
|
||||
'equity': 'Equity',
|
||||
'stocks': 'Stock',
|
||||
'stock': 'Stock',
|
||||
'tax': 'Tax',
|
||||
'tr_tax': 'Tax',
|
||||
'tax-out': 'Tax',
|
||||
'tax-in': 'Tax',
|
||||
'charges_personnel': 'Chargeable',
|
||||
'fixed asset': 'Fixed Asset',
|
||||
'cogs': 'Cost of Goods Sold',
|
||||
|
||||
}
|
||||
for root in root_list:
|
||||
for node in root[0].findall("record"):
|
||||
if node.get("model") == "account.account.type":
|
||||
if node.get("model")=="account.account.type":
|
||||
data = {}
|
||||
for field in node.findall("field"):
|
||||
if (
|
||||
field.get("name") == "code"
|
||||
and field.text.lower() != "none"
|
||||
and account_type_map.get(field.text)
|
||||
):
|
||||
data["account_type"] = account_type_map[field.text]
|
||||
if field.get("name")=="code" and field.text.lower() != "none" \
|
||||
and account_type_map.get(field.text):
|
||||
data["account_type"] = account_type_map[field.text]
|
||||
|
||||
node_id = prefix + "." + node.get("id") if prefix else node.get("id")
|
||||
types[node_id] = data
|
||||
|
||||
if csv_content and csv_content[0][0] == "id":
|
||||
if csv_content and csv_content[0][0]=="id":
|
||||
for row in csv_content[1:]:
|
||||
row_dict = dict(zip(csv_content[0], row))
|
||||
data = {}
|
||||
@@ -148,22 +137,21 @@ def get_account_types(root_list, csv_content, prefix=None):
|
||||
types[node_id] = data
|
||||
return types
|
||||
|
||||
|
||||
def make_maps_for_xml(xml_roots, account_types, country_dir):
|
||||
"""make maps for `charts` and `accounts`"""
|
||||
for model, root_list in iteritems(xml_roots):
|
||||
for root in root_list:
|
||||
for node in root[0].findall("record"):
|
||||
if node.get("model") == "account.account.template":
|
||||
if node.get("model")=="account.account.template":
|
||||
data = {}
|
||||
for field in node.findall("field"):
|
||||
if field.get("name") == "name":
|
||||
if field.get("name")=="name":
|
||||
data["name"] = field.text
|
||||
if field.get("name") == "parent_id":
|
||||
if field.get("name")=="parent_id":
|
||||
parent_id = field.get("ref") or field.get("eval")
|
||||
data["parent_id"] = parent_id
|
||||
|
||||
if field.get("name") == "user_type":
|
||||
if field.get("name")=="user_type":
|
||||
value = field.get("ref")
|
||||
if account_types.get(value, {}).get("account_type"):
|
||||
data["account_type"] = account_types[value]["account_type"]
|
||||
@@ -173,17 +161,16 @@ def make_maps_for_xml(xml_roots, account_types, country_dir):
|
||||
data["children"] = []
|
||||
accounts[node.get("id")] = data
|
||||
|
||||
if node.get("model") == "account.chart.template":
|
||||
if node.get("model")=="account.chart.template":
|
||||
data = {}
|
||||
for field in node.findall("field"):
|
||||
if field.get("name") == "name":
|
||||
if field.get("name")=="name":
|
||||
data["name"] = field.text
|
||||
if field.get("name") == "account_root_id":
|
||||
if field.get("name")=="account_root_id":
|
||||
data["account_root_id"] = field.get("ref")
|
||||
data["id"] = country_dir
|
||||
charts.setdefault(node.get("id"), {}).update(data)
|
||||
|
||||
|
||||
def make_maps_for_csv(csv_content, account_types, country_dir):
|
||||
for content in csv_content.get("account.account.template", []):
|
||||
for row in content[1:]:
|
||||
@@ -191,7 +178,7 @@ def make_maps_for_csv(csv_content, account_types, country_dir):
|
||||
account = {
|
||||
"name": data.get("name"),
|
||||
"parent_id": data.get("parent_id:id") or data.get("parent_id/id"),
|
||||
"children": [],
|
||||
"children": []
|
||||
}
|
||||
user_type = data.get("user_type/id") or data.get("user_type:id")
|
||||
if account_types.get(user_type, {}).get("account_type"):
|
||||
@@ -208,14 +195,12 @@ def make_maps_for_csv(csv_content, account_types, country_dir):
|
||||
for row in content[1:]:
|
||||
if row:
|
||||
data = dict(zip(content[0], row))
|
||||
charts.setdefault(data.get("id"), {}).update(
|
||||
{
|
||||
"account_root_id": data.get("account_root_id:id") or data.get("account_root_id/id"),
|
||||
"name": data.get("name"),
|
||||
"id": country_dir,
|
||||
}
|
||||
)
|
||||
|
||||
charts.setdefault(data.get("id"), {}).update({
|
||||
"account_root_id": data.get("account_root_id:id") or \
|
||||
data.get("account_root_id/id"),
|
||||
"name": data.get("name"),
|
||||
"id": country_dir
|
||||
})
|
||||
|
||||
def make_account_trees():
|
||||
"""build tree hierarchy"""
|
||||
@@ -234,7 +219,6 @@ def make_account_trees():
|
||||
if "children" in accounts[id] and not accounts[id].get("children"):
|
||||
del accounts[id]["children"]
|
||||
|
||||
|
||||
def make_charts():
|
||||
"""write chart files in app/setup/doctype/company/charts"""
|
||||
for chart_id in charts:
|
||||
@@ -253,38 +237,34 @@ def make_charts():
|
||||
chart["country_code"] = src["id"][5:]
|
||||
chart["tree"] = accounts[src["account_root_id"]]
|
||||
|
||||
|
||||
for key, val in chart["tree"].items():
|
||||
if key in ["name", "parent_id"]:
|
||||
chart["tree"].pop(key)
|
||||
if type(val) == dict:
|
||||
val["root_type"] = ""
|
||||
if chart:
|
||||
fpath = os.path.join(
|
||||
"erpnext", "erpnext", "accounts", "doctype", "account", "chart_of_accounts", filename + ".json"
|
||||
)
|
||||
fpath = os.path.join("erpnext", "erpnext", "accounts", "doctype", "account",
|
||||
"chart_of_accounts", filename + ".json")
|
||||
|
||||
with open(fpath, "r") as chartfile:
|
||||
old_content = chartfile.read()
|
||||
if not old_content or (
|
||||
json.loads(old_content).get("is_active", "No") == "No"
|
||||
and json.loads(old_content).get("disabled", "No") == "No"
|
||||
):
|
||||
if not old_content or (json.loads(old_content).get("is_active", "No") == "No" \
|
||||
and json.loads(old_content).get("disabled", "No") == "No"):
|
||||
with open(fpath, "w") as chartfile:
|
||||
chartfile.write(json.dumps(chart, indent=4, sort_keys=True))
|
||||
|
||||
all_roots.setdefault(filename, chart["tree"].keys())
|
||||
|
||||
|
||||
def create_all_roots_file():
|
||||
with open("all_roots.txt", "w") as f:
|
||||
with open('all_roots.txt', 'w') as f:
|
||||
for filename, roots in sorted(all_roots.items()):
|
||||
f.write(filename)
|
||||
f.write("\n----------------------\n")
|
||||
f.write('\n----------------------\n')
|
||||
for r in sorted(roots):
|
||||
f.write(r.encode("utf-8"))
|
||||
f.write("\n")
|
||||
f.write("\n\n\n")
|
||||
f.write(r.encode('utf-8'))
|
||||
f.write('\n')
|
||||
f.write('\n\n\n')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__=="__main__":
|
||||
go()
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
}
|
||||
},
|
||||
"Petty Cash": {
|
||||
"Petty Cash - Administration": {
|
||||
"Petty Cash - Admininistration": {
|
||||
"account_type": "Cash"
|
||||
},
|
||||
"Petty Cash - Others": {
|
||||
@@ -326,7 +326,7 @@
|
||||
"Current Liabilities": {
|
||||
"Accounts Payable": {
|
||||
"Payables": {
|
||||
"Advance Payable to Suppliers": {
|
||||
"Advance Paybale to Suppliers": {
|
||||
"account_type": "Payable"
|
||||
},
|
||||
"Consigned Payable": {
|
||||
|
||||
@@ -1,531 +0,0 @@
|
||||
{
|
||||
"country_code": "de",
|
||||
"name": "SKR03 mit Kontonummern",
|
||||
"tree": {
|
||||
"Aktiva": {
|
||||
"is_group": 1,
|
||||
"root_type": "Asset",
|
||||
"A - Anlagevermögen": {
|
||||
"is_group": 1,
|
||||
"EDV-Software": {
|
||||
"account_number": "0027",
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"Gesch\u00e4ftsausstattung": {
|
||||
"account_number": "0410",
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"B\u00fcroeinrichtung": {
|
||||
"account_number": "0420",
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"Darlehen": {
|
||||
"account_number": "0565"
|
||||
},
|
||||
"Maschinen": {
|
||||
"account_number": "0210",
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"Betriebsausstattung": {
|
||||
"account_number": "0400",
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"Ladeneinrichtung": {
|
||||
"account_number": "0430",
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"Accumulated Depreciation": {
|
||||
"account_type": "Accumulated Depreciation"
|
||||
}
|
||||
},
|
||||
"B - Umlaufvermögen": {
|
||||
"is_group": 1,
|
||||
"I. Vorräte": {
|
||||
"is_group": 1,
|
||||
"Roh-, Hilfs- und Betriebsstoffe (Bestand)": {
|
||||
"account_number": "3970",
|
||||
"account_type": "Stock"
|
||||
},
|
||||
"Waren (Bestand)": {
|
||||
"account_number": "3980",
|
||||
"account_type": "Stock"
|
||||
}
|
||||
},
|
||||
"II. Forderungen und sonstige Vermögensgegenstände": {
|
||||
"is_group": 1,
|
||||
"Ford. a. Lieferungen und Leistungen": {
|
||||
"account_number": "1400",
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
"Durchlaufende Posten": {
|
||||
"account_number": "1590"
|
||||
},
|
||||
"Gewinnermittlung \u00a74/3 nicht Ergebniswirksam": {
|
||||
"account_number": "1371"
|
||||
},
|
||||
"Abziehbare Vorsteuer": {
|
||||
"account_type": "Tax",
|
||||
"is_group": 1,
|
||||
"Abziehbare Vorsteuer 7%": {
|
||||
"account_number": "1571"
|
||||
},
|
||||
"Abziehbare Vorsteuer 19%": {
|
||||
"account_number": "1576"
|
||||
},
|
||||
"Abziehbare Vorsteuer nach \u00a713b UStG 19%": {
|
||||
"account_number": "1577"
|
||||
},
|
||||
"Leistungen \u00a713b UStG 19% Vorsteuer, 19% Umsatzsteuer": {
|
||||
"account_number": "3120"
|
||||
}
|
||||
}
|
||||
},
|
||||
"III. Wertpapiere": {
|
||||
"is_group": 1
|
||||
},
|
||||
"IV. Kassenbestand, Bundesbankguthaben, Guthaben bei Kreditinstituten und Schecks.": {
|
||||
"is_group": 1,
|
||||
"Kasse": {
|
||||
"account_type": "Cash",
|
||||
"is_group": 1,
|
||||
"Kasse": {
|
||||
"is_group": 1,
|
||||
"account_number": "1000",
|
||||
"account_type": "Cash"
|
||||
}
|
||||
},
|
||||
"Bank": {
|
||||
"is_group": 1,
|
||||
"account_type": "Bank",
|
||||
"Postbank": {
|
||||
"account_number": "1100",
|
||||
"account_type": "Bank"
|
||||
},
|
||||
"Bankkonto": {
|
||||
"account_number": "1200",
|
||||
"account_type": "Bank"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"C - Rechnungsabgrenzungsposten": {
|
||||
"is_group": 1,
|
||||
"Aktive Rechnungsabgrenzung": {
|
||||
"account_number": "0980"
|
||||
}
|
||||
},
|
||||
"D - Aktive latente Steuern": {
|
||||
"is_group": 1,
|
||||
"Aktive latente Steuern": {
|
||||
"account_number": "0983"
|
||||
}
|
||||
},
|
||||
"E - Aktiver Unterschiedsbetrag aus der Vermögensverrechnung": {
|
||||
"is_group": 1
|
||||
}
|
||||
},
|
||||
"Passiva": {
|
||||
"is_group": 1,
|
||||
"root_type": "Liability",
|
||||
"A. Eigenkapital": {
|
||||
"is_group": 1,
|
||||
"I. Gezeichnetes Kapital": {
|
||||
"is_group": 1
|
||||
},
|
||||
"II. Kapitalrücklage": {
|
||||
"is_group": 1
|
||||
},
|
||||
"III. Gewinnrücklagen": {
|
||||
"is_group": 1
|
||||
},
|
||||
"IV. Gewinnvortrag/Verlustvortrag": {
|
||||
"is_group": 1
|
||||
},
|
||||
"V. Jahresüberschuß/Jahresfehlbetrag": {
|
||||
"is_group": 1
|
||||
}
|
||||
},
|
||||
"B. Rückstellungen": {
|
||||
"is_group": 1,
|
||||
"I. Rückstellungen für Pensionen und ähnliche Verpflichtungen": {
|
||||
"is_group": 1
|
||||
},
|
||||
"II. Steuerrückstellungen": {
|
||||
"is_group": 1
|
||||
},
|
||||
"III. sonstige Rückstellungen": {
|
||||
"is_group": 1
|
||||
}
|
||||
},
|
||||
"C. Verbindlichkeiten": {
|
||||
"is_group": 1,
|
||||
"I. Anleihen": {
|
||||
"is_group": 1
|
||||
},
|
||||
"II. Verbindlichkeiten gegenüber Kreditinstituten": {
|
||||
"is_group": 1
|
||||
},
|
||||
"III. Erhaltene Anzahlungen auf Bestellungen": {
|
||||
"is_group": 1
|
||||
},
|
||||
"IV. Verbindlichkeiten aus Lieferungen und Leistungen": {
|
||||
"is_group": 1,
|
||||
"Verbindlichkeiten aus Lieferungen u. Leistungen": {
|
||||
"account_number": "1600",
|
||||
"account_type": "Payable"
|
||||
}
|
||||
},
|
||||
"V. Verbindlichkeiten aus der Annahme gezogener Wechsel und der Ausstellung eigener Wechsel": {
|
||||
"is_group": 1
|
||||
},
|
||||
"VI. Verbindlichkeiten gegenüber verbundenen Unternehmen": {
|
||||
"is_group": 1
|
||||
},
|
||||
"VII. Verbindlichkeiten gegenüber Unternehmen, mit denen ein Beteiligungsverhältnis besteht": {
|
||||
"is_group": 1
|
||||
},
|
||||
"VIII. sonstige Verbindlichkeiten": {
|
||||
"is_group": 1,
|
||||
"Sonstige Verbindlichkeiten": {
|
||||
"account_number": "1700",
|
||||
"account_type": "Asset Received But Not Billed"
|
||||
},
|
||||
"Sonstige Verbindlichkeiten (1 bis 5 Jahre)": {
|
||||
"account_number": "1702",
|
||||
"account_type": "Stock Received But Not Billed"
|
||||
},
|
||||
"Verbindlichkeiten aus Lohn und Gehalt": {
|
||||
"account_number": "1740",
|
||||
"account_type": "Payable"
|
||||
},
|
||||
"Umsatzsteuer": {
|
||||
"is_group": 1,
|
||||
"account_type": "Tax",
|
||||
"Umsatzsteuer 7%": {
|
||||
"account_number": "1771"
|
||||
},
|
||||
"Umsatzsteuer 19%": {
|
||||
"account_number": "1776"
|
||||
},
|
||||
"Umsatzsteuer-Vorauszahlung": {
|
||||
"account_number": "1780"
|
||||
},
|
||||
"Umsatzsteuer-Vorauszahlung 1/11": {
|
||||
"account_number": "1781"
|
||||
},
|
||||
"Umsatzsteuer \u00a7 13b UStG 19%": {
|
||||
"account_number": "1787"
|
||||
},
|
||||
"Umsatzsteuer Vorjahr": {
|
||||
"account_number": "1790"
|
||||
},
|
||||
"Umsatzsteuer fr\u00fchere Jahre": {
|
||||
"account_number": "1791"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"D. Rechnungsabgrenzungsposten": {
|
||||
"is_group": 1,
|
||||
"Passive Rechnungsabgrenzung": {
|
||||
"account_number": "0990"
|
||||
}
|
||||
},
|
||||
"E. Passive latente Steuern": {
|
||||
"is_group": 1
|
||||
}
|
||||
},
|
||||
"Erl\u00f6se u. Ertr\u00e4ge 2/8": {
|
||||
"is_group": 1,
|
||||
"root_type": "Income",
|
||||
"Erl\u00f6skonten 8": {
|
||||
"is_group": 1,
|
||||
"Erl\u00f6se": {
|
||||
"account_number": "8200",
|
||||
"account_type": "Income Account"
|
||||
},
|
||||
"Erl\u00f6se USt. 19%": {
|
||||
"account_number": "8400",
|
||||
"account_type": "Income Account"
|
||||
},
|
||||
"Erl\u00f6se USt. 7%": {
|
||||
"account_number": "8300",
|
||||
"account_type": "Income Account"
|
||||
}
|
||||
},
|
||||
"Ertragskonten 2": {
|
||||
"is_group": 1,
|
||||
"sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge": {
|
||||
"account_number": "2650",
|
||||
"account_type": "Income Account"
|
||||
},
|
||||
"Au\u00dferordentliche Ertr\u00e4ge": {
|
||||
"account_number": "2500",
|
||||
"account_type": "Income Account"
|
||||
},
|
||||
"Sonstige Ertr\u00e4ge": {
|
||||
"account_number": "2700",
|
||||
"account_type": "Income Account"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Aufwendungen 2/4": {
|
||||
"is_group": 1,
|
||||
"root_type": "Expense",
|
||||
"Wareneingang": {
|
||||
"account_number": "3200"
|
||||
},
|
||||
"Bezugsnebenkosten": {
|
||||
"account_number": "3800",
|
||||
"account_type": "Expenses Included In Asset Valuation"
|
||||
},
|
||||
"Herstellungskosten": {
|
||||
"account_number": "4996",
|
||||
"account_type": "Cost of Goods Sold"
|
||||
},
|
||||
"Verluste aus dem Abgang von Gegenständen des Anlagevermögens": {
|
||||
"account_number": "2320",
|
||||
"account_type": "Stock Adjustment"
|
||||
},
|
||||
"Verwaltungskosten": {
|
||||
"account_number": "4997",
|
||||
"account_type": "Expenses Included In Valuation"
|
||||
},
|
||||
"Vertriebskosten": {
|
||||
"account_number": "4998",
|
||||
"account_type": "Expenses Included In Valuation"
|
||||
},
|
||||
"Gegenkonto 4996-4998": {
|
||||
"account_number": "4999"
|
||||
},
|
||||
"Abschreibungen": {
|
||||
"is_group": 1,
|
||||
"Abschreibungen auf Sachanlagen (ohne AfA auf Kfz und Gebäude)": {
|
||||
"account_number": "4830",
|
||||
"account_type": "Accumulated Depreciation"
|
||||
},
|
||||
"Abschreibungen auf Gebäude": {
|
||||
"account_number": "4831",
|
||||
"account_type": "Depreciation"
|
||||
},
|
||||
"Abschreibungen auf Kfz": {
|
||||
"account_number": "4832",
|
||||
"account_type": "Depreciation"
|
||||
},
|
||||
"Sofortabschreibung GWG": {
|
||||
"account_number": "4855",
|
||||
"account_type": "Expense Account"
|
||||
}
|
||||
},
|
||||
"Kfz-Kosten": {
|
||||
"is_group": 1,
|
||||
"Kfz-Steuer": {
|
||||
"account_number": "4510",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Kfz-Versicherungen": {
|
||||
"account_number": "4520",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"laufende Kfz-Betriebskosten": {
|
||||
"account_number": "4530",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Kfz-Reparaturen": {
|
||||
"account_number": "4540",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Fremdfahrzeuge": {
|
||||
"account_number": "4570",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"sonstige Kfz-Kosten": {
|
||||
"account_number": "4580",
|
||||
"account_type": "Expense Account"
|
||||
}
|
||||
},
|
||||
"Personalkosten": {
|
||||
"is_group": 1,
|
||||
"Geh\u00e4lter": {
|
||||
"account_number": "4120",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"gesetzliche soziale Aufwendungen": {
|
||||
"account_number": "4130",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Aufwendungen f\u00fcr Altersvorsorge": {
|
||||
"account_number": "4165",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Verm\u00f6genswirksame Leistungen": {
|
||||
"account_number": "4170",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Aushilfsl\u00f6hne": {
|
||||
"account_number": "4190",
|
||||
"account_type": "Expense Account"
|
||||
}
|
||||
},
|
||||
"Raumkosten": {
|
||||
"is_group": 1,
|
||||
"Miete und Nebenkosten": {
|
||||
"account_number": "4210",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Gas, Wasser, Strom (Verwaltung, Vertrieb)": {
|
||||
"account_number": "4240",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Reinigung": {
|
||||
"account_number": "4250",
|
||||
"account_type": "Expense Account"
|
||||
}
|
||||
},
|
||||
"Reparatur/Instandhaltung": {
|
||||
"is_group": 1,
|
||||
"Reparatur u. Instandh. von Anlagen/Maschinen u. Betriebs- u. Gesch\u00e4ftsausst.": {
|
||||
"account_number": "4805",
|
||||
"account_type": "Expense Account"
|
||||
}
|
||||
},
|
||||
"Versicherungsbeitr\u00e4ge": {
|
||||
"is_group": 1,
|
||||
"Versicherungen": {
|
||||
"account_number": "4360",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Beitr\u00e4ge": {
|
||||
"account_number": "4380",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"sonstige Ausgaben": {
|
||||
"account_number": "4390",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"steuerlich abzugsf\u00e4hige Versp\u00e4tungszuschl\u00e4ge und Zwangsgelder": {
|
||||
"account_number": "4396",
|
||||
"account_type": "Expense Account"
|
||||
}
|
||||
},
|
||||
"Werbe-/Reisekosten": {
|
||||
"is_group": 1,
|
||||
"Werbekosten": {
|
||||
"account_number": "4610",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Aufmerksamkeiten": {
|
||||
"account_number": "4653",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"nicht abzugsf\u00e4hige Betriebsausg. aus Werbe-, Repr\u00e4s.- u. Reisekosten": {
|
||||
"account_number": "4665",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Reisekosten Unternehmer": {
|
||||
"account_number": "4670",
|
||||
"account_type": "Expense Account"
|
||||
}
|
||||
},
|
||||
"verschiedene Kosten": {
|
||||
"is_group": 1,
|
||||
"Porto": {
|
||||
"account_number": "4910",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Telekom": {
|
||||
"account_number": "4920",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Mobilfunk D2": {
|
||||
"account_number": "4921",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Internet": {
|
||||
"account_number": "4922",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"B\u00fcrobedarf": {
|
||||
"account_number": "4930",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Zeitschriften, B\u00fccher": {
|
||||
"account_number": "4940",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Fortbildungskosten": {
|
||||
"account_number": "4945",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Buchf\u00fchrungskosten": {
|
||||
"account_number": "4955",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Abschlu\u00df- u. Pr\u00fcfungskosten": {
|
||||
"account_number": "4957",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Nebenkosten des Geldverkehrs": {
|
||||
"account_number": "4970",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Werkzeuge und Kleinger\u00e4te": {
|
||||
"account_number": "4985",
|
||||
"account_type": "Expense Account"
|
||||
}
|
||||
},
|
||||
"Zinsaufwendungen": {
|
||||
"is_group": 1,
|
||||
"Zinsaufwendungen f\u00fcr kurzfristige Verbindlichkeiten": {
|
||||
"account_number": "2110",
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
"Zinsaufwendungen f\u00fcr KFZ Finanzierung": {
|
||||
"account_number": "2121",
|
||||
"account_type": "Expense Account"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Anfangsbestand 9": {
|
||||
"is_group": 1,
|
||||
"root_type": "Equity",
|
||||
"Saldenvortragskonten": {
|
||||
"is_group": 1,
|
||||
"Saldenvortrag Sachkonten": {
|
||||
"account_number": "9000"
|
||||
},
|
||||
"Saldenvortr\u00e4ge Debitoren": {
|
||||
"account_number": "9008"
|
||||
},
|
||||
"Saldenvortr\u00e4ge Kreditoren": {
|
||||
"account_number": "9009"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Privatkonten 1": {
|
||||
"is_group": 1,
|
||||
"root_type": "Equity",
|
||||
"Privatentnahmen/-einlagen": {
|
||||
"is_group": 1,
|
||||
"Privatentnahme allgemein": {
|
||||
"account_number": "1800"
|
||||
},
|
||||
"Privatsteuern": {
|
||||
"account_number": "1810"
|
||||
},
|
||||
"Sonderausgaben beschr\u00e4nkt abzugsf\u00e4hig": {
|
||||
"account_number": "1820"
|
||||
},
|
||||
"Sonderausgaben unbeschr\u00e4nkt abzugsf\u00e4hig": {
|
||||
"account_number": "1830"
|
||||
},
|
||||
"Au\u00dfergew\u00f6hnliche Belastungen": {
|
||||
"account_number": "1850"
|
||||
},
|
||||
"Privateinlagen": {
|
||||
"account_number": "1890"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,21 +292,18 @@
|
||||
"Umsatzsteuerforderungen fr\u00fchere Jahre": {}
|
||||
},
|
||||
"Sonstige Verm\u00f6gensgegenst\u00e4nde oder sonstige Verbindlichkeiten": {
|
||||
"Abziehbare Vorsteuer": {
|
||||
"account_type": "Tax",
|
||||
"is_group": 1,
|
||||
"Abziehbare Vorsteuer 16%": {},
|
||||
"Abziehbare Vorsteuer 19%": {},
|
||||
"Abziehbare Vorsteuer 7%": {},
|
||||
"Abziehbare Vorsteuer aus der Auslagerung von Gegenst\u00e4nden aus einem Unsatzsteuerlager": {},
|
||||
"Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb": {},
|
||||
"Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb 16%": {},
|
||||
"Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb 19%": {},
|
||||
"Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb von Neufahrzeugen von Lieferanten ohne Ust-Identifikationsnummer": {},
|
||||
"Abziehbare Vorsteuer nach \u00a7 13b UStG ": {},
|
||||
"Abziehbare Vorsteuer nach \u00a7 13b UStG 16%": {},
|
||||
"Abziehbare Vorsteuer nach \u00a7 13b UStG 19%": {}
|
||||
},
|
||||
"Abziehbare Vorsteuer": {},
|
||||
"Abziehbare Vorsteuer 16%": {},
|
||||
"Abziehbare Vorsteuer 19%": {},
|
||||
"Abziehbare Vorsteuer 7%": {},
|
||||
"Abziehbare Vorsteuer aus der Auslagerung von Gegenst\u00e4nden aus einem Unsatzsteuerlager": {},
|
||||
"Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb": {},
|
||||
"Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb 16%": {},
|
||||
"Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb 19%": {},
|
||||
"Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb von Neufahrzeugen von Lieferanten ohne Ust-Identifikationsnummer": {},
|
||||
"Abziehbare Vorsteuer nach \u00a7 13b UStG ": {},
|
||||
"Abziehbare Vorsteuer nach \u00a7 13b UStG 16%": {},
|
||||
"Abziehbare Vorsteuer nach \u00a7 13b UStG 19%": {},
|
||||
"Aufl\u00f6sung Vorsteuer aus Vorjahr \u00a7 4/3 EStG": {},
|
||||
"Aufzuteilende Vorsteuer": {},
|
||||
"Aufzuteilende Vorsteuer 16%": {},
|
||||
@@ -676,26 +673,23 @@
|
||||
"Sonstige Verrechnungskonten (Interimskonto)": {
|
||||
"account_type": "Stock Received But Not Billed"
|
||||
},
|
||||
"Umsatzsteuer": {
|
||||
"account_type": "Tax",
|
||||
"is_group": 1,
|
||||
"Umsatzsteuer 16%": {},
|
||||
"Umsatzsteuer 19%": {},
|
||||
"Umsatzsteuer 7%": {},
|
||||
"Umsatzsteuer Vorjahr": {},
|
||||
"Umsatzsteuer aus der Auslagerung von Gegenst\u00e4nden aus einem Umsatzsteuerlager": {},
|
||||
"Umsatzsteuer aus im Inland steuerpflichtigen EG-Lieferungen": {},
|
||||
"Umsatzsteuer aus im Inland steuerpflichtigen EG-Lieferungen 19%": {},
|
||||
"Umsatzsteuer aus innergemeinschaftlichem Erwerb ": {},
|
||||
"Umsatzsteuer aus innergemeinschaftlichem Erwerb 16%": {},
|
||||
"Umsatzsteuer aus innergemeinschaftlichem Erwerb 19%": {},
|
||||
"Umsatzsteuer aus innergemeinschaftlichem Erwerb ohne Vorsteuerabzug": {},
|
||||
"Umsatzsteuer fr\u00fchere Jahre": {},
|
||||
"Umsatzsteuer laufendes Jahr": {},
|
||||
"Umsatzsteuer nach \u00a713b UStG": {},
|
||||
"Umsatzsteuer nach \u00a713b UStG 16%": {},
|
||||
"Umsatzsteuer nach \u00a713b UStG 19%": {}
|
||||
},
|
||||
"Umsatzsteuer": {},
|
||||
"Umsatzsteuer 16%": {},
|
||||
"Umsatzsteuer 19%": {},
|
||||
"Umsatzsteuer 7%": {},
|
||||
"Umsatzsteuer Vorjahr": {},
|
||||
"Umsatzsteuer aus der Auslagerung von Gegenst\u00e4nden aus einem Umsatzsteuerlager": {},
|
||||
"Umsatzsteuer aus im Inland steuerpflichtigen EG-Lieferungen": {},
|
||||
"Umsatzsteuer aus im Inland steuerpflichtigen EG-Lieferungen 19%": {},
|
||||
"Umsatzsteuer aus innergemeinschaftlichem Erwerb ": {},
|
||||
"Umsatzsteuer aus innergemeinschaftlichem Erwerb 16%": {},
|
||||
"Umsatzsteuer aus innergemeinschaftlichem Erwerb 19%": {},
|
||||
"Umsatzsteuer aus innergemeinschaftlichem Erwerb ohne Vorsteuerabzug": {},
|
||||
"Umsatzsteuer fr\u00fchere Jahre": {},
|
||||
"Umsatzsteuer laufendes Jahr": {},
|
||||
"Umsatzsteuer nach \u00a713b UStG": {},
|
||||
"Umsatzsteuer nach \u00a713b UStG 16%": {},
|
||||
"Umsatzsteuer nach \u00a713b UStG 19%": {},
|
||||
"Umsatzsteuer- Vorauszahlungen": {},
|
||||
"Umsatzsteuer- Vorauszahlungen 1/11": {},
|
||||
"Verbindlichkeiten aus Lohn- und Kirchensteuer": {}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,809 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,109 +1,187 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe import _
|
||||
|
||||
|
||||
def get():
|
||||
return {
|
||||
_("Application of Funds (Assets)"): {
|
||||
_("Current Assets"): {
|
||||
_("Accounts Receivable"): {_("Debtors"): {"account_type": "Receivable"}},
|
||||
_("Bank Accounts"): {"account_type": "Bank", "is_group": 1},
|
||||
_("Cash In Hand"): {_("Cash"): {"account_type": "Cash"}, "account_type": "Cash"},
|
||||
_("Loans and Advances (Assets)"): {
|
||||
_("Employee Advances"): {},
|
||||
_("Application of Funds (Assets)"): {
|
||||
_("Current Assets"): {
|
||||
_("Accounts Receivable"): {
|
||||
_("Debtors"): {
|
||||
"account_type": "Receivable"
|
||||
}
|
||||
},
|
||||
_("Bank Accounts"): {
|
||||
"account_type": "Bank",
|
||||
"is_group": 1
|
||||
},
|
||||
_("Cash In Hand"): {
|
||||
_("Cash"): {
|
||||
"account_type": "Cash"
|
||||
},
|
||||
"account_type": "Cash"
|
||||
},
|
||||
_("Loans and Advances (Assets)"): {
|
||||
_("Employee Advances"): {
|
||||
},
|
||||
},
|
||||
_("Securities and Deposits"): {
|
||||
_("Earnest Money"): {}
|
||||
},
|
||||
_("Stock Assets"): {
|
||||
_("Stock In Hand"): {
|
||||
"account_type": "Stock"
|
||||
},
|
||||
"account_type": "Stock",
|
||||
},
|
||||
_("Tax Assets"): {
|
||||
"is_group": 1
|
||||
}
|
||||
},
|
||||
_("Fixed Assets"): {
|
||||
_("Capital Equipments"): {
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
_("Electronic Equipments"): {
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
_("Furnitures and Fixtures"): {
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
_("Office Equipments"): {
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
_("Plants and Machineries"): {
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
_("Buildings"): {
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
_("Securities and Deposits"): {_("Earnest Money"): {}},
|
||||
_("Stock Assets"): {
|
||||
_("Stock In Hand"): {"account_type": "Stock"},
|
||||
"account_type": "Stock",
|
||||
_("Softwares"): {
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
_("Tax Assets"): {"is_group": 1},
|
||||
},
|
||||
_("Fixed Assets"): {
|
||||
_("Capital Equipments"): {"account_type": "Fixed Asset"},
|
||||
_("Electronic Equipments"): {"account_type": "Fixed Asset"},
|
||||
_("Furnitures and Fixtures"): {"account_type": "Fixed Asset"},
|
||||
_("Office Equipments"): {"account_type": "Fixed Asset"},
|
||||
_("Plants and Machineries"): {"account_type": "Fixed Asset"},
|
||||
_("Buildings"): {"account_type": "Fixed Asset"},
|
||||
_("Softwares"): {"account_type": "Fixed Asset"},
|
||||
_("Accumulated Depreciation"): {"account_type": "Accumulated Depreciation"},
|
||||
_("CWIP Account"): {
|
||||
"account_type": "Capital Work in Progress",
|
||||
},
|
||||
},
|
||||
_("Investments"): {"is_group": 1},
|
||||
_("Temporary Accounts"): {_("Temporary Opening"): {"account_type": "Temporary"}},
|
||||
"root_type": "Asset",
|
||||
},
|
||||
_("Expenses"): {
|
||||
_("Direct Expenses"): {
|
||||
_("Stock Expenses"): {
|
||||
_("Cost of Goods Sold"): {"account_type": "Cost of Goods Sold"},
|
||||
_("Expenses Included In Asset Valuation"): {
|
||||
"account_type": "Expenses Included In Asset Valuation"
|
||||
},
|
||||
_("Expenses Included In Valuation"): {"account_type": "Expenses Included In Valuation"},
|
||||
_("Stock Adjustment"): {"account_type": "Stock Adjustment"},
|
||||
},
|
||||
},
|
||||
_("Indirect Expenses"): {
|
||||
_("Administrative Expenses"): {},
|
||||
_("Commission on Sales"): {},
|
||||
_("Depreciation"): {"account_type": "Depreciation"},
|
||||
_("Entertainment Expenses"): {},
|
||||
_("Freight and Forwarding Charges"): {"account_type": "Chargeable"},
|
||||
_("Legal Expenses"): {},
|
||||
_("Marketing Expenses"): {"account_type": "Chargeable"},
|
||||
_("Miscellaneous Expenses"): {"account_type": "Chargeable"},
|
||||
_("Office Maintenance Expenses"): {},
|
||||
_("Office Rent"): {},
|
||||
_("Postal Expenses"): {},
|
||||
_("Print and Stationery"): {},
|
||||
_("Round Off"): {"account_type": "Round Off"},
|
||||
_("Salary"): {},
|
||||
_("Sales Expenses"): {},
|
||||
_("Telephone Expenses"): {},
|
||||
_("Travel Expenses"): {},
|
||||
_("Utility Expenses"): {},
|
||||
_("Accumulated Depreciation"): {
|
||||
"account_type": "Accumulated Depreciation"
|
||||
},
|
||||
_("CWIP Account"): {
|
||||
"account_type": "Capital Work in Progress",
|
||||
}
|
||||
},
|
||||
_("Investments"): {
|
||||
"is_group": 1
|
||||
},
|
||||
_("Temporary Accounts"): {
|
||||
_("Temporary Opening"): {
|
||||
"account_type": "Temporary"
|
||||
}
|
||||
},
|
||||
"root_type": "Asset"
|
||||
},
|
||||
_("Expenses"): {
|
||||
_("Direct Expenses"): {
|
||||
_("Stock Expenses"): {
|
||||
_("Cost of Goods Sold"): {
|
||||
"account_type": "Cost of Goods Sold"
|
||||
},
|
||||
_("Expenses Included In Asset Valuation"): {
|
||||
"account_type": "Expenses Included In Asset Valuation"
|
||||
},
|
||||
_("Expenses Included In Valuation"): {
|
||||
"account_type": "Expenses Included In Valuation"
|
||||
},
|
||||
_("Stock Adjustment"): {
|
||||
"account_type": "Stock Adjustment"
|
||||
}
|
||||
},
|
||||
},
|
||||
_("Indirect Expenses"): {
|
||||
_("Administrative Expenses"): {},
|
||||
_("Commission on Sales"): {},
|
||||
_("Depreciation"): {
|
||||
"account_type": "Depreciation"
|
||||
},
|
||||
_("Entertainment Expenses"): {},
|
||||
_("Freight and Forwarding Charges"): {
|
||||
"account_type": "Chargeable"
|
||||
},
|
||||
_("Legal Expenses"): {},
|
||||
_("Marketing Expenses"): {
|
||||
"account_type": "Chargeable"
|
||||
},
|
||||
_("Miscellaneous Expenses"): {
|
||||
"account_type": "Chargeable"
|
||||
},
|
||||
_("Office Maintenance Expenses"): {},
|
||||
_("Office Rent"): {},
|
||||
_("Postal Expenses"): {},
|
||||
_("Print and Stationery"): {},
|
||||
_("Round Off"): {
|
||||
"account_type": "Round Off"
|
||||
},
|
||||
_("Salary"): {},
|
||||
_("Sales Expenses"): {},
|
||||
_("Telephone Expenses"): {},
|
||||
_("Travel Expenses"): {},
|
||||
_("Utility Expenses"): {},
|
||||
_("Write Off"): {},
|
||||
_("Exchange Gain/Loss"): {},
|
||||
_("Gain/Loss on Asset Disposal"): {},
|
||||
},
|
||||
"root_type": "Expense",
|
||||
},
|
||||
_("Income"): {
|
||||
_("Direct Income"): {_("Sales"): {}, _("Service"): {}},
|
||||
_("Indirect Income"): {"is_group": 1},
|
||||
"root_type": "Income",
|
||||
},
|
||||
_("Source of Funds (Liabilities)"): {
|
||||
_("Current Liabilities"): {
|
||||
_("Accounts Payable"): {
|
||||
_("Creditors"): {"account_type": "Payable"},
|
||||
_("Payroll Payable"): {},
|
||||
_("Gain/Loss on Asset Disposal"): {}
|
||||
},
|
||||
"root_type": "Expense"
|
||||
},
|
||||
_("Income"): {
|
||||
_("Direct Income"): {
|
||||
_("Sales"): {},
|
||||
_("Service"): {}
|
||||
},
|
||||
_("Indirect Income"): {
|
||||
"is_group": 1
|
||||
},
|
||||
"root_type": "Income"
|
||||
},
|
||||
_("Source of Funds (Liabilities)"): {
|
||||
_("Current Liabilities"): {
|
||||
_("Accounts Payable"): {
|
||||
_("Creditors"): {
|
||||
"account_type": "Payable"
|
||||
},
|
||||
_("Payroll Payable"): {},
|
||||
},
|
||||
_("Stock Liabilities"): {
|
||||
_("Stock Received But Not Billed"): {
|
||||
"account_type": "Stock Received But Not Billed"
|
||||
},
|
||||
_("Asset Received But Not Billed"): {
|
||||
"account_type": "Asset Received But Not Billed"
|
||||
}
|
||||
},
|
||||
_("Duties and Taxes"): {
|
||||
"account_type": "Tax",
|
||||
"is_group": 1
|
||||
},
|
||||
_("Stock Liabilities"): {
|
||||
_("Stock Received But Not Billed"): {"account_type": "Stock Received But Not Billed"},
|
||||
_("Asset Received But Not Billed"): {"account_type": "Asset Received But Not Billed"},
|
||||
},
|
||||
_("Duties and Taxes"): {"account_type": "Tax", "is_group": 1},
|
||||
_("Loans (Liabilities)"): {
|
||||
_("Secured Loans"): {},
|
||||
_("Unsecured Loans"): {},
|
||||
_("Bank Overdraft Account"): {},
|
||||
},
|
||||
},
|
||||
"root_type": "Liability",
|
||||
},
|
||||
},
|
||||
"root_type": "Liability"
|
||||
},
|
||||
_("Equity"): {
|
||||
_("Capital Stock"): {"account_type": "Equity"},
|
||||
_("Dividends Paid"): {"account_type": "Equity"},
|
||||
_("Opening Balance Equity"): {"account_type": "Equity"},
|
||||
_("Retained Earnings"): {"account_type": "Equity"},
|
||||
"root_type": "Equity",
|
||||
},
|
||||
_("Capital Stock"): {
|
||||
"account_type": "Equity"
|
||||
},
|
||||
_("Dividends Paid"): {
|
||||
"account_type": "Equity"
|
||||
},
|
||||
_("Opening Balance Equity"): {
|
||||
"account_type": "Equity"
|
||||
},
|
||||
_("Retained Earnings"): {
|
||||
"account_type": "Equity"
|
||||
},
|
||||
"root_type": "Equity"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,158 +1,289 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe import _
|
||||
|
||||
|
||||
def get():
|
||||
return {
|
||||
_("Application of Funds (Assets)"): {
|
||||
_("Current Assets"): {
|
||||
_("Accounts Receivable"): {
|
||||
_("Debtors"): {"account_type": "Receivable", "account_number": "1310"},
|
||||
"account_number": "1300",
|
||||
},
|
||||
_("Bank Accounts"): {"account_type": "Bank", "is_group": 1, "account_number": "1200"},
|
||||
_("Cash In Hand"): {
|
||||
_("Cash"): {"account_type": "Cash", "account_number": "1110"},
|
||||
"account_type": "Cash",
|
||||
"account_number": "1100",
|
||||
},
|
||||
_("Loans and Advances (Assets)"): {
|
||||
_("Employee Advances"): {"account_number": "1610"},
|
||||
"account_number": "1600",
|
||||
},
|
||||
_("Securities and Deposits"): {
|
||||
_("Earnest Money"): {"account_number": "1651"},
|
||||
"account_number": "1650",
|
||||
},
|
||||
_("Stock Assets"): {
|
||||
_("Stock In Hand"): {"account_type": "Stock", "account_number": "1410"},
|
||||
"account_type": "Stock",
|
||||
"account_number": "1400",
|
||||
},
|
||||
_("Tax Assets"): {"is_group": 1, "account_number": "1500"},
|
||||
"account_number": "1100-1600",
|
||||
},
|
||||
_("Fixed Assets"): {
|
||||
_("Capital Equipments"): {"account_type": "Fixed Asset", "account_number": "1710"},
|
||||
_("Electronic Equipments"): {"account_type": "Fixed Asset", "account_number": "1720"},
|
||||
_("Furnitures and Fixtures"): {"account_type": "Fixed Asset", "account_number": "1730"},
|
||||
_("Office Equipments"): {"account_type": "Fixed Asset", "account_number": "1740"},
|
||||
_("Plants and Machineries"): {"account_type": "Fixed Asset", "account_number": "1750"},
|
||||
_("Buildings"): {"account_type": "Fixed Asset", "account_number": "1760"},
|
||||
_("Softwares"): {"account_type": "Fixed Asset", "account_number": "1770"},
|
||||
_("Accumulated Depreciation"): {
|
||||
"account_type": "Accumulated Depreciation",
|
||||
"account_number": "1780",
|
||||
},
|
||||
_("CWIP Account"): {"account_type": "Capital Work in Progress", "account_number": "1790"},
|
||||
"account_number": "1700",
|
||||
},
|
||||
_("Investments"): {"is_group": 1, "account_number": "1800"},
|
||||
_("Temporary Accounts"): {
|
||||
_("Temporary Opening"): {"account_type": "Temporary", "account_number": "1910"},
|
||||
"account_number": "1900",
|
||||
},
|
||||
"root_type": "Asset",
|
||||
"account_number": "1000",
|
||||
},
|
||||
_("Expenses"): {
|
||||
_("Direct Expenses"): {
|
||||
_("Stock Expenses"): {
|
||||
_("Cost of Goods Sold"): {"account_type": "Cost of Goods Sold", "account_number": "5111"},
|
||||
_("Expenses Included In Asset Valuation"): {
|
||||
"account_type": "Expenses Included In Asset Valuation",
|
||||
"account_number": "5112",
|
||||
},
|
||||
_("Expenses Included In Valuation"): {
|
||||
"account_type": "Expenses Included In Valuation",
|
||||
"account_number": "5118",
|
||||
},
|
||||
_("Stock Adjustment"): {"account_type": "Stock Adjustment", "account_number": "5119"},
|
||||
"account_number": "5110",
|
||||
},
|
||||
"account_number": "5100",
|
||||
},
|
||||
_("Indirect Expenses"): {
|
||||
_("Administrative Expenses"): {"account_number": "5201"},
|
||||
_("Commission on Sales"): {"account_number": "5202"},
|
||||
_("Depreciation"): {"account_type": "Depreciation", "account_number": "5203"},
|
||||
_("Entertainment Expenses"): {"account_number": "5204"},
|
||||
_("Freight and Forwarding Charges"): {"account_type": "Chargeable", "account_number": "5205"},
|
||||
_("Legal Expenses"): {"account_number": "5206"},
|
||||
_("Marketing Expenses"): {"account_type": "Chargeable", "account_number": "5207"},
|
||||
_("Office Maintenance Expenses"): {"account_number": "5208"},
|
||||
_("Office Rent"): {"account_number": "5209"},
|
||||
_("Postal Expenses"): {"account_number": "5210"},
|
||||
_("Print and Stationery"): {"account_number": "5211"},
|
||||
_("Round Off"): {"account_type": "Round Off", "account_number": "5212"},
|
||||
_("Salary"): {"account_number": "5213"},
|
||||
_("Sales Expenses"): {"account_number": "5214"},
|
||||
_("Telephone Expenses"): {"account_number": "5215"},
|
||||
_("Travel Expenses"): {"account_number": "5216"},
|
||||
_("Utility Expenses"): {"account_number": "5217"},
|
||||
_("Write Off"): {"account_number": "5218"},
|
||||
_("Exchange Gain/Loss"): {"account_number": "5219"},
|
||||
_("Gain/Loss on Asset Disposal"): {"account_number": "5220"},
|
||||
_("Miscellaneous Expenses"): {"account_type": "Chargeable", "account_number": "5221"},
|
||||
"account_number": "5200",
|
||||
},
|
||||
"root_type": "Expense",
|
||||
"account_number": "5000",
|
||||
},
|
||||
_("Income"): {
|
||||
_("Direct Income"): {
|
||||
_("Sales"): {"account_number": "4110"},
|
||||
_("Service"): {"account_number": "4120"},
|
||||
"account_number": "4100",
|
||||
},
|
||||
_("Indirect Income"): {"is_group": 1, "account_number": "4200"},
|
||||
"root_type": "Income",
|
||||
"account_number": "4000",
|
||||
},
|
||||
_("Source of Funds (Liabilities)"): {
|
||||
_("Current Liabilities"): {
|
||||
_("Accounts Payable"): {
|
||||
_("Creditors"): {"account_type": "Payable", "account_number": "2110"},
|
||||
_("Payroll Payable"): {"account_number": "2120"},
|
||||
"account_number": "2100",
|
||||
},
|
||||
_("Stock Liabilities"): {
|
||||
_("Stock Received But Not Billed"): {
|
||||
"account_type": "Stock Received But Not Billed",
|
||||
"account_number": "2210",
|
||||
},
|
||||
_("Asset Received But Not Billed"): {
|
||||
"account_type": "Asset Received But Not Billed",
|
||||
"account_number": "2211",
|
||||
},
|
||||
"account_number": "2200",
|
||||
},
|
||||
_("Duties and Taxes"): {
|
||||
_("TDS Payable"): {"account_number": "2310"},
|
||||
"account_type": "Tax",
|
||||
"is_group": 1,
|
||||
"account_number": "2300",
|
||||
},
|
||||
_("Loans (Liabilities)"): {
|
||||
_("Secured Loans"): {"account_number": "2410"},
|
||||
_("Unsecured Loans"): {"account_number": "2420"},
|
||||
_("Bank Overdraft Account"): {"account_number": "2430"},
|
||||
"account_number": "2400",
|
||||
},
|
||||
"account_number": "2100-2400",
|
||||
},
|
||||
"root_type": "Liability",
|
||||
"account_number": "2000",
|
||||
},
|
||||
_("Equity"): {
|
||||
_("Capital Stock"): {"account_type": "Equity", "account_number": "3100"},
|
||||
_("Dividends Paid"): {"account_type": "Equity", "account_number": "3200"},
|
||||
_("Opening Balance Equity"): {"account_type": "Equity", "account_number": "3300"},
|
||||
_("Retained Earnings"): {"account_type": "Equity", "account_number": "3400"},
|
||||
"root_type": "Equity",
|
||||
"account_number": "3000",
|
||||
},
|
||||
}
|
||||
return {
|
||||
_("Application of Funds (Assets)"): {
|
||||
_("Current Assets"): {
|
||||
_("Accounts Receivable"): {
|
||||
_("Debtors"): {
|
||||
"account_type": "Receivable",
|
||||
"account_number": "1310"
|
||||
},
|
||||
"account_number": "1300"
|
||||
},
|
||||
_("Bank Accounts"): {
|
||||
"account_type": "Bank",
|
||||
"is_group": 1,
|
||||
"account_number": "1200"
|
||||
},
|
||||
_("Cash In Hand"): {
|
||||
_("Cash"): {
|
||||
"account_type": "Cash",
|
||||
"account_number": "1110"
|
||||
},
|
||||
"account_type": "Cash",
|
||||
"account_number": "1100"
|
||||
},
|
||||
_("Loans and Advances (Assets)"): {
|
||||
_("Employee Advances"): {
|
||||
"account_number": "1610"
|
||||
},
|
||||
"account_number": "1600"
|
||||
},
|
||||
_("Securities and Deposits"): {
|
||||
_("Earnest Money"): {
|
||||
"account_number": "1651"
|
||||
},
|
||||
"account_number": "1650"
|
||||
},
|
||||
_("Stock Assets"): {
|
||||
_("Stock In Hand"): {
|
||||
"account_type": "Stock",
|
||||
"account_number": "1410"
|
||||
},
|
||||
"account_type": "Stock",
|
||||
"account_number": "1400"
|
||||
},
|
||||
_("Tax Assets"): {
|
||||
"is_group": 1,
|
||||
"account_number": "1500"
|
||||
},
|
||||
"account_number": "1100-1600"
|
||||
},
|
||||
_("Fixed Assets"): {
|
||||
_("Capital Equipments"): {
|
||||
"account_type": "Fixed Asset",
|
||||
"account_number": "1710"
|
||||
},
|
||||
_("Electronic Equipments"): {
|
||||
"account_type": "Fixed Asset",
|
||||
"account_number": "1720"
|
||||
},
|
||||
_("Furnitures and Fixtures"): {
|
||||
"account_type": "Fixed Asset",
|
||||
"account_number": "1730"
|
||||
},
|
||||
_("Office Equipments"): {
|
||||
"account_type": "Fixed Asset",
|
||||
"account_number": "1740"
|
||||
},
|
||||
_("Plants and Machineries"): {
|
||||
"account_type": "Fixed Asset",
|
||||
"account_number": "1750"
|
||||
},
|
||||
_("Buildings"): {
|
||||
"account_type": "Fixed Asset",
|
||||
"account_number": "1760"
|
||||
},
|
||||
_("Softwares"): {
|
||||
"account_type": "Fixed Asset",
|
||||
"account_number": "1770"
|
||||
},
|
||||
_("Accumulated Depreciation"): {
|
||||
"account_type": "Accumulated Depreciation",
|
||||
"account_number": "1780"
|
||||
},
|
||||
_("CWIP Account"): {
|
||||
"account_type": "Capital Work in Progress",
|
||||
"account_number": "1790"
|
||||
},
|
||||
"account_number": "1700"
|
||||
},
|
||||
_("Investments"): {
|
||||
"is_group": 1,
|
||||
"account_number": "1800"
|
||||
},
|
||||
_("Temporary Accounts"): {
|
||||
_("Temporary Opening"): {
|
||||
"account_type": "Temporary",
|
||||
"account_number": "1910"
|
||||
},
|
||||
"account_number": "1900"
|
||||
},
|
||||
"root_type": "Asset",
|
||||
"account_number": "1000"
|
||||
},
|
||||
_("Expenses"): {
|
||||
_("Direct Expenses"): {
|
||||
_("Stock Expenses"): {
|
||||
_("Cost of Goods Sold"): {
|
||||
"account_type": "Cost of Goods Sold",
|
||||
"account_number": "5111"
|
||||
},
|
||||
_("Expenses Included In Asset Valuation"): {
|
||||
"account_type": "Expenses Included In Asset Valuation",
|
||||
"account_number": "5112"
|
||||
},
|
||||
_("Expenses Included In Valuation"): {
|
||||
"account_type": "Expenses Included In Valuation",
|
||||
"account_number": "5118"
|
||||
},
|
||||
_("Stock Adjustment"): {
|
||||
"account_type": "Stock Adjustment",
|
||||
"account_number": "5119"
|
||||
},
|
||||
"account_number": "5110"
|
||||
},
|
||||
"account_number": "5100"
|
||||
},
|
||||
_("Indirect Expenses"): {
|
||||
_("Administrative Expenses"): {
|
||||
"account_number": "5201"
|
||||
},
|
||||
_("Commission on Sales"): {
|
||||
"account_number": "5202"
|
||||
},
|
||||
_("Depreciation"): {
|
||||
"account_type": "Depreciation",
|
||||
"account_number": "5203"
|
||||
},
|
||||
_("Entertainment Expenses"): {
|
||||
"account_number": "5204"
|
||||
},
|
||||
_("Freight and Forwarding Charges"): {
|
||||
"account_type": "Chargeable",
|
||||
"account_number": "5205"
|
||||
},
|
||||
_("Legal Expenses"): {
|
||||
"account_number": "5206"
|
||||
},
|
||||
_("Marketing Expenses"): {
|
||||
"account_type": "Chargeable",
|
||||
"account_number": "5207"
|
||||
},
|
||||
_("Office Maintenance Expenses"): {
|
||||
"account_number": "5208"
|
||||
},
|
||||
_("Office Rent"): {
|
||||
"account_number": "5209"
|
||||
},
|
||||
_("Postal Expenses"): {
|
||||
"account_number": "5210"
|
||||
},
|
||||
_("Print and Stationery"): {
|
||||
"account_number": "5211"
|
||||
},
|
||||
_("Round Off"): {
|
||||
"account_type": "Round Off",
|
||||
"account_number": "5212"
|
||||
},
|
||||
_("Salary"): {
|
||||
"account_number": "5213"
|
||||
},
|
||||
_("Sales Expenses"): {
|
||||
"account_number": "5214"
|
||||
},
|
||||
_("Telephone Expenses"): {
|
||||
"account_number": "5215"
|
||||
},
|
||||
_("Travel Expenses"): {
|
||||
"account_number": "5216"
|
||||
},
|
||||
_("Utility Expenses"): {
|
||||
"account_number": "5217"
|
||||
},
|
||||
_("Write Off"): {
|
||||
"account_number": "5218"
|
||||
},
|
||||
_("Exchange Gain/Loss"): {
|
||||
"account_number": "5219"
|
||||
},
|
||||
_("Gain/Loss on Asset Disposal"): {
|
||||
"account_number": "5220"
|
||||
},
|
||||
_("Miscellaneous Expenses"): {
|
||||
"account_type": "Chargeable",
|
||||
"account_number": "5221"
|
||||
},
|
||||
"account_number": "5200"
|
||||
},
|
||||
"root_type": "Expense",
|
||||
"account_number": "5000"
|
||||
},
|
||||
_("Income"): {
|
||||
_("Direct Income"): {
|
||||
_("Sales"): {
|
||||
"account_number": "4110"
|
||||
},
|
||||
_("Service"): {
|
||||
"account_number": "4120"
|
||||
},
|
||||
"account_number": "4100"
|
||||
},
|
||||
_("Indirect Income"): {
|
||||
"is_group": 1,
|
||||
"account_number": "4200"
|
||||
},
|
||||
"root_type": "Income",
|
||||
"account_number": "4000"
|
||||
},
|
||||
_("Source of Funds (Liabilities)"): {
|
||||
_("Current Liabilities"): {
|
||||
_("Accounts Payable"): {
|
||||
_("Creditors"): {
|
||||
"account_type": "Payable",
|
||||
"account_number": "2110"
|
||||
},
|
||||
_("Payroll Payable"): {
|
||||
"account_number": "2120"
|
||||
},
|
||||
"account_number": "2100"
|
||||
},
|
||||
_("Stock Liabilities"): {
|
||||
_("Stock Received But Not Billed"): {
|
||||
"account_type": "Stock Received But Not Billed",
|
||||
"account_number": "2210"
|
||||
},
|
||||
_("Asset Received But Not Billed"): {
|
||||
"account_type": "Asset Received But Not Billed",
|
||||
"account_number": "2211"
|
||||
},
|
||||
"account_number": "2200"
|
||||
},
|
||||
_("Duties and Taxes"): {
|
||||
"account_type": "Tax",
|
||||
"is_group": 1,
|
||||
"account_number": "2300"
|
||||
},
|
||||
_("Loans (Liabilities)"): {
|
||||
_("Secured Loans"): {
|
||||
"account_number": "2410"
|
||||
},
|
||||
_("Unsecured Loans"): {
|
||||
"account_number": "2420"
|
||||
},
|
||||
_("Bank Overdraft Account"): {
|
||||
"account_number": "2430"
|
||||
},
|
||||
"account_number": "2400"
|
||||
},
|
||||
"account_number": "2100-2400"
|
||||
},
|
||||
"root_type": "Liability",
|
||||
"account_number": "2000"
|
||||
},
|
||||
_("Equity"): {
|
||||
_("Capital Stock"): {
|
||||
"account_type": "Equity",
|
||||
"account_number": "3100"
|
||||
},
|
||||
_("Dividends Paid"): {
|
||||
"account_type": "Equity",
|
||||
"account_number": "3200"
|
||||
},
|
||||
_("Opening Balance Equity"): {
|
||||
"account_type": "Equity",
|
||||
"account_number": "3300"
|
||||
},
|
||||
_("Retained Earnings"): {
|
||||
"account_type": "Equity",
|
||||
"account_number": "3400"
|
||||
},
|
||||
"root_type": "Equity",
|
||||
"account_number": "3000"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
|
||||
import frappe
|
||||
|
||||
from erpnext.accounts.doctype.account.account import merge_account, update_account_number
|
||||
from erpnext.stock import get_company_default_inventory_account, get_warehouse_account
|
||||
|
||||
from erpnext.stock import get_warehouse_account, get_company_default_inventory_account
|
||||
from erpnext.accounts.doctype.account.account import update_account_number
|
||||
from erpnext.accounts.doctype.account.account import merge_account
|
||||
|
||||
class TestAccount(unittest.TestCase):
|
||||
def test_rename_account(self):
|
||||
@@ -20,9 +18,8 @@ class TestAccount(unittest.TestCase):
|
||||
acc.company = "_Test Company"
|
||||
acc.insert()
|
||||
|
||||
account_number, account_name = frappe.db.get_value(
|
||||
"Account", "1210 - Debtors - _TC", ["account_number", "account_name"]
|
||||
)
|
||||
account_number, account_name = frappe.db.get_value("Account", "1210 - Debtors - _TC",
|
||||
["account_number", "account_name"])
|
||||
self.assertEqual(account_number, "1210")
|
||||
self.assertEqual(account_name, "Debtors")
|
||||
|
||||
@@ -31,12 +28,8 @@ class TestAccount(unittest.TestCase):
|
||||
|
||||
update_account_number("1210 - Debtors - _TC", new_account_name, new_account_number)
|
||||
|
||||
new_acc = frappe.db.get_value(
|
||||
"Account",
|
||||
"1211-11-4 - 6 - - Debtors 1 - Test - - _TC",
|
||||
["account_name", "account_number"],
|
||||
as_dict=1,
|
||||
)
|
||||
new_acc = frappe.db.get_value("Account", "1211-11-4 - 6 - - Debtors 1 - Test - - _TC",
|
||||
["account_name", "account_number"], as_dict=1)
|
||||
|
||||
self.assertEqual(new_acc.account_name, "Debtors 1 - Test -")
|
||||
self.assertEqual(new_acc.account_number, "1211-11-4 - 6 -")
|
||||
@@ -76,7 +69,6 @@ class TestAccount(unittest.TestCase):
|
||||
acc.account_name = "Accumulated Depreciation"
|
||||
acc.parent_account = "Fixed Assets - _TC"
|
||||
acc.company = "_Test Company"
|
||||
acc.account_type = "Accumulated Depreciation"
|
||||
acc.insert()
|
||||
|
||||
doc = frappe.get_doc("Account", "Securities and Deposits - _TC")
|
||||
@@ -84,9 +76,7 @@ class TestAccount(unittest.TestCase):
|
||||
|
||||
self.assertEqual(parent, "Securities and Deposits - _TC")
|
||||
|
||||
merge_account(
|
||||
"Securities and Deposits - _TC", "Cash In Hand - _TC", doc.is_group, doc.root_type, doc.company
|
||||
)
|
||||
merge_account("Securities and Deposits - _TC", "Cash In Hand - _TC", doc.is_group, doc.root_type, doc.company)
|
||||
parent = frappe.db.get_value("Account", "Earnest Money - _TC", "parent_account")
|
||||
|
||||
# Parent account of the child account changes after merging
|
||||
@@ -98,173 +88,29 @@ class TestAccount(unittest.TestCase):
|
||||
doc = frappe.get_doc("Account", "Current Assets - _TC")
|
||||
|
||||
# Raise error as is_group property doesn't match
|
||||
self.assertRaises(
|
||||
frappe.ValidationError,
|
||||
merge_account,
|
||||
"Current Assets - _TC",
|
||||
"Accumulated Depreciation - _TC",
|
||||
doc.is_group,
|
||||
doc.root_type,
|
||||
doc.company,
|
||||
)
|
||||
self.assertRaises(frappe.ValidationError, merge_account, "Current Assets - _TC",\
|
||||
"Accumulated Depreciation - _TC", doc.is_group, doc.root_type, doc.company)
|
||||
|
||||
doc = frappe.get_doc("Account", "Capital Stock - _TC")
|
||||
|
||||
# Raise error as root_type property doesn't match
|
||||
self.assertRaises(
|
||||
frappe.ValidationError,
|
||||
merge_account,
|
||||
"Capital Stock - _TC",
|
||||
"Softwares - _TC",
|
||||
doc.is_group,
|
||||
doc.root_type,
|
||||
doc.company,
|
||||
)
|
||||
self.assertRaises(frappe.ValidationError, merge_account, "Capital Stock - _TC",\
|
||||
"Softwares - _TC", doc.is_group, doc.root_type, doc.company)
|
||||
|
||||
def test_account_sync(self):
|
||||
frappe.local.flags.pop("ignore_root_company_validation", None)
|
||||
|
||||
del frappe.local.flags["ignore_root_company_validation"]
|
||||
acc = frappe.new_doc("Account")
|
||||
acc.account_name = "Test Sync Account"
|
||||
acc.parent_account = "Temporary Accounts - _TC3"
|
||||
acc.company = "_Test Company 3"
|
||||
acc.insert()
|
||||
|
||||
acc_tc_4 = frappe.db.get_value(
|
||||
"Account", {"account_name": "Test Sync Account", "company": "_Test Company 4"}
|
||||
)
|
||||
acc_tc_5 = frappe.db.get_value(
|
||||
"Account", {"account_name": "Test Sync Account", "company": "_Test Company 5"}
|
||||
)
|
||||
acc_tc_4 = frappe.db.get_value('Account', {'account_name': "Test Sync Account", "company": "_Test Company 4"})
|
||||
acc_tc_5 = frappe.db.get_value('Account', {'account_name': "Test Sync Account", "company": "_Test Company 5"})
|
||||
self.assertEqual(acc_tc_4, "Test Sync Account - _TC4")
|
||||
self.assertEqual(acc_tc_5, "Test Sync Account - _TC5")
|
||||
|
||||
def test_add_account_to_a_group(self):
|
||||
frappe.db.set_value("Account", "Office Rent - _TC3", "is_group", 1)
|
||||
|
||||
acc = frappe.new_doc("Account")
|
||||
acc.account_name = "Test Group Account"
|
||||
acc.parent_account = "Office Rent - _TC3"
|
||||
acc.company = "_Test Company 3"
|
||||
self.assertRaises(frappe.ValidationError, acc.insert)
|
||||
|
||||
frappe.db.set_value("Account", "Office Rent - _TC3", "is_group", 0)
|
||||
|
||||
def test_account_rename_sync(self):
|
||||
frappe.local.flags.pop("ignore_root_company_validation", None)
|
||||
|
||||
acc = frappe.new_doc("Account")
|
||||
acc.account_name = "Test Rename Account"
|
||||
acc.parent_account = "Temporary Accounts - _TC3"
|
||||
acc.company = "_Test Company 3"
|
||||
acc.insert()
|
||||
|
||||
# Rename account in parent company
|
||||
update_account_number(acc.name, "Test Rename Sync Account", "1234")
|
||||
|
||||
# Check if renamed in children
|
||||
self.assertTrue(
|
||||
frappe.db.exists(
|
||||
"Account",
|
||||
{
|
||||
"account_name": "Test Rename Sync Account",
|
||||
"company": "_Test Company 4",
|
||||
"account_number": "1234",
|
||||
},
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
frappe.db.exists(
|
||||
"Account",
|
||||
{
|
||||
"account_name": "Test Rename Sync Account",
|
||||
"company": "_Test Company 5",
|
||||
"account_number": "1234",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
frappe.delete_doc("Account", "1234 - Test Rename Sync Account - _TC3")
|
||||
frappe.delete_doc("Account", "1234 - Test Rename Sync Account - _TC4")
|
||||
frappe.delete_doc("Account", "1234 - Test Rename Sync Account - _TC5")
|
||||
|
||||
def test_child_company_account_rename_sync(self):
|
||||
frappe.local.flags.pop("ignore_root_company_validation", None)
|
||||
|
||||
acc = frappe.new_doc("Account")
|
||||
acc.account_name = "Test Group Account"
|
||||
acc.parent_account = "Temporary Accounts - _TC3"
|
||||
acc.is_group = 1
|
||||
acc.company = "_Test Company 3"
|
||||
acc.insert()
|
||||
|
||||
self.assertTrue(
|
||||
frappe.db.exists(
|
||||
"Account", {"account_name": "Test Group Account", "company": "_Test Company 4"}
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
frappe.db.exists(
|
||||
"Account", {"account_name": "Test Group Account", "company": "_Test Company 5"}
|
||||
)
|
||||
)
|
||||
|
||||
# Try renaming child company account
|
||||
acc_tc_5 = frappe.db.get_value(
|
||||
"Account", {"account_name": "Test Group Account", "company": "_Test Company 5"}
|
||||
)
|
||||
self.assertRaises(
|
||||
frappe.ValidationError, update_account_number, acc_tc_5, "Test Modified Account"
|
||||
)
|
||||
|
||||
# Rename child company account with allow_account_creation_against_child_company enabled
|
||||
frappe.db.set_value(
|
||||
"Company", "_Test Company 5", "allow_account_creation_against_child_company", 1
|
||||
)
|
||||
|
||||
update_account_number(acc_tc_5, "Test Modified Account")
|
||||
self.assertTrue(
|
||||
frappe.db.exists(
|
||||
"Account", {"name": "Test Modified Account - _TC5", "company": "_Test Company 5"}
|
||||
)
|
||||
)
|
||||
|
||||
frappe.db.set_value(
|
||||
"Company", "_Test Company 5", "allow_account_creation_against_child_company", 0
|
||||
)
|
||||
|
||||
to_delete = [
|
||||
"Test Group Account - _TC3",
|
||||
"Test Group Account - _TC4",
|
||||
"Test Modified Account - _TC5",
|
||||
]
|
||||
for doc in to_delete:
|
||||
frappe.delete_doc("Account", doc)
|
||||
|
||||
def test_validate_account_currency(self):
|
||||
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
|
||||
|
||||
if not frappe.db.get_value("Account", "Test Currency Account - _TC"):
|
||||
acc = frappe.new_doc("Account")
|
||||
acc.account_name = "Test Currency Account"
|
||||
acc.parent_account = "Tax Assets - _TC"
|
||||
acc.company = "_Test Company"
|
||||
acc.insert()
|
||||
else:
|
||||
acc = frappe.get_doc("Account", "Test Currency Account - _TC")
|
||||
|
||||
self.assertEqual(acc.account_currency, "INR")
|
||||
|
||||
# Make a JV against this account
|
||||
make_journal_entry(
|
||||
"Test Currency Account - _TC", "Miscellaneous Expenses - _TC", 100, submit=True
|
||||
)
|
||||
|
||||
acc.account_currency = "USD"
|
||||
self.assertRaises(frappe.ValidationError, acc.save)
|
||||
|
||||
|
||||
def _make_test_records(verbose=None):
|
||||
def _make_test_records(verbose):
|
||||
from frappe.test_runner import make_test_objects
|
||||
|
||||
accounts = [
|
||||
@@ -273,16 +119,20 @@ def _make_test_records(verbose=None):
|
||||
["_Test Bank USD", "Bank Accounts", 0, "Bank", "USD"],
|
||||
["_Test Bank EUR", "Bank Accounts", 0, "Bank", "EUR"],
|
||||
["_Test Cash", "Cash In Hand", 0, "Cash", None],
|
||||
|
||||
["_Test Account Stock Expenses", "Direct Expenses", 1, None, None],
|
||||
["_Test Account Shipping Charges", "_Test Account Stock Expenses", 0, "Chargeable", None],
|
||||
["_Test Account Customs Duty", "_Test Account Stock Expenses", 0, "Tax", None],
|
||||
["_Test Account Insurance Charges", "_Test Account Stock Expenses", 0, "Chargeable", None],
|
||||
["_Test Account Stock Adjustment", "_Test Account Stock Expenses", 0, "Stock Adjustment", None],
|
||||
["_Test Employee Advance", "Current Liabilities", 0, None, None],
|
||||
|
||||
["_Test Account Tax Assets", "Current Assets", 1, None, None],
|
||||
["_Test Account VAT", "_Test Account Tax Assets", 0, "Tax", None],
|
||||
["_Test Account Service Tax", "_Test Account Tax Assets", 0, "Tax", None],
|
||||
|
||||
["_Test Account Reserves and Surplus", "Current Liabilities", 0, None, None],
|
||||
|
||||
["_Test Account Cost for Goods Sold", "Expenses", 0, None, None],
|
||||
["_Test Account Excise Duty", "_Test Account Tax Assets", 0, "Tax", None],
|
||||
["_Test Account Education Cess", "_Test Account Tax Assets", 0, "Tax", None],
|
||||
@@ -291,45 +141,36 @@ def _make_test_records(verbose=None):
|
||||
["_Test Account Discount", "Direct Expenses", 0, None, None],
|
||||
["_Test Write Off", "Indirect Expenses", 0, None, None],
|
||||
["_Test Exchange Gain/Loss", "Indirect Expenses", 0, None, None],
|
||||
["_Test Account Sales", "Direct Income", 0, None, None],
|
||||
|
||||
# related to Account Inventory Integration
|
||||
["_Test Account Stock In Hand", "Current Assets", 0, None, None],
|
||||
|
||||
# fixed asset depreciation
|
||||
["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None],
|
||||
["_Test Accumulated Depreciations", "Current Assets", 0, "Accumulated Depreciation", None],
|
||||
["_Test Accumulated Depreciations", "Current Assets", 0, None, None],
|
||||
["_Test Depreciations", "Expenses", 0, None, None],
|
||||
["_Test Gain/Loss on Asset Disposal", "Expenses", 0, None, None],
|
||||
|
||||
# Receivable / Payable Account
|
||||
["_Test Receivable", "Current Assets", 0, "Receivable", None],
|
||||
["_Test Payable", "Current Liabilities", 0, "Payable", None],
|
||||
["_Test Receivable USD", "Current Assets", 0, "Receivable", "USD"],
|
||||
["_Test Payable USD", "Current Liabilities", 0, "Payable", "USD"],
|
||||
["_Test Payable USD", "Current Liabilities", 0, "Payable", "USD"]
|
||||
]
|
||||
|
||||
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,
|
||||
"parent_account": parent_account + " - " + abbr,
|
||||
"company": company,
|
||||
"is_group": is_group,
|
||||
"account_type": account_type,
|
||||
"account_currency": currency,
|
||||
}
|
||||
for account_name, parent_account, is_group, account_type, currency in accounts
|
||||
],
|
||||
)
|
||||
for company, abbr in [["_Test Company", "_TC"], ["_Test Company 1", "_TC1"]]:
|
||||
test_objects = make_test_objects("Account", [{
|
||||
"doctype": "Account",
|
||||
"account_name": account_name,
|
||||
"parent_account": parent_account + " - " + abbr,
|
||||
"company": company,
|
||||
"is_group": is_group,
|
||||
"account_type": account_type,
|
||||
"account_currency": currency
|
||||
} for account_name, parent_account, is_group, account_type, currency in accounts])
|
||||
|
||||
return test_objects
|
||||
|
||||
|
||||
def get_inventory_account(company, warehouse=None):
|
||||
account = None
|
||||
if warehouse:
|
||||
@@ -339,24 +180,18 @@ def get_inventory_account(company, warehouse=None):
|
||||
|
||||
return account
|
||||
|
||||
|
||||
def create_account(**kwargs):
|
||||
account = frappe.db.get_value(
|
||||
"Account", filters={"account_name": kwargs.get("account_name"), "company": kwargs.get("company")}
|
||||
)
|
||||
account = frappe.db.get_value("Account", filters={"account_name": kwargs.get("account_name"), "company": kwargs.get("company")})
|
||||
if account:
|
||||
return account
|
||||
else:
|
||||
account = frappe.get_doc(
|
||||
dict(
|
||||
doctype="Account",
|
||||
account_name=kwargs.get("account_name"),
|
||||
account_type=kwargs.get("account_type"),
|
||||
parent_account=kwargs.get("parent_account"),
|
||||
company=kwargs.get("company"),
|
||||
account_currency=kwargs.get("account_currency"),
|
||||
)
|
||||
)
|
||||
account = frappe.get_doc(dict(
|
||||
doctype = "Account",
|
||||
account_name = kwargs.get('account_name'),
|
||||
account_type = kwargs.get('account_type'),
|
||||
parent_account = kwargs.get('parent_account'),
|
||||
company = kwargs.get('company')
|
||||
))
|
||||
|
||||
account.save()
|
||||
return account.name
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Account Subtype', {
|
||||
refresh: function() {
|
||||
|
||||
}
|
||||
});
|
||||
134
erpnext/accounts/doctype/account_subtype/account_subtype.json
Normal file
134
erpnext/accounts/doctype/account_subtype/account_subtype.json
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:account_subtype",
|
||||
"beta": 0,
|
||||
"creation": "2018-10-25 15:46:08.054586",
|
||||
"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": "account_subtype",
|
||||
"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": "Account Subtype",
|
||||
"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-10-25 15:47:03.841390",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account Subtype",
|
||||
"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,
|
||||
"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,
|
||||
"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,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class AccountSubtype(Document):
|
||||
pass
|
||||
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Account Subtype", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Account Subtype
|
||||
() => frappe.tests.make('Account Subtype', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
class TestAccountSubtype(unittest.TestCase):
|
||||
pass
|
||||
8
erpnext/accounts/doctype/account_type/account_type.js
Normal file
8
erpnext/accounts/doctype/account_type/account_type.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Account Type', {
|
||||
refresh: function() {
|
||||
|
||||
}
|
||||
});
|
||||
134
erpnext/accounts/doctype/account_type/account_type.json
Normal file
134
erpnext/accounts/doctype/account_type/account_type.json
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:account_type",
|
||||
"beta": 0,
|
||||
"creation": "2018-10-25 15:45:45.789963",
|
||||
"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": "account_type",
|
||||
"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": "Account Type",
|
||||
"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-10-25 15:46:51.042604",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account Type",
|
||||
"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,
|
||||
"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,
|
||||
"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,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
9
erpnext/accounts/doctype/account_type/account_type.py
Normal file
9
erpnext/accounts/doctype/account_type/account_type.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class AccountType(Document):
|
||||
pass
|
||||
23
erpnext/accounts/doctype/account_type/test_account_type.js
Normal file
23
erpnext/accounts/doctype/account_type/test_account_type.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Account Type", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Account Type
|
||||
() => frappe.tests.make('Account Type', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
class TestAccountType(unittest.TestCase):
|
||||
pass
|
||||
@@ -1,63 +0,0 @@
|
||||
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Accounting Dimension', {
|
||||
refresh: function(frm) {
|
||||
frm.set_query('document_type', () => {
|
||||
let invalid_doctypes = frappe.model.core_doctypes_list;
|
||||
invalid_doctypes.push('Accounting Dimension', 'Project',
|
||||
'Cost Center', 'Accounting Dimension Detail', 'Company');
|
||||
|
||||
return {
|
||||
filters: {
|
||||
name: ['not in', invalid_doctypes]
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
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));
|
||||
|
||||
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");
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
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,86 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "field:label",
|
||||
"creation": "2019-05-04 18:13:37.002352",
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"document_type",
|
||||
"label",
|
||||
"fieldname",
|
||||
"dimension_defaults",
|
||||
"disabled"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "label",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Dimension Name",
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "fieldname",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Fieldname"
|
||||
},
|
||||
{
|
||||
"fieldname": "document_type",
|
||||
"fieldtype": "Link",
|
||||
"label": "Reference Document Type",
|
||||
"options": "DocType",
|
||||
"read_only_depends_on": "eval:!doc.__islocal",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "disabled",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"label": "Disable",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "dimension_defaults",
|
||||
"fieldtype": "Table",
|
||||
"label": "Dimension Defaults",
|
||||
"options": "Accounting Dimension Detail"
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2021-02-08 16:37:53.936656",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounting Dimension",
|
||||
"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 Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -1,285 +0,0 @@
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
|
||||
import json
|
||||
|
||||
import frappe
|
||||
from frappe import _, scrub
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
from frappe.model import core_doctypes_list
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import cstr
|
||||
|
||||
|
||||
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",
|
||||
"Company",
|
||||
"Account",
|
||||
):
|
||||
|
||||
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"))
|
||||
|
||||
if not self.is_new():
|
||||
self.validate_document_type_change()
|
||||
|
||||
def validate_document_type_change(self):
|
||||
doctype_before_save = frappe.db.get_value("Accounting Dimension", self.name, "document_type")
|
||||
if doctype_before_save != self.document_type:
|
||||
message = _("Cannot change Reference Document Type.")
|
||||
message += _("Please create a new Accounting Dimension if required.")
|
||||
frappe.throw(message)
|
||||
|
||||
def after_insert(self):
|
||||
if frappe.flags.in_test:
|
||||
make_dimension_in_accounting_doctypes(doc=self)
|
||||
else:
|
||||
frappe.enqueue(make_dimension_in_accounting_doctypes, doc=self, queue="long")
|
||||
|
||||
def on_trash(self):
|
||||
if frappe.flags.in_test:
|
||||
delete_accounting_dimension(doc=self)
|
||||
else:
|
||||
frappe.enqueue(delete_accounting_dimension, doc=self, queue="long")
|
||||
|
||||
def set_fieldname_and_label(self):
|
||||
if not self.label:
|
||||
self.label = cstr(self.document_type)
|
||||
|
||||
if not self.fieldname:
|
||||
self.fieldname = scrub(self.label)
|
||||
|
||||
def on_update(self):
|
||||
frappe.flags.accounting_dimensions = None
|
||||
|
||||
|
||||
def make_dimension_in_accounting_doctypes(doc, doclist=None):
|
||||
if not doclist:
|
||||
doclist = get_doctypes_with_dimensions()
|
||||
|
||||
doc_count = len(get_accounting_dimensions())
|
||||
count = 0
|
||||
|
||||
for doctype in doclist:
|
||||
|
||||
if (doc_count + 1) % 2 == 0:
|
||||
insert_after_field = "dimension_col_break"
|
||||
else:
|
||||
insert_after_field = "accounting_dimensions_section"
|
||||
|
||||
df = {
|
||||
"fieldname": doc.fieldname,
|
||||
"label": doc.label,
|
||||
"fieldtype": "Link",
|
||||
"options": doc.document_type,
|
||||
"insert_after": insert_after_field,
|
||||
"owner": "Administrator",
|
||||
}
|
||||
|
||||
meta = frappe.get_meta(doctype, cached=False)
|
||||
fieldnames = [d.fieldname for d in meta.get("fields")]
|
||||
|
||||
if df["fieldname"] not in fieldnames:
|
||||
if doctype == "Budget":
|
||||
add_dimension_to_budget_doctype(df.copy(), doc)
|
||||
else:
|
||||
create_custom_field(doctype, df, ignore_validate=True)
|
||||
|
||||
count += 1
|
||||
|
||||
frappe.publish_progress(count * 100 / len(doclist), title=_("Creating Dimensions..."))
|
||||
frappe.clear_cache(doctype=doctype)
|
||||
|
||||
|
||||
def add_dimension_to_budget_doctype(df, doc):
|
||||
df.update(
|
||||
{
|
||||
"insert_after": "cost_center",
|
||||
"depends_on": "eval:doc.budget_against == '{0}'".format(doc.document_type),
|
||||
}
|
||||
)
|
||||
|
||||
create_custom_field("Budget", df, ignore_validate=True)
|
||||
|
||||
property_setter = frappe.db.exists("Property Setter", "Budget-budget_against-options")
|
||||
|
||||
if property_setter:
|
||||
property_setter_doc = frappe.get_doc("Property Setter", "Budget-budget_against-options")
|
||||
property_setter_doc.value = property_setter_doc.value + "\n" + doc.document_type
|
||||
property_setter_doc.save()
|
||||
|
||||
frappe.clear_cache(doctype="Budget")
|
||||
else:
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Property Setter",
|
||||
"doctype_or_field": "DocField",
|
||||
"doc_type": "Budget",
|
||||
"field_name": "budget_against",
|
||||
"property": "options",
|
||||
"property_type": "Text",
|
||||
"value": "\nCost Center\nProject\n" + doc.document_type,
|
||||
}
|
||||
).insert(ignore_permissions=True)
|
||||
|
||||
|
||||
def delete_accounting_dimension(doc):
|
||||
doclist = get_doctypes_with_dimensions()
|
||||
|
||||
frappe.db.sql(
|
||||
"""
|
||||
DELETE FROM `tabCustom Field`
|
||||
WHERE fieldname = %s
|
||||
AND dt IN (%s)"""
|
||||
% ("%s", ", ".join(["%s"] * len(doclist))), # nosec
|
||||
tuple([doc.fieldname] + doclist),
|
||||
)
|
||||
|
||||
frappe.db.sql(
|
||||
"""
|
||||
DELETE FROM `tabProperty Setter`
|
||||
WHERE field_name = %s
|
||||
AND doc_type IN (%s)"""
|
||||
% ("%s", ", ".join(["%s"] * len(doclist))), # nosec
|
||||
tuple([doc.fieldname] + doclist),
|
||||
)
|
||||
|
||||
budget_against_property = frappe.get_doc("Property Setter", "Budget-budget_against-options")
|
||||
value_list = budget_against_property.value.split("\n")[3:]
|
||||
|
||||
if doc.document_type in value_list:
|
||||
value_list.remove(doc.document_type)
|
||||
|
||||
budget_against_property.value = "\nCost Center\nProject\n" + "\n".join(value_list)
|
||||
budget_against_property.save()
|
||||
|
||||
for doctype in doclist:
|
||||
frappe.clear_cache(doctype=doctype)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def disable_dimension(doc):
|
||||
if frappe.flags.in_test:
|
||||
toggle_disabling(doc=doc)
|
||||
else:
|
||||
frappe.enqueue(toggle_disabling, doc=doc)
|
||||
|
||||
|
||||
def toggle_disabling(doc):
|
||||
doc = json.loads(doc)
|
||||
|
||||
if doc.get("disabled"):
|
||||
df = {"read_only": 1}
|
||||
else:
|
||||
df = {"read_only": 0}
|
||||
|
||||
doclist = get_doctypes_with_dimensions()
|
||||
|
||||
for doctype in doclist:
|
||||
field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": doc.get("fieldname")})
|
||||
if field:
|
||||
custom_field = frappe.get_doc("Custom Field", field)
|
||||
custom_field.update(df)
|
||||
custom_field.save()
|
||||
|
||||
frappe.clear_cache(doctype=doctype)
|
||||
|
||||
|
||||
def get_doctypes_with_dimensions():
|
||||
return frappe.get_hooks("accounting_dimension_doctypes")
|
||||
|
||||
|
||||
def get_accounting_dimensions(as_list=True, filters=None):
|
||||
|
||||
if not filters:
|
||||
filters = {"disabled": 0}
|
||||
|
||||
if frappe.flags.accounting_dimensions is None:
|
||||
frappe.flags.accounting_dimensions = frappe.get_all(
|
||||
"Accounting Dimension",
|
||||
fields=["label", "fieldname", "disabled", "document_type"],
|
||||
filters=filters,
|
||||
)
|
||||
|
||||
if as_list:
|
||||
return [d.fieldname for d in frappe.flags.accounting_dimensions]
|
||||
else:
|
||||
return frappe.flags.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
|
||||
|
||||
|
||||
def get_dimension_with_children(doctype, dimensions):
|
||||
|
||||
if isinstance(dimensions, str):
|
||||
dimensions = [dimensions]
|
||||
|
||||
all_dimensions = []
|
||||
|
||||
for dimension in dimensions:
|
||||
lft, rgt = frappe.db.get_value(doctype, dimension, ["lft", "rgt"])
|
||||
children = frappe.get_all(
|
||||
doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]}, order_by="lft"
|
||||
)
|
||||
all_dimensions += [c.name for c in children]
|
||||
|
||||
return all_dimensions
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_dimensions(with_cost_center_and_project=False):
|
||||
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 p.fieldname, c.company, c.default_dimension
|
||||
FROM `tabAccounting Dimension Detail` c, `tabAccounting Dimension` p
|
||||
WHERE c.parent = p.name""",
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
if with_cost_center_and_project:
|
||||
dimension_filters.extend(
|
||||
[
|
||||
{"fieldname": "cost_center", "document_type": "Cost Center"},
|
||||
{"fieldname": "project", "document_type": "Project"},
|
||||
]
|
||||
)
|
||||
|
||||
default_dimensions_map = {}
|
||||
for dimension in default_dimensions:
|
||||
default_dimensions_map.setdefault(dimension.company, {})
|
||||
default_dimensions_map[dimension.company][dimension.fieldname] = dimension.default_dimension
|
||||
|
||||
return dimension_filters, default_dimensions_map
|
||||
@@ -1,131 +0,0 @@
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
import unittest
|
||||
|
||||
import frappe
|
||||
|
||||
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
|
||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||
|
||||
test_dependencies = ["Cost Center", "Location", "Warehouse", "Department"]
|
||||
|
||||
|
||||
class TestAccountingDimension(unittest.TestCase):
|
||||
def setUp(self):
|
||||
create_dimension()
|
||||
|
||||
def test_dimension_against_sales_invoice(self):
|
||||
si = create_sales_invoice(do_not_save=1)
|
||||
|
||||
si.location = "Block 1"
|
||||
si.append(
|
||||
"items",
|
||||
{
|
||||
"item_code": "_Test Item",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"qty": 1,
|
||||
"rate": 100,
|
||||
"income_account": "Sales - _TC",
|
||||
"expense_account": "Cost of Goods Sold - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"department": "_Test Department - _TC",
|
||||
"location": "Block 1",
|
||||
},
|
||||
)
|
||||
|
||||
si.save()
|
||||
si.submit()
|
||||
|
||||
gle = frappe.get_doc("GL Entry", {"voucher_no": si.name, "account": "Sales - _TC"})
|
||||
|
||||
self.assertEqual(gle.get("department"), "_Test Department - _TC")
|
||||
|
||||
def test_dimension_against_journal_entry(self):
|
||||
je = make_journal_entry("Sales - _TC", "Sales Expenses - _TC", 500, save=False)
|
||||
je.accounts[0].update({"department": "_Test Department - _TC"})
|
||||
je.accounts[1].update({"department": "_Test Department - _TC"})
|
||||
|
||||
je.accounts[0].update({"location": "Block 1"})
|
||||
je.accounts[1].update({"location": "Block 1"})
|
||||
|
||||
je.save()
|
||||
je.submit()
|
||||
|
||||
gle = frappe.get_doc("GL Entry", {"voucher_no": je.name, "account": "Sales - _TC"})
|
||||
gle1 = frappe.get_doc("GL Entry", {"voucher_no": je.name, "account": "Sales Expenses - _TC"})
|
||||
self.assertEqual(gle.get("department"), "_Test Department - _TC")
|
||||
self.assertEqual(gle1.get("department"), "_Test Department - _TC")
|
||||
|
||||
def test_mandatory(self):
|
||||
si = create_sales_invoice(do_not_save=1)
|
||||
si.append(
|
||||
"items",
|
||||
{
|
||||
"item_code": "_Test Item",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"qty": 1,
|
||||
"rate": 100,
|
||||
"income_account": "Sales - _TC",
|
||||
"expense_account": "Cost of Goods Sold - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"location": "",
|
||||
},
|
||||
)
|
||||
|
||||
si.save()
|
||||
self.assertRaises(frappe.ValidationError, si.submit)
|
||||
|
||||
def tearDown(self):
|
||||
disable_dimension()
|
||||
|
||||
|
||||
def create_dimension():
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
if not frappe.db.exists("Accounting Dimension", {"document_type": "Department"}):
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Accounting Dimension",
|
||||
"document_type": "Department",
|
||||
}
|
||||
).insert()
|
||||
else:
|
||||
dimension = frappe.get_doc("Accounting Dimension", "Department")
|
||||
dimension.disabled = 0
|
||||
dimension.save()
|
||||
|
||||
if not frappe.db.exists("Accounting Dimension", {"document_type": "Location"}):
|
||||
dimension1 = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Accounting Dimension",
|
||||
"document_type": "Location",
|
||||
}
|
||||
)
|
||||
|
||||
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.save()
|
||||
|
||||
|
||||
def disable_dimension():
|
||||
dimension1 = frappe.get_doc("Accounting Dimension", "Department")
|
||||
dimension1.disabled = 1
|
||||
dimension1.save()
|
||||
|
||||
dimension2 = frappe.get_doc("Accounting Dimension", "Location")
|
||||
dimension2.disabled = 1
|
||||
dimension2.save()
|
||||
@@ -1,65 +0,0 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class AccountingDimensionDetail(Document):
|
||||
pass
|
||||
@@ -1,82 +0,0 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Accounting Dimension Filter', {
|
||||
refresh: function(frm, cdt, cdn) {
|
||||
if (frm.doc.accounting_dimension) {
|
||||
frm.set_df_property('dimensions', 'label', frm.doc.accounting_dimension, cdn, 'dimension_value');
|
||||
}
|
||||
|
||||
let help_content =
|
||||
`<table class="table table-bordered" style="background-color: var(--scrollbar-track-color);">
|
||||
<tr><td>
|
||||
<p>
|
||||
<i class="fa fa-hand-right"></i>
|
||||
{{__('Note: On checking Is Mandatory the accounting dimension will become mandatory against that specific account for all accounting transactions')}}
|
||||
</p>
|
||||
</td></tr>
|
||||
</table>`;
|
||||
|
||||
frm.set_df_property('dimension_filter_help', 'options', help_content);
|
||||
},
|
||||
onload: function(frm) {
|
||||
frm.set_query('applicable_on_account', 'accounts', function() {
|
||||
return {
|
||||
filters: {
|
||||
'company': frm.doc.company
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
frappe.db.get_list('Accounting Dimension',
|
||||
{fields: ['document_type']}).then((res) => {
|
||||
let options = ['Cost Center', 'Project'];
|
||||
|
||||
res.forEach((dimension) => {
|
||||
options.push(dimension.document_type);
|
||||
});
|
||||
|
||||
frm.set_df_property('accounting_dimension', 'options', options);
|
||||
});
|
||||
|
||||
frm.trigger('setup_filters');
|
||||
},
|
||||
|
||||
setup_filters: function(frm) {
|
||||
let filters = {};
|
||||
|
||||
if (frm.doc.accounting_dimension) {
|
||||
frappe.model.with_doctype(frm.doc.accounting_dimension, function() {
|
||||
if (frappe.model.is_tree(frm.doc.accounting_dimension)) {
|
||||
filters['is_group'] = 0;
|
||||
}
|
||||
|
||||
if (frappe.meta.has_field(frm.doc.accounting_dimension, 'company')) {
|
||||
filters['company'] = frm.doc.company;
|
||||
}
|
||||
|
||||
frm.set_query('dimension_value', 'dimensions', function() {
|
||||
return {
|
||||
filters: filters
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
accounting_dimension: function(frm) {
|
||||
frm.clear_table("dimensions");
|
||||
let row = frm.add_child("dimensions");
|
||||
row.accounting_dimension = frm.doc.accounting_dimension;
|
||||
frm.refresh_field("dimensions");
|
||||
frm.trigger('setup_filters');
|
||||
},
|
||||
});
|
||||
|
||||
frappe.ui.form.on('Allowed Dimension', {
|
||||
dimensions_add: function(frm, cdt, cdn) {
|
||||
let row = locals[cdt][cdn];
|
||||
row.accounting_dimension = frm.doc.accounting_dimension;
|
||||
frm.refresh_field("dimensions");
|
||||
}
|
||||
});
|
||||
@@ -1,158 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "format:{accounting_dimension}-{#####}",
|
||||
"creation": "2020-11-08 18:28:11.906146",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"accounting_dimension",
|
||||
"disabled",
|
||||
"column_break_2",
|
||||
"company",
|
||||
"allow_or_restrict",
|
||||
"section_break_4",
|
||||
"accounts",
|
||||
"column_break_6",
|
||||
"dimensions",
|
||||
"section_break_10",
|
||||
"dimension_filter_help"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "accounting_dimension",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Accounting Dimension",
|
||||
"reqd": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_4",
|
||||
"fieldtype": "Section Break",
|
||||
"hide_border": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_6",
|
||||
"fieldtype": "Column Break",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "allow_or_restrict",
|
||||
"fieldtype": "Select",
|
||||
"label": "Allow Or Restrict Dimension",
|
||||
"options": "Allow\nRestrict",
|
||||
"reqd": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "accounts",
|
||||
"fieldtype": "Table",
|
||||
"label": "Applicable On Account",
|
||||
"options": "Applicable On Account",
|
||||
"reqd": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.accounting_dimension",
|
||||
"fieldname": "dimensions",
|
||||
"fieldtype": "Table",
|
||||
"label": "Applicable Dimension",
|
||||
"options": "Allowed Dimension",
|
||||
"reqd": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "disabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Disabled",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "dimension_filter_help",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Dimension Filter Help",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_10",
|
||||
"fieldtype": "Section Break",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-02-03 12:04:58.678402",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounting Dimension Filter",
|
||||
"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": "Accounts Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
# Copyright, (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
|
||||
import frappe
|
||||
from frappe import _, scrub
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class AccountingDimensionFilter(Document):
|
||||
def validate(self):
|
||||
self.validate_applicable_accounts()
|
||||
|
||||
def validate_applicable_accounts(self):
|
||||
accounts = frappe.db.sql(
|
||||
"""
|
||||
SELECT a.applicable_on_account as account
|
||||
FROM `tabApplicable On Account` a, `tabAccounting Dimension Filter` d
|
||||
WHERE d.name = a.parent
|
||||
and d.name != %s
|
||||
and d.accounting_dimension = %s
|
||||
""",
|
||||
(self.name, self.accounting_dimension),
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
account_list = [d.account for d in accounts]
|
||||
|
||||
for account in self.get("accounts"):
|
||||
if account.applicable_on_account in account_list:
|
||||
frappe.throw(
|
||||
_("Row {0}: {1} account already applied for Accounting Dimension {2}").format(
|
||||
account.idx,
|
||||
frappe.bold(account.applicable_on_account),
|
||||
frappe.bold(self.accounting_dimension),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def get_dimension_filter_map():
|
||||
filters = frappe.db.sql(
|
||||
"""
|
||||
SELECT
|
||||
a.applicable_on_account, d.dimension_value, p.accounting_dimension,
|
||||
p.allow_or_restrict, a.is_mandatory
|
||||
FROM
|
||||
`tabApplicable On Account` a, `tabAllowed Dimension` d,
|
||||
`tabAccounting Dimension Filter` p
|
||||
WHERE
|
||||
p.name = a.parent
|
||||
AND p.disabled = 0
|
||||
AND p.name = d.parent
|
||||
""",
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
dimension_filter_map = {}
|
||||
|
||||
for f in filters:
|
||||
f.fieldname = scrub(f.accounting_dimension)
|
||||
|
||||
build_map(
|
||||
dimension_filter_map,
|
||||
f.fieldname,
|
||||
f.applicable_on_account,
|
||||
f.dimension_value,
|
||||
f.allow_or_restrict,
|
||||
f.is_mandatory,
|
||||
)
|
||||
|
||||
return dimension_filter_map
|
||||
|
||||
|
||||
def build_map(map_object, dimension, account, filter_value, allow_or_restrict, is_mandatory):
|
||||
map_object.setdefault(
|
||||
(dimension, account),
|
||||
{"allowed_dimensions": [], "is_mandatory": is_mandatory, "allow_or_restrict": allow_or_restrict},
|
||||
)
|
||||
map_object[(dimension, account)]["allowed_dimensions"].append(filter_value)
|
||||
@@ -1,106 +0,0 @@
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
import unittest
|
||||
|
||||
import frappe
|
||||
|
||||
from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import (
|
||||
create_dimension,
|
||||
disable_dimension,
|
||||
)
|
||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||
from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
|
||||
|
||||
test_dependencies = ["Location", "Cost Center", "Department"]
|
||||
|
||||
|
||||
class TestAccountingDimensionFilter(unittest.TestCase):
|
||||
def setUp(self):
|
||||
create_dimension()
|
||||
create_accounting_dimension_filter()
|
||||
self.invoice_list = []
|
||||
|
||||
def test_allowed_dimension_validation(self):
|
||||
si = create_sales_invoice(do_not_save=1)
|
||||
si.items[0].cost_center = "Main - _TC"
|
||||
si.department = "Accounts - _TC"
|
||||
si.location = "Block 1"
|
||||
si.save()
|
||||
|
||||
self.assertRaises(InvalidAccountDimensionError, si.submit)
|
||||
self.invoice_list.append(si)
|
||||
|
||||
def test_mandatory_dimension_validation(self):
|
||||
si = create_sales_invoice(do_not_save=1)
|
||||
si.department = ""
|
||||
si.location = "Block 1"
|
||||
|
||||
# Test with no department for Sales Account
|
||||
si.items[0].department = ""
|
||||
si.items[0].cost_center = "_Test Cost Center 2 - _TC"
|
||||
si.save()
|
||||
|
||||
self.assertRaises(MandatoryAccountDimensionError, si.submit)
|
||||
self.invoice_list.append(si)
|
||||
|
||||
def tearDown(self):
|
||||
disable_dimension_filter()
|
||||
disable_dimension()
|
||||
|
||||
for si in self.invoice_list:
|
||||
si.load_from_db()
|
||||
if si.docstatus == 1:
|
||||
si.cancel()
|
||||
|
||||
|
||||
def create_accounting_dimension_filter():
|
||||
if not frappe.db.get_value(
|
||||
"Accounting Dimension Filter", {"accounting_dimension": "Cost Center"}
|
||||
):
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Accounting Dimension Filter",
|
||||
"accounting_dimension": "Cost Center",
|
||||
"allow_or_restrict": "Allow",
|
||||
"company": "_Test Company",
|
||||
"accounts": [
|
||||
{
|
||||
"applicable_on_account": "Sales - _TC",
|
||||
}
|
||||
],
|
||||
"dimensions": [
|
||||
{"accounting_dimension": "Cost Center", "dimension_value": "_Test Cost Center 2 - _TC"}
|
||||
],
|
||||
}
|
||||
).insert()
|
||||
else:
|
||||
doc = frappe.get_doc("Accounting Dimension Filter", {"accounting_dimension": "Cost Center"})
|
||||
doc.disabled = 0
|
||||
doc.save()
|
||||
|
||||
if not frappe.db.get_value("Accounting Dimension Filter", {"accounting_dimension": "Department"}):
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Accounting Dimension Filter",
|
||||
"accounting_dimension": "Department",
|
||||
"allow_or_restrict": "Allow",
|
||||
"company": "_Test Company",
|
||||
"accounts": [{"applicable_on_account": "Sales - _TC", "is_mandatory": 1}],
|
||||
"dimensions": [{"accounting_dimension": "Department", "dimension_value": "Accounts - _TC"}],
|
||||
}
|
||||
).insert()
|
||||
else:
|
||||
doc = frappe.get_doc("Accounting Dimension Filter", {"accounting_dimension": "Department"})
|
||||
doc.disabled = 0
|
||||
doc.save()
|
||||
|
||||
|
||||
def disable_dimension_filter():
|
||||
doc = frappe.get_doc("Accounting Dimension Filter", {"accounting_dimension": "Cost Center"})
|
||||
doc.disabled = 1
|
||||
doc.save()
|
||||
|
||||
doc = frappe.get_doc("Accounting Dimension Filter", {"accounting_dimension": "Department"})
|
||||
doc.disabled = 1
|
||||
doc.save()
|
||||
@@ -1,15 +1,13 @@
|
||||
# -*- 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 import _
|
||||
|
||||
|
||||
class OverlapError(frappe.ValidationError):
|
||||
pass
|
||||
|
||||
class OverlapError(frappe.ValidationError): pass
|
||||
|
||||
class AccountingPeriod(Document):
|
||||
def validate(self):
|
||||
@@ -19,12 +17,11 @@ class AccountingPeriod(Document):
|
||||
self.bootstrap_doctypes_for_closing()
|
||||
|
||||
def autoname(self):
|
||||
company_abbr = frappe.get_cached_value("Company", self.company, "abbr")
|
||||
company_abbr = frappe.get_cached_value('Company', self.company, "abbr")
|
||||
self.name = " - ".join([self.period_name, company_abbr])
|
||||
|
||||
def validate_overlap(self):
|
||||
existing_accounting_period = frappe.db.sql(
|
||||
"""select name from `tabAccounting Period`
|
||||
existing_accounting_period = frappe.db.sql("""select name from `tabAccounting Period`
|
||||
where (
|
||||
(%(start_date)s between start_date and end_date)
|
||||
or (%(end_date)s between start_date and end_date)
|
||||
@@ -35,29 +32,17 @@ class AccountingPeriod(Document):
|
||||
"start_date": self.start_date,
|
||||
"end_date": self.end_date,
|
||||
"name": self.name,
|
||||
"company": self.company,
|
||||
},
|
||||
as_dict=True,
|
||||
)
|
||||
"company": self.company
|
||||
}, as_dict=True)
|
||||
|
||||
if len(existing_accounting_period) > 0:
|
||||
frappe.throw(
|
||||
_("Accounting Period overlaps with {0}").format(existing_accounting_period[0].get("name")),
|
||||
OverlapError,
|
||||
)
|
||||
frappe.throw(_("Accounting Period overlaps with {0}")
|
||||
.format(existing_accounting_period[0].get("name")), OverlapError)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_doctypes_for_closing(self):
|
||||
docs_for_closing = []
|
||||
doctypes = [
|
||||
"Sales Invoice",
|
||||
"Purchase Invoice",
|
||||
"Journal Entry",
|
||||
"Payroll Entry",
|
||||
"Bank Clearance",
|
||||
"Asset",
|
||||
"Stock Entry",
|
||||
]
|
||||
doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", "Bank Reconciliation",
|
||||
"Asset", "Purchase Order", "Sales Order", "Leave Application", "Leave Allocation", "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)
|
||||
@@ -67,7 +52,7 @@ class AccountingPeriod(Document):
|
||||
def bootstrap_doctypes_for_closing(self):
|
||||
if len(self.closed_documents) == 0:
|
||||
for doctype_for_closing in self.get_doctypes_for_closing():
|
||||
self.append(
|
||||
"closed_documents",
|
||||
{"document_type": doctype_for_closing.document_type, "closed": doctype_for_closing.closed},
|
||||
)
|
||||
self.append('closed_documents', {
|
||||
"document_type": doctype_for_closing.document_type,
|
||||
"closed": doctype_for_closing.closed
|
||||
})
|
||||
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Accounting Period", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Accounting Period
|
||||
() => frappe.tests.make('Accounting Period', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
||||
@@ -1,55 +1,46 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
import unittest
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from frappe.utils import add_months, nowdate
|
||||
|
||||
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
|
||||
from erpnext.accounts.general_ledger import ClosedAccountingPeriod
|
||||
|
||||
test_dependencies = ["Item"]
|
||||
|
||||
|
||||
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()
|
||||
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)
|
||||
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()
|
||||
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)
|
||||
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)
|
||||
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})
|
||||
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
|
||||
return accounting_period
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user