Compare commits
814 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a1319289e | ||
|
|
c5a43e46d8 | ||
|
|
04dfd7b98f | ||
|
|
85e0e87f01 | ||
|
|
e7a3c7c5ab | ||
|
|
acc32fe7f7 | ||
|
|
487454e817 | ||
|
|
dc278a7427 | ||
|
|
698ee434c0 | ||
|
|
e116cb596c | ||
|
|
169c3ed09d | ||
|
|
d7ba618b92 | ||
|
|
0a37f5575f | ||
|
|
b1bae1bde8 | ||
|
|
bcfd4277f4 | ||
|
|
2b6915519f | ||
|
|
5eb84352ec | ||
|
|
1580bf9ca4 | ||
|
|
4c4c534dcd | ||
|
|
0da11f1b10 | ||
|
|
cb4784c940 | ||
|
|
4c8ee279f3 | ||
|
|
58aea1f819 | ||
|
|
760bfb27d0 | ||
|
|
c0c4e866be | ||
|
|
b16474e606 | ||
|
|
bbed8972c3 | ||
|
|
35f94dfbc6 | ||
|
|
832fa2e76b | ||
|
|
682ce24f8c | ||
|
|
9f02b08427 | ||
|
|
2645980f62 | ||
|
|
ae1a91835e | ||
|
|
094755415a | ||
|
|
746eae4d1a | ||
|
|
cdbb448f6c | ||
|
|
907ea7dd8a | ||
|
|
9a73b7a319 | ||
|
|
2e54da2ea5 | ||
|
|
7e4b93f48e | ||
|
|
b01cc1b449 | ||
|
|
f738b951c5 | ||
|
|
bb1679b74b | ||
|
|
6ddcac7cee | ||
|
|
bcf7da6b1e | ||
|
|
c51d5ba5df | ||
|
|
57ca765d9e | ||
|
|
92e7d1f41d | ||
|
|
ed40542658 | ||
|
|
207b3efed7 | ||
|
|
3131c732ff | ||
|
|
1828c12481 | ||
|
|
4a91c49e0d | ||
|
|
ba1f4263dd | ||
|
|
7d45929872 | ||
|
|
b70f871592 | ||
|
|
d58df13150 | ||
|
|
4101a48869 | ||
|
|
28eff7fb91 | ||
|
|
6dc40e9baf | ||
|
|
ac6d11eb3c | ||
|
|
1c6eeb228f | ||
|
|
b44f26d1ba | ||
|
|
8ea2f45713 | ||
|
|
dde65752b6 | ||
|
|
845980c010 | ||
|
|
6f593130d0 | ||
|
|
52f3bfca73 | ||
|
|
3c3a3ecea8 | ||
|
|
246e47e76e | ||
|
|
f6aad5ed2d | ||
|
|
aa87931172 | ||
|
|
fc155c7712 | ||
|
|
47b5e6272d | ||
|
|
eae56cae54 | ||
|
|
ea925d26a8 | ||
|
|
56f5156f3c | ||
|
|
ee069d47b5 | ||
|
|
6c83b6bddc | ||
|
|
815b460ddd | ||
|
|
d1416542a0 | ||
|
|
69095e7285 | ||
|
|
d6bdad7adf | ||
|
|
48cccca9af | ||
|
|
7c5124140e | ||
|
|
143f384986 | ||
|
|
37fdc43c88 | ||
|
|
ceb761852e | ||
|
|
65d8de36d0 | ||
|
|
8142cd2865 | ||
|
|
ed3a6cf748 | ||
|
|
2285eb7649 | ||
|
|
1648605950 | ||
|
|
039154faa9 | ||
|
|
147acfd502 | ||
|
|
b4c7bad33d | ||
|
|
ff04bf6346 | ||
|
|
aa5182bb9e | ||
|
|
329afe88f9 | ||
|
|
ffa1e1c3bc | ||
|
|
f6616b6cbd | ||
|
|
d95b8e530a | ||
|
|
0e1314c5b5 | ||
|
|
cc920a7e4c | ||
|
|
5bd394278d | ||
|
|
a208c56813 | ||
|
|
862a2eb975 | ||
|
|
1385f20042 | ||
|
|
950250d444 | ||
|
|
63b98ec113 | ||
|
|
4a0edd04c4 | ||
|
|
b7c0c55d61 | ||
|
|
232ad777c9 | ||
|
|
7edb951fdb | ||
|
|
845bbe3e27 | ||
|
|
f7bf50d6fe | ||
|
|
374559bfad | ||
|
|
e7c6605455 | ||
|
|
5bbe823106 | ||
|
|
ad44b00f33 | ||
|
|
893db7a5c3 | ||
|
|
433cdc960d | ||
|
|
4f2832ecd2 | ||
|
|
1755a5f298 | ||
|
|
b3b059b0ea | ||
|
|
d615d4fdcd | ||
|
|
da77abc25b | ||
|
|
7cb19f6e9f | ||
|
|
441a75b1d4 | ||
|
|
03bccb81d8 | ||
|
|
1db0b6de0c | ||
|
|
db53a789be | ||
|
|
c3e1f6bb96 | ||
|
|
f2e5e7fc22 | ||
|
|
541927d58a | ||
|
|
b16b9cd7a0 | ||
|
|
94f15fcec6 | ||
|
|
ba9dbb1b09 | ||
|
|
b7f2066250 | ||
|
|
b30c40ec8a | ||
|
|
2f5587ab25 | ||
|
|
75e9733283 | ||
|
|
69588f57e7 | ||
|
|
88d8c164f7 | ||
|
|
c330a49e9d | ||
|
|
b75f5fd5ab | ||
|
|
6f5815838e | ||
|
|
fe53651287 | ||
|
|
d8546c4316 | ||
|
|
17405d4130 | ||
|
|
2f443a5789 | ||
|
|
a5e11d7195 | ||
|
|
3832e1f9be | ||
|
|
67079d292c | ||
|
|
01a3a81f71 | ||
|
|
befa8d613f | ||
|
|
9e26bcfeeb | ||
|
|
f948fea3bf | ||
|
|
d851bd8d85 | ||
|
|
30672c6b55 | ||
|
|
e73941b9cc | ||
|
|
f33787a706 | ||
|
|
fcc4021e44 | ||
|
|
3b67c89e0b | ||
|
|
7364ebaff6 | ||
|
|
fd8f34018d | ||
|
|
799fa09a23 | ||
|
|
d1dc622914 | ||
|
|
8ce47862f9 | ||
|
|
b24d2efc4b | ||
|
|
a184fbfa66 | ||
|
|
763821d57d | ||
|
|
a132767126 | ||
|
|
453cc374d4 | ||
|
|
43e46a8506 | ||
|
|
2c95130451 | ||
|
|
d46fb5eb8c | ||
|
|
e95c18a42d | ||
|
|
18c2c54633 | ||
|
|
0edec9d25b | ||
|
|
15216fdd6f | ||
|
|
9117af3077 | ||
|
|
92b6f76612 | ||
|
|
8bf0b89595 | ||
|
|
746c162055 | ||
|
|
9eb9ccd785 | ||
|
|
1e046aa49a | ||
|
|
3ad26e4dd1 | ||
|
|
2f3b097d63 | ||
|
|
c505cbc988 | ||
|
|
1e8025b327 | ||
|
|
0e6f2474e8 | ||
|
|
e102332f08 | ||
|
|
145227e4ec | ||
|
|
18e033514e | ||
|
|
26052df76e | ||
|
|
b2f354a614 | ||
|
|
49a59c075f | ||
|
|
ff3b220c79 | ||
|
|
cc7cb2a70a | ||
|
|
79bf233734 | ||
|
|
3698b84d7c | ||
|
|
3fbbb71afc | ||
|
|
a2f18ba794 | ||
|
|
9088432f10 | ||
|
|
c80059e10e | ||
|
|
8e8e9c61ca | ||
|
|
424f0c7b84 | ||
|
|
aa5fb5e50e | ||
|
|
08a60653ba | ||
|
|
8b96fdac12 | ||
|
|
e319598c51 | ||
|
|
0c7fd6cd94 | ||
|
|
0b5260acf0 | ||
|
|
d4be82cf9b | ||
|
|
0166e9e47a | ||
|
|
b71471fcb5 | ||
|
|
7e8d7d05ef | ||
|
|
228ff87ea2 | ||
|
|
8d8655e1cd | ||
|
|
5c73bafeaa | ||
|
|
14859faf17 | ||
|
|
2b7eda8135 | ||
|
|
751d7ecd85 | ||
|
|
6a09b3f7ef | ||
|
|
21897e3c52 | ||
|
|
15b4f6310c | ||
|
|
196a0bc675 | ||
|
|
7c011985f0 | ||
|
|
3cf67a462b | ||
|
|
f061877b4f | ||
|
|
04d244a360 | ||
|
|
b74999da82 | ||
|
|
061f7079ed | ||
|
|
246ed3f122 | ||
|
|
6b25708b7a | ||
|
|
623ed57663 | ||
|
|
1d21842f68 | ||
|
|
ada485f096 | ||
|
|
8a9d41a92e | ||
|
|
f965c5d203 | ||
|
|
21647974c4 | ||
|
|
9c3dca63fa | ||
|
|
c40b99be26 | ||
|
|
982f4ae44d | ||
|
|
9257413b68 | ||
|
|
c723c8b5aa | ||
|
|
2771b7d828 | ||
|
|
75ebed815f | ||
|
|
975ef07c48 | ||
|
|
f666535223 | ||
|
|
08fb19ac8c | ||
|
|
db9762be3f | ||
|
|
03ae61afce | ||
|
|
1847b705fe | ||
|
|
4a573a7e8b | ||
|
|
f74b9b06f7 | ||
|
|
2820a8749f | ||
|
|
41b4864f0c | ||
|
|
13df8a40ef | ||
|
|
7cfa5f0508 | ||
|
|
bb274fce2e | ||
|
|
fec61fe33e | ||
|
|
d0387f41df | ||
|
|
05d8174696 | ||
|
|
ba02ce6adc | ||
|
|
886def0a69 | ||
|
|
7590aa2524 | ||
|
|
8b48ceab8c | ||
|
|
d900e12ae7 | ||
|
|
098760f0e2 | ||
|
|
cc431716ed | ||
|
|
f5ea801b69 | ||
|
|
e2b8ccf1bb | ||
|
|
f447c8258a | ||
|
|
f78ffd84b4 | ||
|
|
63d345c6ab | ||
|
|
d0d1af2072 | ||
|
|
83694fd180 | ||
|
|
fc353efeca | ||
|
|
16edf8b478 | ||
|
|
c9e4fbeda0 | ||
|
|
46ae789f2f | ||
|
|
a9a284a5ae | ||
|
|
823e88d5bd | ||
|
|
1be94efcfa | ||
|
|
a5e9c71397 | ||
|
|
285135da8e | ||
|
|
906c2babaa | ||
|
|
14a394cde1 | ||
|
|
3c821c89f2 | ||
|
|
a041297861 | ||
|
|
856ee10dc4 | ||
|
|
1401e3f679 | ||
|
|
dae29bf2d4 | ||
|
|
0a3be6da27 | ||
|
|
3631e9cbe0 | ||
|
|
1c9a7d2a1b | ||
|
|
972f2f9194 | ||
|
|
239296d16a | ||
|
|
3210db9056 | ||
|
|
feda4f9bc9 | ||
|
|
f6954fb798 | ||
|
|
c6656e68b8 | ||
|
|
a39387d352 | ||
|
|
f3791797d6 | ||
|
|
ea4d63cef3 | ||
|
|
5464ca8a73 | ||
|
|
6c6875f503 | ||
|
|
20523c45c7 | ||
|
|
0248811e53 | ||
|
|
93416ee72c | ||
|
|
51e7086a08 | ||
|
|
5e849ae53e | ||
|
|
de0db0d000 | ||
|
|
f3a67c4533 | ||
|
|
0847f9a074 | ||
|
|
9490c21b8a | ||
|
|
bdb71bca4e | ||
|
|
e8861e2871 | ||
|
|
b084b5e449 | ||
|
|
41d3e57702 | ||
|
|
9df2899f72 | ||
|
|
dacf127f1b | ||
|
|
2b49f9b30a | ||
|
|
533434e878 | ||
|
|
1956028ddc | ||
|
|
a87dc3b4e6 | ||
|
|
97b3f750c9 | ||
|
|
c41b63eff1 | ||
|
|
e6f7ac961f | ||
|
|
cf26964deb | ||
|
|
94157334a7 | ||
|
|
c530161de0 | ||
|
|
2212ae12d8 | ||
|
|
54ade0d26c | ||
|
|
f043760526 | ||
|
|
1cd049d824 | ||
|
|
0a45260ed9 | ||
|
|
1540ad12f9 | ||
|
|
76bd015b2c | ||
|
|
5054a3955b | ||
|
|
1a0713e4b9 | ||
|
|
e9604d8484 | ||
|
|
008d1a0334 | ||
|
|
fe2ffaeafa | ||
|
|
dcef448f1e | ||
|
|
6224cfc414 | ||
|
|
700434ff37 | ||
|
|
4089b3d376 | ||
|
|
6cfab43d5f | ||
|
|
09a66c4201 | ||
|
|
ed8cecbdd8 | ||
|
|
c70109d0c5 | ||
|
|
ccf8c337f7 | ||
|
|
6809b4d86c | ||
|
|
cc08c68153 | ||
|
|
7daa7900ea | ||
|
|
7641f3fe53 | ||
|
|
fe2f51bbbc | ||
|
|
4f33249e1c | ||
|
|
b95b606f25 | ||
|
|
e690f245f2 | ||
|
|
5da4d857c9 | ||
|
|
6e38e917eb | ||
|
|
f3b0b95b15 | ||
|
|
7b0f1ffb2d | ||
|
|
97bb6bbaf4 | ||
|
|
cb4b2ec52a | ||
|
|
f18bbcef86 | ||
|
|
27976382d8 | ||
|
|
93d3c82737 | ||
|
|
03bf529622 | ||
|
|
6c4085fc0c | ||
|
|
c37484c8da | ||
|
|
b4ec294463 | ||
|
|
58406a920c | ||
|
|
98311f4394 | ||
|
|
53829707ad | ||
|
|
fcc31028c6 | ||
|
|
fc3d87181a | ||
|
|
6336ff7323 | ||
|
|
fde13e666a | ||
|
|
f80c09290e | ||
|
|
b797963bd8 | ||
|
|
03b42a7934 | ||
|
|
7e9ff99a6c | ||
|
|
5cbe3441e8 | ||
|
|
0724449d0e | ||
|
|
5a6ff218e8 | ||
|
|
122e4e0a96 | ||
|
|
e233f0e2ff | ||
|
|
40e92b679b | ||
|
|
4770a1abb5 | ||
|
|
ccb9117ba5 | ||
|
|
db938762c7 | ||
|
|
0910fc3b25 | ||
|
|
f0737667c6 | ||
|
|
2d83122c6b | ||
|
|
e2b7f832cc | ||
|
|
6a6958db5c | ||
|
|
ab1acb460b | ||
|
|
48d71fa7f7 | ||
|
|
30960e6a06 | ||
|
|
736000c223 | ||
|
|
4017bfcd2e | ||
|
|
e594e5de49 | ||
|
|
1f1f14be39 | ||
|
|
ebb60f5dbc | ||
|
|
75b00e3958 | ||
|
|
5e3646ad6e | ||
|
|
4439d8264f | ||
|
|
00d79eb68d | ||
|
|
28a9e35de9 | ||
|
|
c450536a2c | ||
|
|
3b3c48c877 | ||
|
|
621d6eac3c | ||
|
|
f9b356992a | ||
|
|
c516e1871d | ||
|
|
9a38e669ef | ||
|
|
143f2c6faf | ||
|
|
9269813207 | ||
|
|
0e6f92efa8 | ||
|
|
1a0e86f11d | ||
|
|
73b7efd61d | ||
|
|
4c4a5b968c | ||
|
|
7b5ac6396a | ||
|
|
01771e8afc | ||
|
|
347c4affe9 | ||
|
|
526957505f | ||
|
|
faa3416852 | ||
|
|
56912791e2 | ||
|
|
38647c68b9 | ||
|
|
4d64acfafc | ||
|
|
d7441ec051 | ||
|
|
0f15273bd7 | ||
|
|
24efb3122a | ||
|
|
85e6f5d04e | ||
|
|
1faaf71dfc | ||
|
|
5a0fbff1a3 | ||
|
|
7278c0ae85 | ||
|
|
5688a6c31a | ||
|
|
71349d221b | ||
|
|
b7219dc698 | ||
|
|
37c6ce7b1e | ||
|
|
7028ba507e | ||
|
|
fcee17fd16 | ||
|
|
5906f02e3a | ||
|
|
721dcb1870 | ||
|
|
6385967ccd | ||
|
|
81a977cacf | ||
|
|
34058ded0e | ||
|
|
e98120b716 | ||
|
|
50e363b24e | ||
|
|
bc176b6bf8 | ||
|
|
784b49e54e | ||
|
|
04fb6e1a45 | ||
|
|
dffd7c3889 | ||
|
|
0c7594e5ed | ||
|
|
5105f909d6 | ||
|
|
2ab9d6e92c | ||
|
|
7580723ab3 | ||
|
|
52fef71c14 | ||
|
|
2cd02af80a | ||
|
|
0b0ec3536c | ||
|
|
6b35ea873b | ||
|
|
ecf220a721 | ||
|
|
04fb1c7fe4 | ||
|
|
53bd62eafc | ||
|
|
ff68bf2609 | ||
|
|
fdd0db3459 | ||
|
|
f92465981c | ||
|
|
885c70984d | ||
|
|
9c15ef903d | ||
|
|
bc799885d0 | ||
|
|
cb129264cb | ||
|
|
fe9cd1d875 | ||
|
|
64fbe955c7 | ||
|
|
0988440fd9 | ||
|
|
274dd4ada0 | ||
|
|
724fd82419 | ||
|
|
3f2604eff6 | ||
|
|
c761fefb78 | ||
|
|
203cb10ef7 | ||
|
|
90c66b1998 | ||
|
|
fed431f908 | ||
|
|
bd9745ba72 | ||
|
|
8fb123b20e | ||
|
|
333ccd212b | ||
|
|
c8cc8b7115 | ||
|
|
ec44fa95ce | ||
|
|
a25e8ea0bc | ||
|
|
ea02b9a5c3 | ||
|
|
74a63bf003 | ||
|
|
a0f2510b01 | ||
|
|
0820161157 | ||
|
|
56bc215855 | ||
|
|
8687d25f7e | ||
|
|
9cea01fa8b | ||
|
|
e06d01e3ed | ||
|
|
11243a4fb4 | ||
|
|
b9e5cd0df4 | ||
|
|
a1f1edc786 | ||
|
|
e2d8dd0663 | ||
|
|
d1605c5cb2 | ||
|
|
64ca52fb77 | ||
|
|
2f11a3bdaf | ||
|
|
943dc1f59c | ||
|
|
6d1c994bc9 | ||
|
|
93cdee4503 | ||
|
|
dfac6848cc | ||
|
|
8ad0b4e0b9 | ||
|
|
b8cd92f1aa | ||
|
|
1fe48cb820 | ||
|
|
723b046c5b | ||
|
|
035160c9a6 | ||
|
|
01c7ce1da3 | ||
|
|
9cf2910ba1 | ||
|
|
c8da7b7d32 | ||
|
|
9679d31397 | ||
|
|
38bebe1b83 | ||
|
|
ffbc11e8de | ||
|
|
818d9674d9 | ||
|
|
086f8942eb | ||
|
|
c3b492b237 | ||
|
|
9d0dd5066a | ||
|
|
e7f479b26a | ||
|
|
7ee45b4af2 | ||
|
|
5cce1e0929 | ||
|
|
be496bc91c | ||
|
|
59f063e5c3 | ||
|
|
af5820874c | ||
|
|
495db99719 | ||
|
|
123beb5a07 | ||
|
|
7ed4e080a2 | ||
|
|
e91025c0aa | ||
|
|
1ac9f2f50d | ||
|
|
bd9aa13db3 | ||
|
|
ed9d5cfdaf | ||
|
|
bf4547ca5f | ||
|
|
b45a6bcb88 | ||
|
|
ac59c2b300 | ||
|
|
6a8d7a1b91 | ||
|
|
5d71a28e97 | ||
|
|
7d100a1ee7 | ||
|
|
81dca110eb | ||
|
|
9c852108d0 | ||
|
|
e3ac032696 | ||
|
|
64cacfb077 | ||
|
|
ae4cc078ea | ||
|
|
0ee543e932 | ||
|
|
a123638d37 | ||
|
|
58996985ed | ||
|
|
5d0ce7939f | ||
|
|
4abf552d7b | ||
|
|
7c5ba957ac | ||
|
|
77f04e293a | ||
|
|
d1d3237784 | ||
|
|
76f0d26f1e | ||
|
|
65922d3079 | ||
|
|
810041cbe3 | ||
|
|
b9626659ea | ||
|
|
e3d13bee36 | ||
|
|
13bd538aca | ||
|
|
d72a24965b | ||
|
|
dc633fe360 | ||
|
|
39046d663d | ||
|
|
6b01abe9ad | ||
|
|
63e4d31aa6 | ||
|
|
f2a0161709 | ||
|
|
3c1a4a0b9b | ||
|
|
82cc2921d1 | ||
|
|
87edd86854 | ||
|
|
e37dd77923 | ||
|
|
e4f689184f | ||
|
|
85f825e98c | ||
|
|
89592c5180 | ||
|
|
587bd144d5 | ||
|
|
1f048b2426 | ||
|
|
1792ff3be7 | ||
|
|
fc595064e0 | ||
|
|
804b4acb9b | ||
|
|
5c7557914b | ||
|
|
381a9377d9 | ||
|
|
9bdd1aa1ed | ||
|
|
d0df28bfa0 | ||
|
|
1966225450 | ||
|
|
4cee27eec0 | ||
|
|
c7d4eaee79 | ||
|
|
43c1a9b502 | ||
|
|
b937fac3ce | ||
|
|
53d94996ad | ||
|
|
26f6752c1e | ||
|
|
bb429745c0 | ||
|
|
909f0c38f1 | ||
|
|
a790ba05f4 | ||
|
|
11fc4f85d0 | ||
|
|
17452a1695 | ||
|
|
7c3d48e353 | ||
|
|
5d288e407c | ||
|
|
f64fae752f | ||
|
|
82763f052f | ||
|
|
bafc73568a | ||
|
|
d015195617 | ||
|
|
b2f550ccb3 | ||
|
|
41413af42d | ||
|
|
ec60ebde6f | ||
|
|
ce81a61fe7 | ||
|
|
dc76b3fa20 | ||
|
|
828cbee12a | ||
|
|
5f5ef16b91 | ||
|
|
686ef8308a | ||
|
|
b63ad44b10 | ||
|
|
5ef121bc10 | ||
|
|
42c1836db5 | ||
|
|
9dbdef3bd5 | ||
|
|
9fd42ed2f7 | ||
|
|
000835c454 | ||
|
|
de1f934e22 | ||
|
|
7cbd916b00 | ||
|
|
56fcf30cb9 | ||
|
|
ebbdd772a9 | ||
|
|
6268d83173 | ||
|
|
4599467939 | ||
|
|
d3613479c6 | ||
|
|
6bf301f53c | ||
|
|
27d7f21553 | ||
|
|
8f87cff4bd | ||
|
|
8f39766924 | ||
|
|
39669f2717 | ||
|
|
3c1017c43b | ||
|
|
0b18a2d347 | ||
|
|
6262496e70 | ||
|
|
c9963f1805 | ||
|
|
8a2b1bcb97 | ||
|
|
b8ecf7c757 | ||
|
|
cf89fa2253 | ||
|
|
419c1eb90d | ||
|
|
2c214e0362 | ||
|
|
7d04dd0bfd | ||
|
|
f1371a7ee7 | ||
|
|
995a78421a | ||
|
|
352187bee6 | ||
|
|
c6d8121f4a | ||
|
|
030ade428b | ||
|
|
c87595b2da | ||
|
|
42f2674cba | ||
|
|
5359f2651a | ||
|
|
42dcffdad4 | ||
|
|
f7c1743b28 | ||
|
|
64aa6620be | ||
|
|
ed43f8015c | ||
|
|
d3fe7ec858 | ||
|
|
c8b406d050 | ||
|
|
2aa577f110 | ||
|
|
f06d175061 | ||
|
|
74b2116adb | ||
|
|
2204d0af94 | ||
|
|
b8a568765d | ||
|
|
cf29f6468d | ||
|
|
aded46d33e | ||
|
|
b8dd046c84 | ||
|
|
e5fa5e6111 | ||
|
|
b89cf1b3ec | ||
|
|
a33d468d30 | ||
|
|
e481a211b1 | ||
|
|
ca23b5ecfd | ||
|
|
11190268ab | ||
|
|
a19150ddaf | ||
|
|
c17dff4b01 | ||
|
|
47fe136d15 | ||
|
|
8f25402dce | ||
|
|
a9165744e2 | ||
|
|
3ebfad7115 | ||
|
|
c7ef8dda79 | ||
|
|
4a6c178795 | ||
|
|
8908543a9c | ||
|
|
065badc54b | ||
|
|
cd2798368b | ||
|
|
2c30acdcb2 | ||
|
|
4a4a6594d1 | ||
|
|
e3035a593c | ||
|
|
587dde0044 | ||
|
|
b6d13ef5b7 | ||
|
|
a3e9dbbcc3 | ||
|
|
97d2a00d91 | ||
|
|
1749406514 | ||
|
|
99b18224f5 | ||
|
|
b0b446e899 | ||
|
|
80069a6379 | ||
|
|
98c515fe7d | ||
|
|
6ee8c545e3 | ||
|
|
3c67146e4b | ||
|
|
e2c200a91e | ||
|
|
d9d5925f14 | ||
|
|
148386f73e | ||
|
|
1b6c3f1a39 | ||
|
|
618fefea73 | ||
|
|
31d9d9f561 | ||
|
|
e715572e7c | ||
|
|
d138b06c8e | ||
|
|
37ee57c211 | ||
|
|
95b995be6d | ||
|
|
86e479f908 | ||
|
|
2a52f59b32 | ||
|
|
c185734bf3 | ||
|
|
beb7c346ea | ||
|
|
88655890be | ||
|
|
e7b37af525 | ||
|
|
10026ea85c | ||
|
|
960118a954 | ||
|
|
8860b9d94d | ||
|
|
f4f9be9233 | ||
|
|
81bded1afe | ||
|
|
7f1d5efd5b | ||
|
|
54a10cd2af | ||
|
|
f52b5ac8af | ||
|
|
2fd33a2f03 | ||
|
|
78f137890c | ||
|
|
0d79be5628 | ||
|
|
fa555abbd2 | ||
|
|
eb00cae86c | ||
|
|
5b731ff73a | ||
|
|
5b8db3729c | ||
|
|
69fb13f229 | ||
|
|
c2acfc9828 | ||
|
|
409843d768 | ||
|
|
fb4e496b54 | ||
|
|
ff8a854b82 | ||
|
|
438b67e8b0 | ||
|
|
e440914327 | ||
|
|
dcbc4d1a46 | ||
|
|
e1637c4cae | ||
|
|
b3fb6e1e04 | ||
|
|
354443b073 | ||
|
|
d4c8dc2915 | ||
|
|
d51cf79fe2 | ||
|
|
306c49f8a0 | ||
|
|
c7cfa270cd | ||
|
|
1568dc32a2 | ||
|
|
878a18528c | ||
|
|
5fa6c4ce21 | ||
|
|
b8ad56f819 | ||
|
|
b3a142f5ab | ||
|
|
1f5b21673c | ||
|
|
093beecd0a | ||
|
|
822fd7747a | ||
|
|
f29a618b69 | ||
|
|
314af94737 | ||
|
|
6771240471 | ||
|
|
1a804e2217 | ||
|
|
ac9c2de8b9 | ||
|
|
2c6705ef83 | ||
|
|
5536923101 | ||
|
|
63e431a219 | ||
|
|
e2787cf2ec | ||
|
|
c4fa74f51d | ||
|
|
b62068f784 | ||
|
|
f8594feb55 | ||
|
|
6a0563f4b2 | ||
|
|
43539673cc | ||
|
|
4809d36fbe | ||
|
|
f61f76ba45 | ||
|
|
8d76d14614 | ||
|
|
adc830b712 | ||
|
|
ed618f284b | ||
|
|
c4d38e2183 | ||
|
|
a5c9cff38a | ||
|
|
fe8d107731 | ||
|
|
e2968e9893 | ||
|
|
fd4bcd855b | ||
|
|
2eba53f763 | ||
|
|
866e9047b0 | ||
|
|
08e04ef01a | ||
|
|
bf3f944bdb | ||
|
|
1d08304ba5 | ||
|
|
fc79e205f0 | ||
|
|
3b0adc5246 | ||
|
|
4888a5dc0d | ||
|
|
1686876b23 | ||
|
|
8c6ff9ddad | ||
|
|
3bc3384bc4 | ||
|
|
37307215d0 | ||
|
|
61704504e6 | ||
|
|
9895aba42e | ||
|
|
753e40b4d5 | ||
|
|
71b7a52990 | ||
|
|
e372fb11ea | ||
|
|
4c924bb76c | ||
|
|
de7b87ee3a | ||
|
|
f3ae85cc9a | ||
|
|
4a929d53bc | ||
|
|
7f8d6b6252 | ||
|
|
6789680fa3 | ||
|
|
4f3f5308e3 | ||
|
|
9e38d29df7 | ||
|
|
15e13c0ed4 | ||
|
|
4984bccbc6 | ||
|
|
4258753ae8 | ||
|
|
68a6d61589 | ||
|
|
c55edf18ad | ||
|
|
a60984866c | ||
|
|
555fa4fbc2 | ||
|
|
43c885868f | ||
|
|
815cb8959a | ||
|
|
38937ecd3c | ||
|
|
9624bac3cf | ||
|
|
a27cca97b5 | ||
|
|
521aa2e94a | ||
|
|
390df6626b | ||
|
|
a2d8585b07 | ||
|
|
84e658058b | ||
|
|
10e813b010 | ||
|
|
a7bd8ee34b |
12
.travis.yml
12
.travis.yml
@@ -6,6 +6,10 @@ python:
|
||||
services:
|
||||
- mysql
|
||||
|
||||
before_install:
|
||||
- "export DISPLAY=:99.0"
|
||||
- "sh -e /etc/init.d/xvfb start"
|
||||
|
||||
install:
|
||||
- sudo apt-get purge -y mysql-common
|
||||
- wget https://raw.githubusercontent.com/frappe/bench/master/install_scripts/setup_frappe.sh
|
||||
@@ -22,7 +26,9 @@ script:
|
||||
- bench use test_site
|
||||
- bench reinstall
|
||||
- bench build-website
|
||||
- bench --verbose run-tests
|
||||
- bench serve &
|
||||
- sleep 10
|
||||
- bench --verbose run-tests --driver Firefox
|
||||
|
||||
before_script:
|
||||
- mysql -e 'create database test_frappe'
|
||||
@@ -33,6 +39,6 @@ notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/92b3bea86d8c5397beef
|
||||
on_success: always
|
||||
on_failure: always
|
||||
on_success: always
|
||||
on_failure: always
|
||||
on_start: never
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Contributing to Frappe / ERPNext
|
||||
|
||||
## Questions
|
||||
|
||||
If you have questions on how to use ERPNext or want help in customization or debugging of your scripts, please post on https://discuss.erpnext.com. This is only for bug reports and feature requests.
|
||||
|
||||
## Reporting issues
|
||||
|
||||
We only accept issues that are bug reports or feature requests. Bugs must be isolated and reproducible problems. Please read the following guidelines before opening any issue.
|
||||
|
||||
@@ -10,13 +10,13 @@ ERPNext is built on the [Frappe](https://github.com/frappe/frappe) Framework, a
|
||||
|
||||
- [User Guide](https://manual.erpnext.com)
|
||||
- [Getting Help](http://erpnext.org/getting-help.html)
|
||||
- [Discussion Forum](https://discuss.frappe.io/)
|
||||
- [Discussion Forum](https://discuss.erpnext.com/)
|
||||
|
||||
---
|
||||
|
||||
### Full Install
|
||||
|
||||
The Easy Way install script for bench will install all dependencies (e.g. MariaDB). See https://github.com/frappe/bench
|
||||
The Easy Way: our install script for bench will install all dependencies (e.g. MariaDB). See https://github.com/frappe/bench for more details.
|
||||
|
||||
New passwords will be created for the ERPNext "Administrator" user, the MariaDB root user, and the frappe user (the script displays the passwords and saves them to ~/frappe_passwords.txt).
|
||||
|
||||
@@ -71,6 +71,6 @@ We do not allow the use of the trademark in advertising, including AdSense/AdWor
|
||||
|
||||
Please note that it is not the goal of this policy to limit commercial activity around ERPNext. We encourage ERPNext-based businesses, and we would love to see hundreds of them.
|
||||
|
||||
When in doubt about your use of the ERPNext name or logo, please contact the Frappe Technologies for clarification.
|
||||
When in doubt about your use of the ERPNext name or logo, please contact Frappe Technologies for clarification.
|
||||
|
||||
(inspired from WordPress)
|
||||
(inspired by WordPress)
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
from __future__ import unicode_literals
|
||||
__version__ = '5.0.4'
|
||||
__version__ = '5.6.3'
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"permlevel": 0,
|
||||
"read_only": 1,
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
@@ -44,7 +44,7 @@
|
||||
"label": "Is Group",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
@@ -57,7 +57,7 @@
|
||||
"permlevel": 0,
|
||||
"read_only": 1,
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "root_type",
|
||||
@@ -101,7 +101,7 @@
|
||||
"label": "Account Type",
|
||||
"oldfieldname": "account_type",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "\nBank\nCash\nTax\nChargeable\nWarehouse\nReceivable\nPayable\nEquity\nFixed Asset\nCost of Goods Sold\nExpense Account\nIncome Account\nStock Received But Not Billed\nExpenses Included In Valuation\nStock Adjustment\nStock\nTemporary",
|
||||
"options": "\nBank\nCash\nTax\nChargeable\nWarehouse\nReceivable\nPayable\nEquity\nFixed Asset\nCost of Goods Sold\nExpense Account\nRound Off\nIncome Account\nStock Received But Not Billed\nExpenses Included In Valuation\nStock Adjustment\nStock\nTemporary",
|
||||
"permlevel": 0,
|
||||
"search_index": 0
|
||||
},
|
||||
@@ -147,7 +147,8 @@
|
||||
"label": "Lft",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "rgt",
|
||||
@@ -156,7 +157,8 @@
|
||||
"label": "Rgt",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "old_parent",
|
||||
@@ -171,7 +173,7 @@
|
||||
"icon": "icon-money",
|
||||
"idx": 1,
|
||||
"in_create": 0,
|
||||
"modified": "2015-04-27 20:07:37.147184",
|
||||
"modified": "2015-07-20 03:54:14.297995",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account",
|
||||
@@ -255,5 +257,5 @@
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"search_fields": "is_group"
|
||||
"search_fields": ""
|
||||
}
|
||||
@@ -23,6 +23,7 @@ class Account(Document):
|
||||
def validate(self):
|
||||
self.validate_parent()
|
||||
self.validate_root_details()
|
||||
self.set_root_and_report_type()
|
||||
self.validate_mandatory()
|
||||
self.validate_warehouse_account()
|
||||
self.validate_frozen_accounts_modifier()
|
||||
@@ -32,7 +33,7 @@ class Account(Document):
|
||||
"""Fetch Parent Details and validate parent account"""
|
||||
if self.parent_account:
|
||||
par = frappe.db.get_value("Account", self.parent_account,
|
||||
["name", "is_group", "report_type", "root_type", "company"], as_dict=1)
|
||||
["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))
|
||||
elif par.name == self.name:
|
||||
@@ -43,13 +44,27 @@ class Account(Document):
|
||||
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)
|
||||
|
||||
if par.report_type:
|
||||
self.report_type = par.report_type
|
||||
if par.root_type:
|
||||
self.root_type = par.root_type
|
||||
|
||||
if self.is_group:
|
||||
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))
|
||||
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))
|
||||
|
||||
def validate_root_details(self):
|
||||
#does not exists parent
|
||||
# does not exists parent
|
||||
if frappe.db.exists("Account", self.name):
|
||||
if not frappe.db.get_value("Account", self.name, "parent_account"):
|
||||
throw(_("Root cannot be edited."))
|
||||
|
||||
@@ -92,13 +92,13 @@ def get_charts_for_country(country):
|
||||
with open(os.path.join(path, fname), "r") as f:
|
||||
_get_chart_name(f.read())
|
||||
|
||||
countries_use_OHADA_system = ["Benin", "Burkina Faso", "Cameroon", "Central African Republic", "Comoros",
|
||||
"Congo", "Ivory Coast", "Gabon", "Guinea", "Guinea Bissau", "Equatorial Guinea", "Mali", "Niger",
|
||||
"Replica of Democratic Congo", "Senegal", "Chad", "Togo"]
|
||||
|
||||
if country in countries_use_OHADA_system:
|
||||
with open(os.path.join(os.path.dirname(__file__), "syscohada_syscohada_chart_template.json"), "r") as f:
|
||||
_get_chart_name(f.read())
|
||||
# countries_use_OHADA_system = ["Benin", "Burkina Faso", "Cameroon", "Central African Republic", "Comoros",
|
||||
# "Congo", "Ivory Coast", "Gabon", "Guinea", "Guinea Bissau", "Equatorial Guinea", "Mali", "Niger",
|
||||
# "Replica of Democratic Congo", "Senegal", "Chad", "Togo"]
|
||||
#
|
||||
# if country in countries_use_OHADA_system:
|
||||
# with open(os.path.join(os.path.dirname(__file__), "syscohada_syscohada_chart_template.json"), "r") as f:
|
||||
# _get_chart_name(f.read())
|
||||
|
||||
if len(charts) != 1:
|
||||
charts.append("Standard")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"country_code": "ni",
|
||||
"name": "Catalogo de Cuentas",
|
||||
"name": "Catalogo de Cuentas Nicaragua",
|
||||
"is_active": "Yes",
|
||||
"tree": {
|
||||
"Activo": {
|
||||
@@ -72,7 +72,7 @@
|
||||
"IVA Acreditable por Importaciones": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"IVA Acreditable por Prestacion de Servicios": {
|
||||
"IVA Acreditable por Prestacion de Servicios y Uso y Goce de Bienes": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Acreditacion Proporcional": {}
|
||||
@@ -229,11 +229,19 @@
|
||||
"Impuesto al Valor Agregado por Pagar": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Impuesto sobre la Renta": {
|
||||
"Impuesto sobre la Renta por Actividades Economicas": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Impuestos Municipales": {
|
||||
"account_type": "Tax"
|
||||
"Impuesto Municipal Sobre Ingresos": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Recoleccion Basura": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Matricula Municipal": {
|
||||
"account_type": "Tax"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Retenciones por Pagar": {
|
||||
@@ -241,7 +249,13 @@
|
||||
"Retencion Rentas del Trabajo Tarifa Progresiva": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva por Rentas del Trabajo": {
|
||||
"Retencion Definitiva 10% por Rentas del Trabajo - Indemnizacion Adicional": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 12.5% por Rentas del Trabajo - Dietas": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 15% por Rentas del Trabajo - No Residentes": {
|
||||
"account_type": "Tax"
|
||||
}
|
||||
},
|
||||
@@ -258,11 +272,26 @@
|
||||
"Retencion 5% compra Madera en Rollo": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 1.5% Actividades Economicas No Residentes": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 3% Actividades Economicas No Residentes": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 10% Actividades Economicas No Residentes": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 15% Actividades Economicas No Residentes": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Otras Retenciones 10%": {
|
||||
"account_type": "Tax"
|
||||
}
|
||||
},
|
||||
"Rentas y Ganancias de Capital": {
|
||||
"Retencion Defintiva 15% por Rentas de Capital": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Defintiva 10% por Rentas de Capital": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
@@ -272,10 +301,16 @@
|
||||
"Retencion Definitiva 10% por Ganancia de Capital": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva Actividades Economicas No Residentes": {
|
||||
"Retencion Definitiva 0.25% Transacciones Bursatiles": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva Transacciones Bursatiles": {
|
||||
"Retencion Definitiva 1% Transacciones Bursatiles": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 1.5% Transacciones Bursatiles": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 2% Transacciones Bursatiles": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retenciones Defintiva 5% Fondos de Inversion": {
|
||||
|
||||
@@ -117,8 +117,8 @@ def get():
|
||||
_("Print and Stationary"): {
|
||||
"account_type": "Expense Account"
|
||||
},
|
||||
_("Rounded Off"): {
|
||||
"account_type": "Expense Account"
|
||||
_("Round Off"): {
|
||||
"account_type": "Round Off"
|
||||
},
|
||||
_("Salary"): {
|
||||
"account_type": "Expense Account"
|
||||
|
||||
@@ -38,12 +38,19 @@
|
||||
"label": "Credit Controller",
|
||||
"options": "Role",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "check_supplier_invoice_uniqueness",
|
||||
"fieldtype": "Check",
|
||||
"label": "Check Supplier Invoice Number Uniqueness",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
}
|
||||
],
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2015-02-05 05:11:34.163902",
|
||||
"modified": "2015-07-14 00:51:48.095525",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Settings",
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
frappe.ui.form.on("Bank Reconciliation", {
|
||||
refresh: function(frm) {
|
||||
frm.disable_save();
|
||||
},
|
||||
|
||||
update_clearance_date: function(frm) {
|
||||
return frappe.call({
|
||||
method: "update_details",
|
||||
@@ -33,5 +37,4 @@ cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
||||
|
||||
cur_frm.set_value("from_date", frappe.datetime.month_start());
|
||||
cur_frm.set_value("to_date", frappe.datetime.month_end());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,13 +19,15 @@ class BankReconciliation(Document):
|
||||
|
||||
|
||||
dl = frappe.db.sql("""select t1.name, t1.cheque_no, t1.cheque_date, t2.debit,
|
||||
t2.credit, t1.posting_date, t2.against_account, t1.clearance_date
|
||||
t2.credit, t1.posting_date, t2.against_account, t1.clearance_date,
|
||||
t2.reference_type, t2.reference_name
|
||||
from
|
||||
`tabJournal Entry` t1, `tabJournal Entry Account` t2
|
||||
where
|
||||
t2.parent = t1.name and t2.account = %s
|
||||
and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1
|
||||
and ifnull(t1.is_opening, 'No') = 'No' %s""" %
|
||||
and ifnull(t1.is_opening, 'No') = 'No' %s
|
||||
order by t1.posting_date""" %
|
||||
('%s', '%s', '%s', condition), (self.bank_account, self.from_date, self.to_date), as_dict=1)
|
||||
|
||||
self.set('journal_entries', [])
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"creation": "2013-02-22 01:27:37",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "voucher_id",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Voucher ID",
|
||||
"no_copy": 0,
|
||||
@@ -13,46 +21,84 @@
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Journal Entry",
|
||||
"permlevel": 0,
|
||||
"search_index": 0
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "clearance_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Clearance Date",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "clearance_date",
|
||||
"oldfieldtype": "Date",
|
||||
"permlevel": 0,
|
||||
"search_index": 0
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "against_account",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Against Account",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "against_account",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 1,
|
||||
"search_index": 0
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "cheque_number",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Cheque Number",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "cheque_number",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 1,
|
||||
"search_index": 0
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "debit",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Debit",
|
||||
"no_copy": 0,
|
||||
@@ -60,12 +106,21 @@
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 1,
|
||||
"search_index": 0
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "credit",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Credit",
|
||||
"no_copy": 0,
|
||||
@@ -73,40 +128,113 @@
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 1,
|
||||
"search_index": 0
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "reference_type",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Reference Type",
|
||||
"no_copy": 0,
|
||||
"options": "DocType",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "reference_name",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Reference Name",
|
||||
"no_copy": 0,
|
||||
"options": "reference_type",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "posting_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Posting Date",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "posting_date",
|
||||
"oldfieldtype": "Date",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 1,
|
||||
"search_index": 0
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "cheque_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Cheque Date",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "cheque_date",
|
||||
"oldfieldtype": "Date",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 1,
|
||||
"search_index": 0
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 1,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"modified": "2015-04-21 01:29:29.570890",
|
||||
"modified": "2015-08-10 16:59:43.974705",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Reconciliation Detail",
|
||||
"owner": "Administrator",
|
||||
"permissions": []
|
||||
"permissions": [],
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0
|
||||
}
|
||||
@@ -54,7 +54,7 @@ class CForm(Document):
|
||||
frappe.throw(_("Please enter atleast 1 invoice in the table"))
|
||||
|
||||
def set_total_invoiced_amount(self):
|
||||
total = sum([flt(d.base_grand_total) for d in self.get('invoices')])
|
||||
total = sum([flt(d.grand_total) for d in self.get('invoices')])
|
||||
frappe.db.set(self, 'total_invoiced_amount', total)
|
||||
|
||||
def get_invoice_details(self, invoice_no):
|
||||
|
||||
@@ -17,7 +17,7 @@ erpnext.accounts.CostCenterController = frappe.ui.form.Controller.extend({
|
||||
return {
|
||||
filters:[
|
||||
['Account', 'company', '=', me.frm.doc.company],
|
||||
['Account', 'report_type', '=', 'Profit and Loss'],
|
||||
['Account', 'root_type', '=', 'Expense'],
|
||||
['Account', 'is_group', '=', '0'],
|
||||
]
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"description": "Define Budget for this Cost Center. To set budget action, see <a href=\"#!List/Company\">Company Master</a>",
|
||||
"description": "Define Budget for this Cost Center. To set budget action, see \"Company List\"",
|
||||
"fieldname": "sb1",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Budget",
|
||||
@@ -139,7 +139,7 @@
|
||||
"icon": "icon-money",
|
||||
"idx": 1,
|
||||
"in_create": 0,
|
||||
"modified": "2015-04-23 02:54:26.934607",
|
||||
"modified": "2015-07-13 05:28:25.504801",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cost Center",
|
||||
@@ -189,8 +189,8 @@
|
||||
"apply_user_permissions": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"role": "Material User"
|
||||
"role": "Stock User"
|
||||
}
|
||||
],
|
||||
"search_fields": "parent_cost_center, is_group"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
from frappe import msgprint, _
|
||||
|
||||
from frappe import _
|
||||
from frappe.utils.nestedset import NestedSet
|
||||
|
||||
class CostCenter(NestedSet):
|
||||
@@ -14,18 +12,46 @@ class CostCenter(NestedSet):
|
||||
def autoname(self):
|
||||
self.name = self.cost_center_name.strip() + ' - ' + \
|
||||
frappe.db.get_value("Company", self.company, "abbr")
|
||||
|
||||
|
||||
def validate(self):
|
||||
self.validate_mandatory()
|
||||
self.validate_accounts()
|
||||
|
||||
def validate_mandatory(self):
|
||||
if self.cost_center_name != self.company and not self.parent_cost_center:
|
||||
msgprint(_("Please enter parent cost center"), raise_exception=1)
|
||||
frappe.throw(_("Please enter parent cost center"))
|
||||
elif self.cost_center_name == self.company and self.parent_cost_center:
|
||||
msgprint(_("Root cannot have a parent cost center"), raise_exception=1)
|
||||
frappe.throw(_("Root cannot have a parent cost center"))
|
||||
|
||||
def validate_accounts(self):
|
||||
if self.is_group==1 and self.get("budgets"):
|
||||
frappe.throw(_("Budget cannot be set for Group Cost Center"))
|
||||
|
||||
check_acc_list = []
|
||||
for d in self.get('budgets'):
|
||||
if d.account:
|
||||
account_details = frappe.db.get_value("Account", d.account,
|
||||
["is_group", "company", "root_type"], as_dict=1)
|
||||
if account_details.is_group:
|
||||
frappe.throw(_("Budget cannot be assigned against Group Account {0}").format(d.account))
|
||||
elif account_details.company != self.company:
|
||||
frappe.throw(_("Account {0} does not belongs to company {1}").format(d.account, self.company))
|
||||
elif account_details.root_type != "Expense":
|
||||
frappe.throw(_("Budget cannot be assigned against {0}, as it's not an Expense account")
|
||||
.format(d.account))
|
||||
|
||||
if [d.account, d.fiscal_year] in check_acc_list:
|
||||
frappe.throw(_("Account {0} has been entered more than once for fiscal year {1}")
|
||||
.format(d.account, d.fiscal_year))
|
||||
else:
|
||||
check_acc_list.append([d.account, d.fiscal_year])
|
||||
|
||||
def convert_group_to_ledger(self):
|
||||
if self.check_if_child_exists():
|
||||
msgprint(_("Cannot convert Cost Center to ledger as it has child nodes"), raise_exception=1)
|
||||
frappe.throw(_("Cannot convert Cost Center to ledger as it has child nodes"))
|
||||
elif self.check_gle_exists():
|
||||
msgprint(_("Cost Center with existing transactions can not be converted to ledger"), raise_exception=1)
|
||||
frappe.throw(_("Cost Center with existing transactions can not be converted to ledger"))
|
||||
else:
|
||||
self.is_group = 0
|
||||
self.save()
|
||||
@@ -33,7 +59,7 @@ class CostCenter(NestedSet):
|
||||
|
||||
def convert_ledger_to_group(self):
|
||||
if self.check_gle_exists():
|
||||
msgprint(_("Cost Center with existing transactions can not be converted to group"), raise_exception=1)
|
||||
frappe.throw(_("Cost Center with existing transactions can not be converted to group"))
|
||||
else:
|
||||
self.is_group = 1
|
||||
self.save()
|
||||
@@ -46,21 +72,6 @@ class CostCenter(NestedSet):
|
||||
return frappe.db.sql("select name from `tabCost Center` where \
|
||||
parent_cost_center = %s and docstatus != 2", self.name)
|
||||
|
||||
def validate_budget_details(self):
|
||||
check_acc_list = []
|
||||
for d in self.get('budgets'):
|
||||
if self.is_group==1:
|
||||
msgprint(_("Budget cannot be set for Group Cost Centers"), raise_exception=1)
|
||||
|
||||
if [d.account, d.fiscal_year] in check_acc_list:
|
||||
msgprint(_("Account {0} has been entered more than once for fiscal year {1}").format(d.account, d.fiscal_year), raise_exception=1)
|
||||
else:
|
||||
check_acc_list.append([d.account, d.fiscal_year])
|
||||
|
||||
def validate(self):
|
||||
self.validate_mandatory()
|
||||
self.validate_budget_details()
|
||||
|
||||
def before_rename(self, olddn, newdn, merge=False):
|
||||
# Add company abbr if not provided
|
||||
from erpnext.setup.doctype.company.company import get_name_with_abbr
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
],
|
||||
"icon": "icon-calendar",
|
||||
"idx": 1,
|
||||
"modified": "2015-04-18 07:33:23.922518",
|
||||
"modified": "2015-07-13 05:28:27.745408",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Fiscal Year",
|
||||
@@ -78,11 +78,63 @@
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"email": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"role": "All"
|
||||
"role": "Sales User"
|
||||
},
|
||||
{
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Purchase User",
|
||||
"share": 0,
|
||||
"write": 0
|
||||
},
|
||||
{
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Accounts User",
|
||||
"share": 0,
|
||||
"write": 0
|
||||
},
|
||||
{
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Stock User",
|
||||
"share": 0,
|
||||
"write": 0
|
||||
},
|
||||
{
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Employee",
|
||||
"share": 0,
|
||||
"write": 0
|
||||
}
|
||||
],
|
||||
"sort_field": "name",
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Party",
|
||||
"options": "party_type",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "cost_center",
|
||||
@@ -192,7 +193,7 @@
|
||||
"icon": "icon-list",
|
||||
"idx": 1,
|
||||
"in_create": 1,
|
||||
"modified": "2015-04-27 20:32:48.246818",
|
||||
"modified": "2015-07-09 15:51:04.986518",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "GL Entry",
|
||||
@@ -224,6 +225,19 @@
|
||||
"role": "Accounts Manager",
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
{
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 1,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Auditor",
|
||||
"share": 0,
|
||||
"write": 0
|
||||
}
|
||||
],
|
||||
"search_fields": "voucher_no,account,posting_date,against_voucher",
|
||||
|
||||
@@ -4,19 +4,22 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
from frappe.utils import flt, fmt_money, getdate, formatdate
|
||||
from frappe.utils import flt, fmt_money, getdate, formatdate, cstr
|
||||
from frappe import _
|
||||
|
||||
from frappe.model.document import Document
|
||||
|
||||
class GLEntry(Document):
|
||||
class CustomerFrozen(frappe.ValidationError): pass
|
||||
|
||||
class GLEntry(Document):
|
||||
def validate(self):
|
||||
self.flags.ignore_submit_comment = True
|
||||
self.check_mandatory()
|
||||
self.pl_must_have_cost_center()
|
||||
self.validate_posting_date()
|
||||
self.check_pl_account()
|
||||
self.validate_cost_center()
|
||||
self.validate_party()
|
||||
|
||||
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
|
||||
self.validate_account_details(adv_adj)
|
||||
@@ -88,6 +91,13 @@ class GLEntry(Document):
|
||||
|
||||
if self.cost_center and _get_cost_center_company() != self.company:
|
||||
frappe.throw(_("Cost Center {0} does not belong to Company {1}").format(self.cost_center, self.company))
|
||||
|
||||
def validate_party(self):
|
||||
if self.party_type and self.party:
|
||||
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier')
|
||||
if not frozen_accounts_modifier in frappe.get_roles():
|
||||
if frappe.db.get_value(self.party_type, self.party, "is_frozen"):
|
||||
frappe.throw("{0} {1} is frozen".format(self.party_type, self.party), CustomerFrozen)
|
||||
|
||||
def validate_balance_type(account, adv_adj=False):
|
||||
if not adv_adj and account:
|
||||
@@ -118,7 +128,7 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
|
||||
bal = flt(frappe.db.sql("""select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
||||
from `tabGL Entry`
|
||||
where against_voucher_type=%s and against_voucher=%s
|
||||
and account = %s and party_type=%s and party=%s""",
|
||||
and account = %s and ifnull(party_type, '')=%s and ifnull(party, '')=%s""",
|
||||
(against_voucher_type, against_voucher, account, party_type, party))[0][0] or 0.0)
|
||||
|
||||
if against_voucher_type == 'Purchase Invoice':
|
||||
@@ -127,8 +137,9 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
|
||||
against_voucher_amount = flt(frappe.db.sql("""
|
||||
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
||||
from `tabGL Entry` where voucher_type = 'Journal Entry' and voucher_no = %s
|
||||
and account = %s and party_type=%s and party=%s and ifnull(against_voucher, '') = ''""",
|
||||
(against_voucher, account, party_type, party))[0][0])
|
||||
and account = %s and ifnull(party_type, '')=%s and ifnull(party, '')=%s
|
||||
and ifnull(against_voucher, '') = ''""",
|
||||
(against_voucher, account, cstr(party_type), cstr(party)))[0][0])
|
||||
|
||||
if not against_voucher_amount:
|
||||
frappe.throw(_("Against Journal Entry {0} is already adjusted against some other voucher")
|
||||
@@ -138,9 +149,9 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
|
||||
if against_voucher_amount < 0:
|
||||
bal = -bal
|
||||
|
||||
# Validation : Outstanding can not be negative
|
||||
if bal < 0 and not on_cancel:
|
||||
frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal)))
|
||||
# Validation : Outstanding can not be negative for JV
|
||||
if bal < 0 and not on_cancel:
|
||||
frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal)))
|
||||
|
||||
# Update outstanding amt on against voucher
|
||||
if against_voucher_type in ["Sales Invoice", "Purchase Invoice"]:
|
||||
@@ -157,3 +168,22 @@ def validate_frozen_account(account, adv_adj=None):
|
||||
frappe.throw(_("Account {0} is frozen").format(account))
|
||||
elif frozen_accounts_modifier not in frappe.get_roles():
|
||||
frappe.throw(_("Not authorized to edit frozen Account {0}").format(account))
|
||||
|
||||
def update_against_account(voucher_type, voucher_no):
|
||||
entries = frappe.db.get_all("GL Entry",
|
||||
filters={"voucher_type": voucher_type, "voucher_no": voucher_no},
|
||||
fields=["name", "party", "against", "debit", "credit", "account"])
|
||||
|
||||
accounts_debited, accounts_credited = [], []
|
||||
for d in entries:
|
||||
if flt(d.debit > 0): accounts_debited.append(d.party or d.account)
|
||||
if flt(d.credit) > 0: accounts_credited.append(d.party or d.account)
|
||||
|
||||
for d in entries:
|
||||
if flt(d.debit > 0):
|
||||
new_against = ", ".join(list(set(accounts_credited)))
|
||||
if flt(d.credit > 0):
|
||||
new_against = ", ".join(list(set(accounts_debited)))
|
||||
|
||||
if d.against != new_against:
|
||||
frappe.db.set_value("GL Entry", d.name, "against", new_against)
|
||||
|
||||
25
erpnext/accounts/doctype/gl_entry/test_gl_entry.py
Normal file
25
erpnext/accounts/doctype/gl_entry/test_gl_entry.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# 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, unittest
|
||||
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
|
||||
|
||||
class TestGLEntry(unittest.TestCase):
|
||||
def test_round_off_entry(self):
|
||||
frappe.db.set_value("Company", "_Test Company", "round_off_account", "_Test Write Off - _TC")
|
||||
frappe.db.set_value("Company", "_Test Company", "round_off_cost_center", "_Test Cost Center - _TC")
|
||||
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Account Bank Account - _TC", 100, "_Test Cost Center - _TC", submit=False)
|
||||
|
||||
jv.get("accounts")[0].debit = 100.01
|
||||
jv.flags.ignore_validate = True
|
||||
jv.submit()
|
||||
|
||||
round_off_entry = frappe.db.sql("""select name from `tabGL Entry`
|
||||
where voucher_type='Journal Entry' and voucher_no = %s
|
||||
and account='_Test Write Off - _TC' and cost_center='_Test Cost Center - _TC'
|
||||
and ifnull(debit, 0) = 0 and ifnull(credit, 0) = '.01'""", jv.name)
|
||||
|
||||
self.assertTrue(round_off_entry)
|
||||
@@ -4,7 +4,7 @@
|
||||
frappe.provide("erpnext.accounts");
|
||||
frappe.require("assets/erpnext/js/utils.js");
|
||||
|
||||
erpnext.accounts.JournalVoucher = frappe.ui.form.Controller.extend({
|
||||
erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
||||
onload: function() {
|
||||
this.load_defaults();
|
||||
this.setup_queries();
|
||||
@@ -48,34 +48,49 @@ erpnext.accounts.JournalVoucher = frappe.ui.form.Controller.extend({
|
||||
}
|
||||
});
|
||||
|
||||
$.each([["against_voucher", "Purchase Invoice", "supplier"],
|
||||
["against_invoice", "Sales Invoice", "customer"]], function(i, opts) {
|
||||
me.frm.set_query(opts[0], "accounts", function(doc, cdt, cdn) {
|
||||
var jvd = frappe.get_doc(cdt, cdn);
|
||||
frappe.model.validate_missing(jvd, "party_type");
|
||||
frappe.model.validate_missing(jvd, "party");
|
||||
return {
|
||||
filters: [
|
||||
[opts[1], opts[2], "=", jvd.party],
|
||||
[opts[1], "docstatus", "=", 1],
|
||||
[opts[1], "outstanding_amount", ">", 0]
|
||||
]
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
this.frm.set_query("against_jv", "accounts", function(doc, cdt, cdn) {
|
||||
me.frm.set_query("reference_name", "accounts", function(doc, cdt, cdn) {
|
||||
var jvd = frappe.get_doc(cdt, cdn);
|
||||
frappe.model.validate_missing(jvd, "account");
|
||||
|
||||
return {
|
||||
query: "erpnext.accounts.doctype.journal_entry.journal_entry.get_against_jv",
|
||||
filters: {
|
||||
account: jvd.account,
|
||||
party: jvd.party
|
||||
}
|
||||
// expense claim
|
||||
if(jvd.reference_type==="Expense Claim") {
|
||||
return {};
|
||||
}
|
||||
|
||||
// journal entry
|
||||
if(jvd.reference_type==="Journal Entry") {
|
||||
frappe.model.validate_missing(jvd, "account");
|
||||
|
||||
return {
|
||||
query: "erpnext.accounts.doctype.journal_entry.journal_entry.get_against_jv",
|
||||
filters: {
|
||||
account: jvd.account,
|
||||
party: jvd.party
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// against party
|
||||
|
||||
frappe.model.validate_missing(jvd, "party_type");
|
||||
frappe.model.validate_missing(jvd, "party");
|
||||
|
||||
var out = {
|
||||
filters: [
|
||||
[jvd.reference_type, jvd.reference_type.indexOf("Sales")===0 ? "customer" : "supplier", "=", jvd.party],
|
||||
[jvd.reference_type, "docstatus", "=", 1],
|
||||
]
|
||||
};
|
||||
|
||||
if(in_list(["Sales Invoice", "Purchase Invoice"], jvd.reference_type)) {
|
||||
out.filters.push([jvd.reference_type, "outstanding_amount", "!=", 0]);
|
||||
} else {
|
||||
out.filters.push([jvd.reference_type, "per_billed", "<", 100]);
|
||||
}
|
||||
|
||||
return out;
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
|
||||
setup_balance_formatter: function() {
|
||||
@@ -93,24 +108,16 @@ erpnext.accounts.JournalVoucher = frappe.ui.form.Controller.extend({
|
||||
})
|
||||
},
|
||||
|
||||
against_voucher: function(doc, cdt, cdn) {
|
||||
reference_name: function(doc, cdt, cdn) {
|
||||
var d = frappe.get_doc(cdt, cdn);
|
||||
if (d.against_voucher && !flt(d.debit)) {
|
||||
this.get_outstanding('Purchase Invoice', d.against_voucher, d);
|
||||
if (d.reference_type==="Purchase Invoice" && !flt(d.debit)) {
|
||||
this.get_outstanding('Purchase Invoice', d.reference_name, d);
|
||||
}
|
||||
},
|
||||
|
||||
against_invoice: function(doc, cdt, cdn) {
|
||||
var d = frappe.get_doc(cdt, cdn);
|
||||
if (d.against_invoice && !flt(d.credit)) {
|
||||
this.get_outstanding('Sales Invoice', d.against_invoice, d);
|
||||
if (d.reference_type==="Sales Invoice" && !flt(d.credit)) {
|
||||
this.get_outstanding('Sales Invoice', d.reference_name, d);
|
||||
}
|
||||
},
|
||||
|
||||
against_jv: function(doc, cdt, cdn) {
|
||||
var d = frappe.get_doc(cdt, cdn);
|
||||
if (d.against_jv && d.party && !flt(d.credit) && !flt(d.debit)) {
|
||||
this.get_outstanding('Journal Entry', d.against_jv, d);
|
||||
if (d.reference_type==="Journal Entry" && !flt(d.credit) && !flt(d.debit)) {
|
||||
this.get_outstanding('Journal Entry', d.reference_name, d);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -119,7 +126,8 @@ erpnext.accounts.JournalVoucher = frappe.ui.form.Controller.extend({
|
||||
var args = {
|
||||
"doctype": doctype,
|
||||
"docname": docname,
|
||||
"party": child.party
|
||||
"party": child.party,
|
||||
"account": child.account
|
||||
}
|
||||
|
||||
return this.frm.call({
|
||||
@@ -130,10 +138,31 @@ erpnext.accounts.JournalVoucher = frappe.ui.form.Controller.extend({
|
||||
cur_frm.cscript.update_totals(me.frm.doc);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
accounts_add: function(doc, cdt, cdn) {
|
||||
var row = frappe.get_doc(cdt, cdn);
|
||||
$.each(doc.accounts, function(i, d) {
|
||||
if(d.account && d.party && d.party_type) {
|
||||
row.account = d.account;
|
||||
row.party = d.party;
|
||||
row.party_type = d.party_type;
|
||||
}
|
||||
});
|
||||
|
||||
// set difference
|
||||
if(doc.difference) {
|
||||
if(doc.difference > 0) {
|
||||
row.credit = doc.difference;
|
||||
} else {
|
||||
row.debit = -doc.difference;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
cur_frm.script_manager.make(erpnext.accounts.JournalVoucher);
|
||||
cur_frm.script_manager.make(erpnext.accounts.JournalEntry);
|
||||
|
||||
cur_frm.cscript.refresh = function(doc) {
|
||||
erpnext.toggle_naming_series();
|
||||
@@ -192,11 +221,12 @@ cur_frm.cscript.account = function(doc,dt,dn) {
|
||||
var d = locals[dt][dn];
|
||||
if(d.account) {
|
||||
return frappe.call({
|
||||
method: "erpnext.accounts.utils.get_balance_on",
|
||||
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_account_balance_and_party_type",
|
||||
args: {account: d.account, date: doc.posting_date},
|
||||
callback: function(r) {
|
||||
d.balance = r.message;
|
||||
$.extend(d, r.message);
|
||||
refresh_field('balance', d.name, 'accounts');
|
||||
refresh_field('party_type', d.name, 'accounts');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"fieldname": "posting_date",
|
||||
"fieldtype": "Date",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Posting Date",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "posting_date",
|
||||
@@ -310,7 +310,7 @@
|
||||
"depends_on": "eval:doc.voucher_type == 'Write Off Entry'",
|
||||
"fieldname": "write_off_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Write Off Amount <=",
|
||||
"label": "Write Off Amount",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
@@ -445,7 +445,7 @@
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2015-04-27 20:32:31.655580",
|
||||
"modified": "2015-06-29 15:28:12.529019",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Journal Entry",
|
||||
@@ -503,4 +503,4 @@
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "title"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, cint
|
||||
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, date_diff
|
||||
from frappe import msgprint, _, scrub
|
||||
from erpnext.setup.utils import get_company_currency
|
||||
from erpnext.controllers.accounts_controller import AccountsController
|
||||
@@ -28,14 +28,11 @@ class JournalEntry(AccountsController):
|
||||
self.validate_entries_for_advance()
|
||||
self.validate_debit_and_credit()
|
||||
self.validate_against_jv()
|
||||
self.validate_against_sales_invoice()
|
||||
self.validate_against_purchase_invoice()
|
||||
self.validate_reference_doc()
|
||||
self.set_against_account()
|
||||
self.create_remarks()
|
||||
self.set_print_format_fields()
|
||||
self.validate_against_sales_order()
|
||||
self.validate_against_purchase_order()
|
||||
self.check_credit_days()
|
||||
self.check_due_date()
|
||||
self.validate_expense_claim()
|
||||
self.validate_credit_debit_note()
|
||||
self.validate_empty_accounts_table()
|
||||
@@ -54,10 +51,8 @@ class JournalEntry(AccountsController):
|
||||
advance_paid = frappe._dict()
|
||||
for d in self.get("accounts"):
|
||||
if d.is_advance:
|
||||
if d.against_sales_order:
|
||||
advance_paid.setdefault("Sales Order", []).append(d.against_sales_order)
|
||||
elif d.against_purchase_order:
|
||||
advance_paid.setdefault("Purchase Order", []).append(d.against_purchase_order)
|
||||
if d.reference_type in ("Sales Order", "Purchase Order"):
|
||||
advance_paid.setdefault(d.reference_type, []).append(d.reference_name)
|
||||
|
||||
for voucher_type, order_list in advance_paid.items():
|
||||
for voucher_no in list(set(order_list)):
|
||||
@@ -65,7 +60,7 @@ class JournalEntry(AccountsController):
|
||||
|
||||
def on_cancel(self):
|
||||
from erpnext.accounts.utils import remove_against_link_from_jv
|
||||
remove_against_link_from_jv(self.doctype, self.name, "against_jv")
|
||||
remove_against_link_from_jv(self.doctype, self.name)
|
||||
|
||||
self.make_gl_entries(1)
|
||||
self.update_advance_paid()
|
||||
@@ -76,34 +71,31 @@ class JournalEntry(AccountsController):
|
||||
account_type = frappe.db.get_value("Account", d.account, "account_type")
|
||||
if account_type in ["Receivable", "Payable"]:
|
||||
if not (d.party_type and d.party):
|
||||
frappe.throw(_("Row{0}: Party Type and Party is required for Receivable / Payable account {1}").format(d.idx, d.account))
|
||||
frappe.throw(_("Row {0}: Party Type and Party is required for Receivable / Payable account {1}").format(d.idx, d.account))
|
||||
elif d.party_type and d.party:
|
||||
frappe.throw(_("Row{0}: Party Type and Party is only applicable against Receivable / Payable account").format(d.idx))
|
||||
frappe.throw(_("Row {0}: Party Type and Party is only applicable against Receivable / Payable account").format(d.idx))
|
||||
|
||||
def check_credit_limit(self):
|
||||
customers = list(set([d.party for d in self.get("accounts") if d.party_type=="Customer" and flt(d.debit) > 0]))
|
||||
customers = list(set([d.party for d in self.get("accounts")
|
||||
if d.party_type=="Customer" and d.party and flt(d.debit) > 0]))
|
||||
if customers:
|
||||
from erpnext.selling.doctype.customer.customer import check_credit_limit
|
||||
for customer in customers:
|
||||
check_credit_limit(customer, self.company)
|
||||
|
||||
def check_credit_days(self):
|
||||
from erpnext.accounts.party import get_credit_days
|
||||
posting_date = None
|
||||
def check_due_date(self):
|
||||
if self.cheque_date:
|
||||
for d in self.get("accounts"):
|
||||
if d.party_type and d.party and d.get("credit" if d.party_type=="Customer" else "debit") > 0:
|
||||
if d.against_invoice:
|
||||
posting_date = frappe.db.get_value("Sales Invoice", d.against_invoice, "posting_date")
|
||||
elif d.against_voucher:
|
||||
posting_date = frappe.db.get_value("Purchase Invoice", d.against_voucher, "posting_date")
|
||||
due_date = None
|
||||
if d.reference_type in ("Sales Invoice", "Purchase Invoice"):
|
||||
due_date = frappe.db.get_value(d.reference_type, d.reference_name, "due_date")
|
||||
|
||||
credit_days = get_credit_days(d.party_type, d.party, self.company)
|
||||
if posting_date and credit_days:
|
||||
date_diff = (getdate(self.cheque_date) - getdate(posting_date)).days
|
||||
if date_diff > flt(credit_days):
|
||||
msgprint(_("Note: Reference Date exceeds allowed credit days by {0} days for {1} {2}")
|
||||
.format(date_diff - flt(credit_days), d.party_type, d.party))
|
||||
if due_date and getdate(self.cheque_date) > getdate(due_date):
|
||||
diff = date_diff(self.cheque_date, due_date)
|
||||
if diff > 0:
|
||||
msgprint(_("Note: Reference Date exceeds invoice due date by {0} days for {1} {2}")
|
||||
.format(diff, d.party_type, d.party))
|
||||
|
||||
def validate_cheque_info(self):
|
||||
if self.voucher_type in ['Bank Entry']:
|
||||
@@ -116,17 +108,17 @@ class JournalEntry(AccountsController):
|
||||
|
||||
def validate_entries_for_advance(self):
|
||||
for d in self.get('accounts'):
|
||||
if not (d.against_voucher and d.against_invoice and d.against_jv):
|
||||
if d.reference_type not in ("Sales Invoice", "Purchase Invoice", "Journal Entry"):
|
||||
if (d.party_type == 'Customer' and flt(d.credit) > 0) or \
|
||||
(d.party_type == 'Supplier' and flt(d.debit) > 0):
|
||||
if not d.is_advance:
|
||||
if d.is_advance=="No":
|
||||
msgprint(_("Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry.").format(d.idx, d.account))
|
||||
elif (d.against_sales_order or d.against_purchase_order) and d.is_advance != "Yes":
|
||||
elif d.reference_type in ("Sales Order", "Purchase Order") and d.is_advance != "Yes":
|
||||
frappe.throw(_("Row {0}: Payment against Sales/Purchase Order should always be marked as advance").format(d.idx))
|
||||
|
||||
def validate_against_jv(self):
|
||||
for d in self.get('accounts'):
|
||||
if d.against_jv:
|
||||
if d.reference_type=="Journal Entry":
|
||||
account_root_type = frappe.db.get_value("Account", d.account, "root_type")
|
||||
if account_root_type == "Asset" and flt(d.debit) > 0:
|
||||
frappe.throw(_("For {0}, only credit accounts can be linked against another debit entry")
|
||||
@@ -135,17 +127,17 @@ class JournalEntry(AccountsController):
|
||||
frappe.throw(_("For {0}, only debit accounts can be linked against another credit entry")
|
||||
.format(d.account))
|
||||
|
||||
if d.against_jv == self.name:
|
||||
if d.reference_name == self.name:
|
||||
frappe.throw(_("You can not enter current voucher in 'Against Journal Entry' column"))
|
||||
|
||||
against_entries = frappe.db.sql("""select * from `tabJournal Entry Account`
|
||||
where account = %s and docstatus = 1 and parent = %s
|
||||
and ifnull(against_jv, '') = '' and ifnull(against_invoice, '') = ''
|
||||
and ifnull(against_voucher, '') = ''""", (d.account, d.against_jv), as_dict=True)
|
||||
and ifnull(reference_type, '') in ("", "Sales Order", "Purchase Order")
|
||||
""", (d.account, d.reference_name), as_dict=True)
|
||||
|
||||
if not against_entries:
|
||||
frappe.throw(_("Journal Entry {0} does not have account {1} or already matched against other voucher")
|
||||
.format(d.against_jv, d.account))
|
||||
.format(d.reference_name, d.account))
|
||||
else:
|
||||
dr_or_cr = "debit" if d.credit > 0 else "credit"
|
||||
valid = False
|
||||
@@ -154,96 +146,105 @@ class JournalEntry(AccountsController):
|
||||
valid = True
|
||||
if not valid:
|
||||
frappe.throw(_("Against Journal Entry {0} does not have any unmatched {1} entry")
|
||||
.format(d.against_jv, dr_or_cr))
|
||||
.format(d.reference_name, dr_or_cr))
|
||||
|
||||
def validate_against_sales_invoice(self):
|
||||
payment_against_voucher = self.validate_account_in_against_voucher("against_invoice", "Sales Invoice")
|
||||
self.validate_against_invoice_fields("Sales Invoice", payment_against_voucher)
|
||||
|
||||
def validate_against_purchase_invoice(self):
|
||||
payment_against_voucher = self.validate_account_in_against_voucher("against_voucher", "Purchase Invoice")
|
||||
self.validate_against_invoice_fields("Purchase Invoice", payment_against_voucher)
|
||||
|
||||
def validate_against_sales_order(self):
|
||||
payment_against_voucher = self.validate_account_in_against_voucher("against_sales_order", "Sales Order")
|
||||
self.validate_against_order_fields("Sales Order", payment_against_voucher)
|
||||
|
||||
def validate_against_purchase_order(self):
|
||||
payment_against_voucher = self.validate_account_in_against_voucher("against_purchase_order", "Purchase Order")
|
||||
self.validate_against_order_fields("Purchase Order", payment_against_voucher)
|
||||
|
||||
def validate_account_in_against_voucher(self, against_field, doctype):
|
||||
payment_against_voucher = frappe._dict()
|
||||
field_dict = {'Sales Invoice': ["Customer", "Debit To"],
|
||||
def validate_reference_doc(self):
|
||||
"""Validates reference document"""
|
||||
field_dict = {
|
||||
'Sales Invoice': ["Customer", "Debit To"],
|
||||
'Purchase Invoice': ["Supplier", "Credit To"],
|
||||
'Sales Order': ["Customer"],
|
||||
'Purchase Order': ["Supplier"]
|
||||
}
|
||||
}
|
||||
|
||||
self.reference_totals = {}
|
||||
self.reference_types = {}
|
||||
|
||||
for d in self.get("accounts"):
|
||||
if d.get(against_field):
|
||||
dr_or_cr = "credit" if against_field in ["against_invoice", "against_sales_order"] \
|
||||
if not d.reference_type:
|
||||
d.reference_name = None
|
||||
if not d.reference_name:
|
||||
d.reference_type = None
|
||||
if d.reference_type and d.reference_name and (d.reference_type in field_dict.keys()):
|
||||
dr_or_cr = "credit" if d.reference_type in ("Sales Order", "Sales Invoice") \
|
||||
else "debit"
|
||||
if against_field in ["against_invoice", "against_sales_order"] and flt(d.debit) > 0:
|
||||
frappe.throw(_("Row {0}: Debit entry can not be linked with a {1}").format(d.idx, doctype))
|
||||
|
||||
if against_field in ["against_voucher", "against_purchase_order"] and flt(d.credit) > 0:
|
||||
frappe.throw(_("Row {0}: Credit entry can not be linked with a {1}").format(d.idx, doctype))
|
||||
# check debit or credit type Sales / Purchase Order
|
||||
if d.reference_type=="Sales Order" and flt(d.debit) > 0:
|
||||
frappe.throw(_("Row {0}: Debit entry can not be linked with a {1}").format(d.idx, d.reference_type))
|
||||
|
||||
against_voucher = frappe.db.get_value(doctype, d.get(against_field),
|
||||
[scrub(dt) for dt in field_dict.get(doctype)])
|
||||
if d.reference_type == "Purchase Order" and flt(d.credit) > 0:
|
||||
frappe.throw(_("Row {0}: Credit entry can not be linked with a {1}").format(d.idx, d.reference_type))
|
||||
|
||||
if against_field in ["against_invoice", "against_voucher"]:
|
||||
if (against_voucher[0] !=d.party or against_voucher[1] != d.account):
|
||||
frappe.throw(_("Row {0}: Party / Account does not match with \
|
||||
Customer / Debit To in {1}").format(d.idx, doctype))
|
||||
else:
|
||||
payment_against_voucher.setdefault(d.get(against_field), []).append(flt(d.get(dr_or_cr)))
|
||||
# set totals
|
||||
if not d.reference_name in self.reference_totals:
|
||||
self.reference_totals[d.reference_name] = 0.0
|
||||
self.reference_totals[d.reference_name] += flt(d.get(dr_or_cr))
|
||||
self.reference_types[d.reference_name] = d.reference_type
|
||||
|
||||
if against_field in ["against_sales_order", "against_purchase_order"]:
|
||||
against_voucher = frappe.db.get_value(d.reference_type, d.reference_name,
|
||||
[scrub(dt) for dt in field_dict.get(d.reference_type)])
|
||||
|
||||
# check if party and account match
|
||||
if d.reference_type in ("Sales Invoice", "Purchase Invoice"):
|
||||
if (against_voucher[0] != d.party or against_voucher[1] != d.account):
|
||||
frappe.throw(_("Row {0}: Party / Account does not match with {1} / {2} in {3} {4}")
|
||||
.format(d.idx, field_dict.get(d.reference_type)[0], field_dict.get(d.reference_type)[1],
|
||||
d.reference_type, d.reference_name))
|
||||
|
||||
# check if party matches for Sales / Purchase Order
|
||||
if d.reference_type in ("Sales Order", "Purchase Order"):
|
||||
# set totals
|
||||
if against_voucher != d.party:
|
||||
frappe.throw(_("Row {0}: {1} {2} does not match with {3}") \
|
||||
.format(d.idx, d.party_type, d.party, doctype))
|
||||
elif d.is_advance == "Yes":
|
||||
payment_against_voucher.setdefault(d.get(against_field), []).append(flt(d.get(dr_or_cr)))
|
||||
.format(d.idx, d.party_type, d.party, d.reference_type))
|
||||
|
||||
return payment_against_voucher
|
||||
self.validate_orders()
|
||||
self.validate_invoices()
|
||||
|
||||
def validate_against_invoice_fields(self, doctype, payment_against_voucher):
|
||||
for voucher_no, payment_list in payment_against_voucher.items():
|
||||
voucher_properties = frappe.db.get_value(doctype, voucher_no,
|
||||
["docstatus", "outstanding_amount"])
|
||||
def validate_orders(self):
|
||||
"""Validate totals, stopped and docstatus for orders"""
|
||||
for reference_name, total in self.reference_totals.iteritems():
|
||||
reference_type = self.reference_types[reference_name]
|
||||
|
||||
if voucher_properties[0] != 1:
|
||||
frappe.throw(_("{0} {1} is not submitted").format(doctype, voucher_no))
|
||||
if reference_type in ("Sales Order", "Purchase Order"):
|
||||
voucher_properties = frappe.db.get_value(reference_type, reference_name,
|
||||
["docstatus", "per_billed", "status", "advance_paid", "base_grand_total"])
|
||||
|
||||
if flt(voucher_properties[1]) < flt(sum(payment_list)):
|
||||
frappe.throw(_("Payment against {0} {1} cannot be greater \
|
||||
than Outstanding Amount {2}").format(doctype, voucher_no, voucher_properties[1]))
|
||||
if voucher_properties[0] != 1:
|
||||
frappe.throw(_("{0} {1} is not submitted").format(reference_type, reference_name))
|
||||
|
||||
def validate_against_order_fields(self, doctype, payment_against_voucher):
|
||||
for voucher_no, payment_list in payment_against_voucher.items():
|
||||
voucher_properties = frappe.db.get_value(doctype, voucher_no,
|
||||
["docstatus", "per_billed", "status", "advance_paid", "base_grand_total"])
|
||||
if flt(voucher_properties[1]) >= 100:
|
||||
frappe.throw(_("{0} {1} is fully billed").format(reference_type, reference_name))
|
||||
|
||||
if voucher_properties[0] != 1:
|
||||
frappe.throw(_("{0} {1} is not submitted").format(doctype, voucher_no))
|
||||
if cstr(voucher_properties[2]) == "Stopped":
|
||||
frappe.throw(_("{0} {1} is stopped").format(reference_type, reference_name))
|
||||
|
||||
if flt(voucher_properties[1]) >= 100:
|
||||
frappe.throw(_("{0} {1} is fully billed").format(doctype, voucher_no))
|
||||
if flt(voucher_properties[4]) < (flt(voucher_properties[3]) + total):
|
||||
frappe.throw(_("Advance paid against {0} {1} cannot be greater \
|
||||
than Grand Total {2}").format(reference_type, reference_name, voucher_properties[4]))
|
||||
|
||||
if cstr(voucher_properties[2]) == "Stopped":
|
||||
frappe.throw(_("{0} {1} is stopped").format(doctype, voucher_no))
|
||||
def validate_invoices(self):
|
||||
"""Validate totals and docstatus for invoices"""
|
||||
for reference_name, total in self.reference_totals.iteritems():
|
||||
reference_type = self.reference_types[reference_name]
|
||||
|
||||
if flt(voucher_properties[4]) < flt(voucher_properties[3]) + flt(sum(payment_list)):
|
||||
frappe.throw(_("Advance paid against {0} {1} cannot be greater \
|
||||
than Grand Total {2}").format(doctype, voucher_no, voucher_properties[3]))
|
||||
if reference_type in ("Sales Invoice", "Purchase Invoice"):
|
||||
voucher_properties = frappe.db.get_value(reference_type, reference_name,
|
||||
["docstatus", "outstanding_amount"])
|
||||
|
||||
if voucher_properties[0] != 1:
|
||||
frappe.throw(_("{0} {1} is not submitted").format(reference_type, reference_name))
|
||||
|
||||
if flt(voucher_properties[1]) < total:
|
||||
frappe.throw(_("Payment against {0} {1} cannot be greater \
|
||||
than Outstanding Amount {2}").format(reference_type, reference_name, voucher_properties[1]))
|
||||
|
||||
def set_against_account(self):
|
||||
accounts_debited, accounts_credited = [], []
|
||||
for d in self.get("accounts"):
|
||||
if flt(d.debit > 0): accounts_debited.append(d.account)
|
||||
if flt(d.credit) > 0: accounts_credited.append(d.account)
|
||||
if flt(d.debit > 0): accounts_debited.append(d.party or d.account)
|
||||
if flt(d.credit) > 0: accounts_credited.append(d.party or d.account)
|
||||
|
||||
for d in self.get("accounts"):
|
||||
if flt(d.debit > 0): d.against_account = ", ".join(list(set(accounts_credited)))
|
||||
@@ -274,30 +275,28 @@ class JournalEntry(AccountsController):
|
||||
else:
|
||||
msgprint(_("Please enter Reference date"), raise_exception=frappe.MandatoryError)
|
||||
|
||||
company_currency = get_company_currency(self.company)
|
||||
|
||||
for d in self.get('accounts'):
|
||||
if d.against_invoice and d.credit:
|
||||
currency = frappe.db.get_value("Sales Invoice", d.against_invoice, "currency")
|
||||
if d.reference_type=="Sales Invoice" and d.credit:
|
||||
r.append(_("{0} against Sales Invoice {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
|
||||
d.reference_name))
|
||||
|
||||
r.append(_("{0} against Sales Invoice {1}").format(fmt_money(flt(d.credit), currency = currency), \
|
||||
d.against_invoice))
|
||||
if d.reference_type=="Sales Order" and d.credit:
|
||||
r.append(_("{0} against Sales Order {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
|
||||
d.reference_name))
|
||||
|
||||
if d.against_sales_order and d.credit:
|
||||
currency = frappe.db.get_value("Sales Order", d.against_sales_order, "currency")
|
||||
r.append(_("{0} against Sales Order {1}").format(fmt_money(flt(d.credit), currency = currency), \
|
||||
d.against_sales_order))
|
||||
|
||||
if d.against_voucher and d.debit:
|
||||
bill_no = frappe.db.sql("""select bill_no, bill_date, currency
|
||||
from `tabPurchase Invoice` where name=%s""", d.against_voucher)
|
||||
if d.reference_type == "Purchase Invoice" and d.debit:
|
||||
bill_no = frappe.db.sql("""select bill_no, bill_date
|
||||
from `tabPurchase Invoice` where name=%s""", d.reference_name)
|
||||
if bill_no and bill_no[0][0] and bill_no[0][0].lower().strip() \
|
||||
not in ['na', 'not applicable', 'none']:
|
||||
r.append(_('{0} against Bill {1} dated {2}').format(fmt_money(flt(d.debit), currency=bill_no[0][2]), bill_no[0][0],
|
||||
r.append(_('{0} against Bill {1} dated {2}').format(fmt_money(flt(d.debit), currency=company_currency), bill_no[0][0],
|
||||
bill_no[0][1] and formatdate(bill_no[0][1].strftime('%Y-%m-%d'))))
|
||||
|
||||
if d.against_purchase_order and d.debit:
|
||||
currency = frappe.db.get_value("Purchase Order", d.against_purchase_order, "currency")
|
||||
r.append(_("{0} against Purchase Order {1}").format(fmt_money(flt(d.credit), currency = currency), \
|
||||
d.against_purchase_order))
|
||||
if d.reference_type == "Purchase Order" and d.debit:
|
||||
r.append(_("{0} against Purchase Order {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
|
||||
d.reference_name))
|
||||
|
||||
if self.user_remark:
|
||||
r.append(_("Note: {0}").format(self.user_remark))
|
||||
@@ -336,13 +335,8 @@ class JournalEntry(AccountsController):
|
||||
"against": d.against_account,
|
||||
"debit": flt(d.debit, self.precision("debit", "accounts")),
|
||||
"credit": flt(d.credit, self.precision("credit", "accounts")),
|
||||
"against_voucher_type": (("Purchase Invoice" if d.against_voucher else None)
|
||||
or ("Sales Invoice" if d.against_invoice else None)
|
||||
or ("Journal Entry" if d.against_jv else None)
|
||||
or ("Sales Order" if d.against_sales_order else None)
|
||||
or ("Purchase Order" if d.against_purchase_order else None)),
|
||||
"against_voucher": d.against_voucher or d.against_invoice or d.against_jv
|
||||
or d.against_sales_order or d.against_purchase_order,
|
||||
"against_voucher_type": d.reference_type,
|
||||
"against_voucher": d.reference_name,
|
||||
"remarks": self.remark,
|
||||
"cost_center": d.cost_center
|
||||
})
|
||||
@@ -389,11 +383,13 @@ class JournalEntry(AccountsController):
|
||||
if self.write_off_based_on == 'Accounts Receivable':
|
||||
jd1.party_type = "Customer"
|
||||
jd1.credit = flt(d.outstanding_amount, self.precision("credit", "accounts"))
|
||||
jd1.against_invoice = cstr(d.name)
|
||||
jd1.reference_type = "Sales Invoice"
|
||||
jd1.reference_name = cstr(d.name)
|
||||
elif self.write_off_based_on == 'Accounts Payable':
|
||||
jd1.party_type = "Supplier"
|
||||
jd1.debit = flt(d.outstanding_amount, self.precision("debit", "accounts"))
|
||||
jd1.against_voucher = cstr(d.name)
|
||||
jd1.reference_type = "Purchase Invoice"
|
||||
jd1.reference_name = cstr(d.name)
|
||||
|
||||
jd2 = self.append('accounts', {})
|
||||
if self.write_off_based_on == 'Accounts Receivable':
|
||||
@@ -419,26 +415,26 @@ class JournalEntry(AccountsController):
|
||||
|
||||
def update_expense_claim(self):
|
||||
for d in self.accounts:
|
||||
if d.against_expense_claim:
|
||||
if d.reference_type=="Expense Claim":
|
||||
amt = frappe.db.sql("""select sum(debit) as amt from `tabJournal Entry Account`
|
||||
where against_expense_claim = %s and docstatus = 1""", d.against_expense_claim ,as_dict=1)[0].amt
|
||||
frappe.db.set_value("Expense Claim", d.against_expense_claim , "total_amount_reimbursed", amt)
|
||||
where reference_type = "Expense Claim" and
|
||||
reference_name = %s and docstatus = 1""", d.reference_name ,as_dict=1)[0].amt
|
||||
frappe.db.set_value("Expense Claim", d.reference_name , "total_amount_reimbursed", amt)
|
||||
|
||||
def validate_expense_claim(self):
|
||||
for d in self.accounts:
|
||||
if d.against_expense_claim:
|
||||
sanctioned_amount, reimbursed_amount = frappe.db.get_value("Expense Claim", d.against_expense_claim,
|
||||
("total_sanctioned_amount", "total_amount_reimbursed"))
|
||||
pending_amount = cint(sanctioned_amount) - cint(reimbursed_amount)
|
||||
if d.reference_type=="Expense Claim":
|
||||
sanctioned_amount, reimbursed_amount = frappe.db.get_value("Expense Claim",
|
||||
d.reference_name, ("total_sanctioned_amount", "total_amount_reimbursed"))
|
||||
pending_amount = flt(sanctioned_amount) - flt(reimbursed_amount)
|
||||
if d.debit > pending_amount:
|
||||
frappe.throw(_("Row No {0}: Amount cannot be greater than Pending Amount against Expense Claim {1}. \
|
||||
Pending Amount is {2}".format(d.idx, d.against_expense_claim, pending_amount)))
|
||||
frappe.throw(_("Row No {0}: Amount cannot be greater than Pending Amount against Expense Claim {1}. Pending Amount is {2}".format(d.idx, d.reference_name, pending_amount)))
|
||||
|
||||
def validate_credit_debit_note(self):
|
||||
if self.stock_entry:
|
||||
if frappe.db.get_value("Stock Entry", self.stock_entry, "docstatus") != 1:
|
||||
frappe.throw(_("Stock Entry {0} is not submitted").format(self.stock_entry))
|
||||
|
||||
|
||||
if frappe.db.exists({"doctype": "Journal Entry", "stock_entry": self.stock_entry, "docstatus":1}):
|
||||
frappe.msgprint(_("Warning: Another {0} # {1} exists against stock entry {2}".format(self.voucher_type, self.name, self.stock_entry)))
|
||||
|
||||
@@ -458,11 +454,11 @@ def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None):
|
||||
if voucher_type=="Bank Entry":
|
||||
account = frappe.db.get_value("Company", company, "default_bank_account")
|
||||
if not account:
|
||||
account = frappe.db.get_value("Account", {"company": company, "account_type": "Bank"})
|
||||
account = frappe.db.get_value("Account", {"company": company, "account_type": "Bank", "is_group": 0})
|
||||
elif voucher_type=="Cash Entry":
|
||||
account = frappe.db.get_value("Company", company, "default_cash_account")
|
||||
if not account:
|
||||
account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash"})
|
||||
account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash", "is_group": 0})
|
||||
|
||||
if account:
|
||||
return {
|
||||
@@ -472,6 +468,7 @@ def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_payment_entry_from_sales_invoice(sales_invoice):
|
||||
"""Returns new Journal Entry document as dict for given Sales Invoice"""
|
||||
from erpnext.accounts.utils import get_balance_on
|
||||
si = frappe.get_doc("Sales Invoice", sales_invoice)
|
||||
jv = get_payment_entry(si)
|
||||
@@ -484,7 +481,8 @@ def get_payment_entry_from_sales_invoice(sales_invoice):
|
||||
jv.get("accounts")[0].balance = get_balance_on(si.debit_to)
|
||||
jv.get("accounts")[0].party_balance = get_balance_on(party=si.customer, party_type="Customer")
|
||||
jv.get("accounts")[0].credit = si.outstanding_amount
|
||||
jv.get("accounts")[0].against_invoice = si.name
|
||||
jv.get("accounts")[0].reference_type = si.doctype
|
||||
jv.get("accounts")[0].reference_name = si.name
|
||||
|
||||
# debit bank
|
||||
jv.get("accounts")[1].debit = si.outstanding_amount
|
||||
@@ -493,6 +491,7 @@ def get_payment_entry_from_sales_invoice(sales_invoice):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_payment_entry_from_purchase_invoice(purchase_invoice):
|
||||
"""Returns new Journal Entry document as dict for given Purchase Invoice"""
|
||||
pi = frappe.get_doc("Purchase Invoice", purchase_invoice)
|
||||
jv = get_payment_entry(pi)
|
||||
jv.remark = 'Payment against Purchase Invoice {0}. {1}'.format(pi.name, pi.remarks)
|
||||
@@ -504,13 +503,78 @@ def get_payment_entry_from_purchase_invoice(purchase_invoice):
|
||||
jv.get("accounts")[0].balance = get_balance_on(pi.credit_to)
|
||||
jv.get("accounts")[0].party_balance = get_balance_on(party=pi.supplier, party_type="Supplier")
|
||||
jv.get("accounts")[0].debit = pi.outstanding_amount
|
||||
jv.get("accounts")[0].against_voucher = pi.name
|
||||
jv.get("accounts")[0].reference_type = pi.doctype
|
||||
jv.get("accounts")[0].reference_name = pi.name
|
||||
|
||||
# credit bank
|
||||
jv.get("accounts")[1].credit = pi.outstanding_amount
|
||||
|
||||
return jv.as_dict()
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_payment_entry_from_sales_order(sales_order):
|
||||
"""Returns new Journal Entry document as dict for given Sales Order"""
|
||||
from erpnext.accounts.utils import get_balance_on
|
||||
from erpnext.accounts.party import get_party_account
|
||||
so = frappe.get_doc("Sales Order", sales_order)
|
||||
|
||||
if flt(so.per_billed, 2) != 0.0:
|
||||
frappe.throw(_("Can only make payment against unbilled Sales Order"))
|
||||
|
||||
jv = get_payment_entry(so)
|
||||
jv.remark = 'Advance payment received against Sales Order {0}.'.format(so.name)
|
||||
party_account = get_party_account(so.company, so.customer, "Customer")
|
||||
|
||||
amount = flt(so.base_grand_total) - flt(so.advance_paid)
|
||||
|
||||
# credit customer
|
||||
jv.get("accounts")[0].account = party_account
|
||||
jv.get("accounts")[0].party_type = "Customer"
|
||||
jv.get("accounts")[0].party = so.customer
|
||||
jv.get("accounts")[0].balance = get_balance_on(party_account)
|
||||
jv.get("accounts")[0].party_balance = get_balance_on(party=so.customer, party_type="Customer")
|
||||
jv.get("accounts")[0].credit = amount
|
||||
jv.get("accounts")[0].reference_type = so.doctype
|
||||
jv.get("accounts")[0].reference_name = so.name
|
||||
jv.get("accounts")[0].is_advance = "Yes"
|
||||
|
||||
# debit bank
|
||||
jv.get("accounts")[1].debit = amount
|
||||
|
||||
return jv.as_dict()
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_payment_entry_from_purchase_order(purchase_order):
|
||||
"""Returns new Journal Entry document as dict for given Sales Order"""
|
||||
from erpnext.accounts.utils import get_balance_on
|
||||
from erpnext.accounts.party import get_party_account
|
||||
po = frappe.get_doc("Purchase Order", purchase_order)
|
||||
|
||||
if flt(po.per_billed, 2) != 0.0:
|
||||
frappe.throw(_("Can only make payment against unbilled Sales Order"))
|
||||
|
||||
jv = get_payment_entry(po)
|
||||
jv.remark = 'Advance payment made against Purchase Order {0}.'.format(po.name)
|
||||
party_account = get_party_account(po.company, po.supplier, "Supplier")
|
||||
|
||||
amount = flt(po.base_grand_total) - flt(po.advance_paid)
|
||||
|
||||
# credit customer
|
||||
jv.get("accounts")[0].account = party_account
|
||||
jv.get("accounts")[0].party_type = "Supplier"
|
||||
jv.get("accounts")[0].party = po.supplier
|
||||
jv.get("accounts")[0].balance = get_balance_on(party_account)
|
||||
jv.get("accounts")[0].party_balance = get_balance_on(party=po.supplier, party_type="Supplier")
|
||||
jv.get("accounts")[0].debit = amount
|
||||
jv.get("accounts")[0].reference_type = po.doctype
|
||||
jv.get("accounts")[0].reference_name = po.name
|
||||
jv.get("accounts")[0].is_advance = "Yes"
|
||||
|
||||
# debit bank
|
||||
jv.get("accounts")[1].credit = amount
|
||||
|
||||
return jv.as_dict()
|
||||
|
||||
def get_payment_entry(doc):
|
||||
bank_account = get_default_bank_cash_account(doc.company, "Bank Entry")
|
||||
|
||||
@@ -538,43 +602,46 @@ def get_opening_accounts(company):
|
||||
|
||||
|
||||
def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
|
||||
if not filters.get("party"):
|
||||
return []
|
||||
return frappe.db.sql("""select jv.name, jv.posting_date, jv.user_remark
|
||||
from `tabJournal Entry` jv, `tabJournal Entry Account` jv_detail
|
||||
where jv_detail.parent = jv.name and jv_detail.account = %s and jv_detail.party = %s
|
||||
and (ifnull(jv_detail.against_invoice, '') = '' and ifnull(jv_detail.against_voucher, '') = ''
|
||||
and ifnull(jv_detail.against_jv, '') = '' )
|
||||
where jv_detail.parent = jv.name and jv_detail.account = %s and ifnull(jv_detail.party, '') = %s
|
||||
and ifnull(jv_detail.reference_type, '') = ''
|
||||
and jv.docstatus = 1 and jv.{0} like %s order by jv.name desc limit %s, %s""".format(searchfield),
|
||||
(filters["account"], filters["party"], "%{0}%".format(txt), start, page_len))
|
||||
(filters.get("account"), cstr(filters.get("party")), "%{0}%".format(txt), start, page_len))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_outstanding(args):
|
||||
if not frappe.has_permission("Account"):
|
||||
frappe.msgprint(_("No Permission"), raise_exception=1)
|
||||
args = eval(args)
|
||||
if args.get("doctype") == "Journal Entry" and args.get("party"):
|
||||
if args.get("doctype") == "Journal Entry":
|
||||
condition = " and party=%(party)s" if args.get("party") else ""
|
||||
|
||||
against_jv_amount = frappe.db.sql("""
|
||||
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
||||
from `tabJournal Entry Account` where parent=%s and party=%s
|
||||
and ifnull(against_invoice, '')='' and ifnull(against_voucher, '')=''
|
||||
and ifnull(against_jv, '')=''""", (args['docname'], args['party']))
|
||||
from `tabJournal Entry Account` where parent=%(docname)s and account=%(account)s {0}
|
||||
and ifnull(reference_type, '')=''""".format(condition), args)
|
||||
|
||||
against_jv_amount = flt(against_jv_amount[0][0]) if against_jv_amount else 0
|
||||
if against_jv_amount > 0:
|
||||
return {"credit": against_jv_amount}
|
||||
else:
|
||||
return {"debit": -1* against_jv_amount}
|
||||
|
||||
elif args.get("doctype") == "Sales Invoice":
|
||||
return {
|
||||
"credit": flt(frappe.db.get_value("Sales Invoice", args["docname"], "outstanding_amount"))
|
||||
("credit" if against_jv_amount > 0 else "debit"): abs(against_jv_amount)
|
||||
}
|
||||
elif args.get("doctype") == "Sales Invoice":
|
||||
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", args["docname"], "outstanding_amount"))
|
||||
return {
|
||||
("credit" if outstanding_amount > 0 else "debit"): abs(outstanding_amount)
|
||||
}
|
||||
elif args.get("doctype") == "Purchase Invoice":
|
||||
outstanding_amount = flt(frappe.db.get_value("Purchase Invoice", args["docname"], "outstanding_amount"))
|
||||
return {
|
||||
"debit": flt(frappe.db.get_value("Purchase Invoice", args["docname"], "outstanding_amount"))
|
||||
("debit" if outstanding_amount > 0 else "credit"): abs(outstanding_amount)
|
||||
}
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_party_account_and_balance(company, party_type, party):
|
||||
if not frappe.has_permission("Account"):
|
||||
frappe.msgprint(_("No Permission"), raise_exception=1)
|
||||
|
||||
from erpnext.accounts.party import get_party_account
|
||||
account = get_party_account(company, party, party_type)
|
||||
|
||||
@@ -586,3 +653,16 @@ def get_party_account_and_balance(company, party_type, party):
|
||||
"balance": account_balance,
|
||||
"party_balance": party_balance
|
||||
}
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_account_balance_and_party_type(account, date):
|
||||
"""Returns dict of account balance and party type to be set in Journal Entry on selection of account."""
|
||||
if not frappe.has_permission("Account"):
|
||||
frappe.msgprint(_("No Permission"), raise_exception=1)
|
||||
|
||||
account_type = frappe.db.get_value("Account", account, "account_type")
|
||||
return {
|
||||
"balance": get_balance_on(account, date),
|
||||
"party_type": {"Receivable":"Customer", "Payable":"Supplier"}.get(account_type, "")
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,6 @@ class TestJournalEntry(unittest.TestCase):
|
||||
|
||||
def jv_against_voucher_testcase(self, base_jv, test_voucher):
|
||||
dr_or_cr = "credit" if test_voucher.doctype in ["Sales Order", "Journal Entry"] else "debit"
|
||||
field_dict = {'Journal Entry': "against_jv",
|
||||
'Sales Order': "against_sales_order",
|
||||
'Purchase Order': "against_purchase_order"
|
||||
}
|
||||
|
||||
test_voucher.insert()
|
||||
test_voucher.submit()
|
||||
@@ -42,21 +38,20 @@ class TestJournalEntry(unittest.TestCase):
|
||||
where account = %s and docstatus = 1 and parent = %s""",
|
||||
("_Test Receivable - _TC", test_voucher.name)))
|
||||
|
||||
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||
where %s=%s""" % (field_dict.get(test_voucher.doctype), '%s'), (test_voucher.name)))
|
||||
self.assertFalse(frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||
where reference_type = %s and reference_name = %s""", (test_voucher.doctype, test_voucher.name)))
|
||||
|
||||
base_jv.get("accounts")[0].is_advance = "Yes" if (test_voucher.doctype in ["Sales Order", "Purchase Order"]) else "No"
|
||||
base_jv.get("accounts")[0].set(field_dict.get(test_voucher.doctype), test_voucher.name)
|
||||
base_jv.get("accounts")[0].set("reference_type", test_voucher.doctype)
|
||||
base_jv.get("accounts")[0].set("reference_name", test_voucher.name)
|
||||
base_jv.insert()
|
||||
base_jv.submit()
|
||||
|
||||
submitted_voucher = frappe.get_doc(test_voucher.doctype, test_voucher.name)
|
||||
|
||||
self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||
where %s=%s""" % (field_dict.get(test_voucher.doctype), '%s'), (submitted_voucher.name)))
|
||||
|
||||
self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||
where %s=%s and %s=400""" % (field_dict.get(submitted_voucher.doctype), '%s', dr_or_cr), (submitted_voucher.name)))
|
||||
where reference_type = %s and reference_name = %s and {0}=400""".format(dr_or_cr),
|
||||
(submitted_voucher.doctype, submitted_voucher.name)))
|
||||
|
||||
if base_jv.get("accounts")[0].is_advance == "Yes":
|
||||
self.advance_paid_testcase(base_jv, submitted_voucher, dr_or_cr)
|
||||
@@ -74,8 +69,8 @@ class TestJournalEntry(unittest.TestCase):
|
||||
if test_voucher.doctype == "Journal Entry":
|
||||
# if test_voucher is a Journal Entry, test cancellation of test_voucher
|
||||
test_voucher.cancel()
|
||||
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||
where against_jv=%s""", test_voucher.name))
|
||||
self.assertFalse(frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||
where reference_type='Journal Entry' and reference_name=%s""", test_voucher.name))
|
||||
|
||||
elif test_voucher.doctype in ["Sales Order", "Purchase Order"]:
|
||||
# if test_voucher is a Sales Order/Purchase Order, test error on cancellation of test_voucher
|
||||
@@ -102,23 +97,23 @@ class TestJournalEntry(unittest.TestCase):
|
||||
|
||||
def test_monthly_budget_crossed_ignore(self):
|
||||
frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore")
|
||||
|
||||
|
||||
self.set_total_expense_zero("2013-02-28")
|
||||
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Account Bank Account - _TC", 40000, "_Test Cost Center - _TC", submit=True)
|
||||
|
||||
|
||||
self.assertTrue(frappe.db.get_value("GL Entry",
|
||||
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
|
||||
|
||||
def test_monthly_budget_crossed_stop(self):
|
||||
frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Stop")
|
||||
|
||||
|
||||
self.set_total_expense_zero("2013-02-28")
|
||||
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Account Bank Account - _TC", 40000, "_Test Cost Center - _TC")
|
||||
|
||||
|
||||
self.assertRaises(BudgetError, jv.submit)
|
||||
|
||||
frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore")
|
||||
@@ -127,37 +122,37 @@ class TestJournalEntry(unittest.TestCase):
|
||||
self.test_monthly_budget_crossed_ignore()
|
||||
|
||||
frappe.db.set_value("Company", "_Test Company", "yearly_bgt_flag", "Stop")
|
||||
|
||||
|
||||
self.set_total_expense_zero("2013-02-28")
|
||||
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Account Bank Account - _TC", 150000, "_Test Cost Center - _TC")
|
||||
|
||||
|
||||
self.assertRaises(BudgetError, jv.submit)
|
||||
|
||||
frappe.db.set_value("Company", "_Test Company", "yearly_bgt_flag", "Ignore")
|
||||
|
||||
def test_monthly_budget_on_cancellation(self):
|
||||
self.set_total_expense_zero("2013-02-28")
|
||||
|
||||
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
|
||||
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Account Bank Account - _TC", 20000, "_Test Cost Center - _TC", submit=True)
|
||||
|
||||
|
||||
self.assertTrue(frappe.db.get_value("GL Entry",
|
||||
{"voucher_type": "Journal Entry", "voucher_no": jv1.name}))
|
||||
|
||||
jv2 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
|
||||
jv2 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Account Bank Account - _TC", 20000, "_Test Cost Center - _TC", submit=True)
|
||||
|
||||
|
||||
self.assertTrue(frappe.db.get_value("GL Entry",
|
||||
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
|
||||
|
||||
|
||||
frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Stop")
|
||||
|
||||
self.assertRaises(BudgetError, jv1.cancel)
|
||||
|
||||
frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore")
|
||||
|
||||
|
||||
def get_actual_expense(self, monthly_end_date):
|
||||
return get_actual_expense({
|
||||
"account": "_Test Account Cost for Goods Sold - _TC",
|
||||
@@ -166,19 +161,19 @@ class TestJournalEntry(unittest.TestCase):
|
||||
"company": "_Test Company",
|
||||
"fiscal_year": get_fiscal_year(monthly_end_date)[0]
|
||||
})
|
||||
|
||||
|
||||
def set_total_expense_zero(self, posting_date):
|
||||
existing_expense = self.get_actual_expense(posting_date)
|
||||
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Account Bank Account - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True)
|
||||
|
||||
|
||||
def make_journal_entry(account1, account2, amount, cost_center=None, submit=False):
|
||||
jv = frappe.new_doc("Journal Entry")
|
||||
jv.posting_date = "2013-02-14"
|
||||
jv.company = "_Test Company"
|
||||
jv.fiscal_year = "_Test Fiscal Year 2013"
|
||||
jv.user_remark = "test"
|
||||
|
||||
|
||||
jv.set("accounts", [
|
||||
{
|
||||
"account": account1,
|
||||
@@ -193,11 +188,11 @@ def make_journal_entry(account1, account2, amount, cost_center=None, submit=Fals
|
||||
}
|
||||
])
|
||||
jv.insert()
|
||||
|
||||
|
||||
if submit:
|
||||
jv.submit()
|
||||
|
||||
|
||||
return jv
|
||||
|
||||
|
||||
|
||||
test_records = frappe.get_test_records('Journal Entry')
|
||||
|
||||
@@ -1,27 +1,44 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "hash",
|
||||
"creation": "2013-02-22 01:27:39",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Account",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_width": "250px",
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 1,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"width": "250px"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "balance",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Account Balance",
|
||||
"no_copy": 1,
|
||||
@@ -30,186 +47,336 @@
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"default": ":Company",
|
||||
"description": "If Income or Expense",
|
||||
"fieldname": "cost_center",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Cost Center",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "cost_center",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Cost Center",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_width": "180px",
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"width": "180px"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "col_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "party_type",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Party Type",
|
||||
"no_copy": 0,
|
||||
"options": "DocType",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "party",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Party",
|
||||
"no_copy": 0,
|
||||
"options": "party_type",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "party_balance",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Party Balance",
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"read_only": 1
|
||||
"print_hide": 0,
|
||||
"read_only": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "sec_break1",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Amount",
|
||||
"permlevel": 0
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "debit",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Debit",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "debit",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "col_break2",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "credit",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Credit",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "credit",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "reference",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Reference",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "against_invoice",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"label": "Against Sales Invoice",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "against_invoice",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Sales Invoice",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"search_index": 1
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "against_voucher",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Against Purchase Invoice",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "against_voucher",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Purchase Invoice",
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "reference_type",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Reference Type",
|
||||
"no_copy": 0,
|
||||
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"search_index": 1
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "against_jv",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"label": "Against Journal Entry",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "against_jv",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Journal Entry",
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "reference_name",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Reference Name",
|
||||
"no_copy": 0,
|
||||
"options": "reference_type",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"search_index": 1
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "col_break3",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "against_sales_order",
|
||||
"fieldtype": "Link",
|
||||
"label": "Against Sales Order",
|
||||
"options": "Sales Order",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "against_purchase_order",
|
||||
"fieldtype": "Link",
|
||||
"label": "Against Purchase Order",
|
||||
"options": "Purchase Order",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "against_expense_claim",
|
||||
"fieldtype": "Link",
|
||||
"label": "Against Expense Claim",
|
||||
"options": "Expense Claim",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "is_advance",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Is Advance",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "is_advance",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "No\nYes",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "against_account",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Against Account",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "against_account",
|
||||
"oldfieldtype": "Text",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 1,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"modified": "2015-02-19 01:07:00.388689",
|
||||
"modified": "2015-08-11 10:44:11.432623",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Journal Entry Account",
|
||||
"owner": "Administrator",
|
||||
"permissions": []
|
||||
"permissions": [],
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0
|
||||
}
|
||||
@@ -44,6 +44,10 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
refresh: function() {
|
||||
this.frm.disable_save();
|
||||
},
|
||||
|
||||
party: function() {
|
||||
var me = this
|
||||
|
||||
@@ -34,8 +34,8 @@ class PaymentReconciliation(Document):
|
||||
t1.name = t2.parent and t1.docstatus = 1 and t2.docstatus = 1
|
||||
and t2.party_type = %(party_type)s and t2.party = %(party)s
|
||||
and t2.account = %(account)s and {dr_or_cr} > 0
|
||||
and ifnull(t2.against_voucher, '')='' and ifnull(t2.against_invoice, '')=''
|
||||
and ifnull(t2.against_jv, '')='' {cond}
|
||||
and ifnull(t2.reference_type, '') in ('', 'Sales Order', 'Purchase Order')
|
||||
{cond}
|
||||
and (CASE
|
||||
WHEN t1.voucher_type in ('Debit Note', 'Credit Note')
|
||||
THEN 1=1
|
||||
@@ -191,9 +191,10 @@ class PaymentReconciliation(Document):
|
||||
frappe.throw(_("Row {0}: Allocated amount {1} must be less than or equals to JV amount {2}")
|
||||
.format(p.idx, p.allocated_amount, p.amount))
|
||||
|
||||
if flt(p.allocated_amount) > unreconciled_invoices.get(p.invoice_type, {}).get(p.invoice_number):
|
||||
invoice_outstanding = unreconciled_invoices.get(p.invoice_type, {}).get(p.invoice_number)
|
||||
if flt(p.allocated_amount) - invoice_outstanding > 0.009:
|
||||
frappe.throw(_("Row {0}: Allocated amount {1} must be less than or equals to invoice outstanding amount {2}")
|
||||
.format(p.idx, p.allocated_amount, unreconciled_invoices.get(p.invoice_type, {}).get(p.invoice_number)))
|
||||
.format(p.idx, p.allocated_amount, invoice_outstanding))
|
||||
|
||||
if not invoices_to_reconcile:
|
||||
frappe.throw(_("Please select Allocated Amount, Invoice Type and Invoice Number in atleast one row"))
|
||||
|
||||
@@ -32,6 +32,7 @@ frappe.ui.form.on("Payment Tool", "onload", function(frm) {
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Payment Tool", "refresh", function(frm) {
|
||||
frm.disable_save();
|
||||
frappe.ui.form.trigger("Payment Tool", "party_type");
|
||||
});
|
||||
|
||||
|
||||
@@ -312,7 +312,7 @@
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"modified": "2015-02-21 03:59:08.154966",
|
||||
"modified": "2015-06-05 11:17:33.843334",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Tool",
|
||||
|
||||
@@ -12,13 +12,6 @@ class PaymentTool(Document):
|
||||
def make_journal_entry(self):
|
||||
from erpnext.accounts.utils import get_balance_on
|
||||
total_payment_amount = 0.00
|
||||
invoice_voucher_type = {
|
||||
'Sales Invoice': 'against_invoice',
|
||||
'Purchase Invoice': 'against_voucher',
|
||||
'Journal Entry': 'against_jv',
|
||||
'Sales Order': 'against_sales_order',
|
||||
'Purchase Order': 'against_purchase_order',
|
||||
}
|
||||
|
||||
jv = frappe.new_doc('Journal Entry')
|
||||
jv.voucher_type = 'Journal Entry'
|
||||
@@ -41,7 +34,8 @@ class PaymentTool(Document):
|
||||
d1.party = self.party
|
||||
d1.balance = get_balance_on(self.party_account)
|
||||
d1.set("debit" if self.received_or_paid=="Paid" else "credit", flt(v.payment_amount))
|
||||
d1.set(invoice_voucher_type.get(v.against_voucher_type), v.against_voucher_no)
|
||||
d1.set("reference_type", v.against_voucher_type)
|
||||
d1.set("reference_name", v.against_voucher_no)
|
||||
d1.set('is_advance', 'Yes' if v.against_voucher_type in ['Sales Order', 'Purchase Order'] else 'No')
|
||||
total_payment_amount = flt(total_payment_amount) + flt(d1.debit) - flt(d1.credit)
|
||||
|
||||
|
||||
@@ -23,10 +23,11 @@ class TestPaymentTool(unittest.TestCase):
|
||||
|
||||
# Create SO with partial outstanding
|
||||
so1 = make_sales_order(customer="_Test Customer 3", qty=10, rate=100)
|
||||
|
||||
|
||||
self.create_against_jv(jv_test_records[0], {
|
||||
"party": "_Test Customer 3",
|
||||
"against_sales_order": so1.name,
|
||||
"reference_type": "Sales Order",
|
||||
"reference_name": so1.name,
|
||||
"is_advance": "Yes"
|
||||
})
|
||||
|
||||
@@ -36,7 +37,8 @@ class TestPaymentTool(unittest.TestCase):
|
||||
|
||||
self.create_against_jv(jv_test_records[0], {
|
||||
"party": "_Test Customer 3",
|
||||
"against_sales_order": so2.name,
|
||||
"reference_type": "Sales Order",
|
||||
"reference_name": so2.name,
|
||||
"credit": 1000,
|
||||
"is_advance": "Yes"
|
||||
})
|
||||
@@ -52,7 +54,8 @@ class TestPaymentTool(unittest.TestCase):
|
||||
|
||||
self.create_against_jv(jv_test_records[0], {
|
||||
"party": "_Test Customer 3",
|
||||
"against_invoice": si1.name
|
||||
"reference_type": si1.doctype,
|
||||
"reference_name": si1.name
|
||||
})
|
||||
#Create SI with no outstanding
|
||||
si2 = self.create_voucher(si_test_records[0], {
|
||||
@@ -62,7 +65,8 @@ class TestPaymentTool(unittest.TestCase):
|
||||
|
||||
self.create_against_jv(jv_test_records[0], {
|
||||
"party": "_Test Customer 3",
|
||||
"against_invoice": si2.name,
|
||||
"reference_type": si2.doctype,
|
||||
"reference_name": si2.name,
|
||||
"credit": 561.80
|
||||
})
|
||||
|
||||
@@ -125,7 +129,7 @@ class TestPaymentTool(unittest.TestCase):
|
||||
def make_voucher_for_party(self, args, expected_outstanding):
|
||||
#Make Journal Entry for Party
|
||||
payment_tool_doc = frappe.new_doc("Payment Tool")
|
||||
|
||||
|
||||
for k, v in args.items():
|
||||
payment_tool_doc.set(k, v)
|
||||
|
||||
@@ -153,29 +157,12 @@ class TestPaymentTool(unittest.TestCase):
|
||||
|
||||
new_jv = paytool.make_journal_entry()
|
||||
|
||||
#Create a list of expected values as [party account, payment against, against_jv, against_invoice,
|
||||
#against_voucher, against_sales_order, against_purchase_order]
|
||||
expected_values = [
|
||||
[paytool.party_account, paytool.party, 100.00, expected_outstanding.get("Journal Entry")[0], None, None, None, None],
|
||||
[paytool.party_account, paytool.party, 100.00, None, expected_outstanding.get("Sales Invoice")[0], None, None, None],
|
||||
[paytool.party_account, paytool.party, 100.00, None, None, expected_outstanding.get("Purchase Invoice")[0], None, None],
|
||||
[paytool.party_account, paytool.party, 100.00, None, None, None, expected_outstanding.get("Sales Order")[0], None],
|
||||
[paytool.party_account, paytool.party, 100.00, None, None, None, None, expected_outstanding.get("Purchase Order")[0]]
|
||||
]
|
||||
|
||||
for jv_entry in new_jv.get("accounts"):
|
||||
if paytool.party_account == jv_entry.get("account") and paytool.party == jv_entry.get("party"):
|
||||
row = [
|
||||
jv_entry.get("account"),
|
||||
jv_entry.get("party"),
|
||||
jv_entry.get("debit" if paytool.party_type=="Supplier" else "credit"),
|
||||
jv_entry.get("against_jv"),
|
||||
jv_entry.get("against_invoice"),
|
||||
jv_entry.get("against_voucher"),
|
||||
jv_entry.get("against_sales_order"),
|
||||
jv_entry.get("against_purchase_order"),
|
||||
]
|
||||
self.assertTrue(row in expected_values)
|
||||
self.assertEquals(100.00,
|
||||
jv_entry.get("debit" if paytool.party_type=="Supplier" else "credit"))
|
||||
self.assertEquals(jv_entry.reference_name,
|
||||
expected_outstanding[jv_entry.reference_type][0])
|
||||
|
||||
self.assertEquals(new_jv.get("cheque_no"), paytool.reference_no)
|
||||
self.assertEquals(new_jv.get("cheque_date"), paytool.reference_date)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
frappe.ui.form.on("POS Setting", "onload", function(frm) {
|
||||
frappe.ui.form.on("POS Profile", "onload", function(frm) {
|
||||
frm.set_query("selling_price_list", function() {
|
||||
return { filter: { selling: 1 } };
|
||||
});
|
||||
|
||||
frm.call({
|
||||
method: "erpnext.accounts.doctype.pos_setting.pos_setting.get_series",
|
||||
method: "erpnext.accounts.doctype.pos_profile.pos_profile.get_series",
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
set_field_options("naming_series", r.message);
|
||||
271
erpnext/accounts/doctype/pos_profile/pos_profile.json
Normal file
271
erpnext/accounts/doctype/pos_profile/pos_profile.json
Normal file
@@ -0,0 +1,271 @@
|
||||
{
|
||||
"allow_rename": 0,
|
||||
"autoname": "hash",
|
||||
"creation": "2013-05-24 12:15:51",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "User",
|
||||
"oldfieldname": "user",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "User",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"description": "",
|
||||
"fieldname": "territory",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Territory",
|
||||
"oldfieldname": "territory",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Territory",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Series",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "naming_series",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "[Select]",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "currency",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 0,
|
||||
"label": "Currency",
|
||||
"oldfieldname": "currency",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Currency",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "selling_price_list",
|
||||
"fieldtype": "Link",
|
||||
"label": "Price List",
|
||||
"oldfieldname": "price_list_name",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Price List",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Company",
|
||||
"oldfieldname": "company",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
"label": "Warehouse",
|
||||
"oldfieldname": "warehouse",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "letter_head",
|
||||
"fieldtype": "Link",
|
||||
"label": "Letter Head",
|
||||
"oldfieldname": "letter_head",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Letter Head",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "tc_name",
|
||||
"fieldtype": "Link",
|
||||
"label": "Terms and Conditions",
|
||||
"oldfieldname": "tc_name",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Terms and Conditions",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "select_print_heading",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 0,
|
||||
"label": "Print Heading",
|
||||
"oldfieldname": "select_print_heading",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Print Heading",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"oldfieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"description": "Create Stock Ledger Entries when you submit a Sales Invoice",
|
||||
"fieldname": "update_stock",
|
||||
"fieldtype": "Check",
|
||||
"label": "Update Stock",
|
||||
"permlevel": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 0,
|
||||
"label": "Customer",
|
||||
"oldfieldname": "customer_account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Customer",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "mode_of_payment",
|
||||
"fieldtype": "Link",
|
||||
"label": "Mode of Payment",
|
||||
"options": "Mode of Payment",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "cash_bank_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Cash/Bank Account",
|
||||
"oldfieldname": "cash_bank_account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "income_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Income Account",
|
||||
"oldfieldname": "income_account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)",
|
||||
"fieldname": "expense_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"label": "Expense Account",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "cost_center",
|
||||
"fieldtype": "Link",
|
||||
"label": "Cost Center",
|
||||
"oldfieldname": "cost_center",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Cost Center",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "write_off_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Write Off Account",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "write_off_cost_center",
|
||||
"fieldtype": "Link",
|
||||
"label": "Write Off Cost Center",
|
||||
"options": "Cost Center",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "taxes_and_charges",
|
||||
"fieldtype": "Link",
|
||||
"label": "Taxes and Charges",
|
||||
"oldfieldname": "charge",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Sales Taxes and Charges Template",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
}
|
||||
],
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"modified": "2015-07-28 15:07:14.417200",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Profile",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"submit": 0
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "user"
|
||||
}
|
||||
16
erpnext/accounts/doctype/pos_setting/pos_setting.py → erpnext/accounts/doctype/pos_profile/pos_profile.py
Executable file → Normal file
16
erpnext/accounts/doctype/pos_setting/pos_setting.py → erpnext/accounts/doctype/pos_profile/pos_profile.py
Executable file → Normal file
@@ -8,29 +8,23 @@ from frappe.utils import cint
|
||||
|
||||
from frappe.model.document import Document
|
||||
|
||||
class POSSetting(Document):
|
||||
class POSProfile(Document):
|
||||
def validate(self):
|
||||
self.check_for_duplicate()
|
||||
self.validate_expense_account()
|
||||
self.validate_all_link_fields()
|
||||
|
||||
def check_for_duplicate(self):
|
||||
res = frappe.db.sql("""select name, user from `tabPOS Setting`
|
||||
res = frappe.db.sql("""select name, user from `tabPOS Profile`
|
||||
where ifnull(user, '') = %s and name != %s and company = %s""",
|
||||
(self.user, self.name, self.company))
|
||||
if res:
|
||||
if res[0][1]:
|
||||
msgprint(_("POS Setting {0} already created for user: {1} and company {2}").format(res[0][0],
|
||||
msgprint(_("POS Profile {0} already created for user: {1} and company {2}").format(res[0][0],
|
||||
res[0][1], self.company), raise_exception=1)
|
||||
else:
|
||||
msgprint(_("Global POS Setting {0} already created for company {1}").format(res[0][0],
|
||||
msgprint(_("Global POS Profile {0} already created for company {1}").format(res[0][0],
|
||||
self.company), raise_exception=1)
|
||||
|
||||
def validate_expense_account(self):
|
||||
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \
|
||||
and not self.expense_account:
|
||||
msgprint(_("Expense Account is mandatory"), raise_exception=1)
|
||||
|
||||
def validate_all_link_fields(self):
|
||||
accounts = {"Account": [self.cash_bank_account, self.income_account,
|
||||
self.expense_account], "Cost Center": [self.cost_center],
|
||||
@@ -57,7 +51,7 @@ class POSSetting(Document):
|
||||
condition = ""
|
||||
|
||||
pos_view_users = frappe.db.sql_list("""select user
|
||||
from `tabPOS Setting` {0}""".format(condition))
|
||||
from `tabPOS Profile` {0}""".format(condition))
|
||||
|
||||
for user in pos_view_users:
|
||||
if user:
|
||||
@@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
@@ -5,7 +6,7 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
test_records = frappe.get_test_records('POS Setting')
|
||||
# test_records = frappe.get_test_records('POS Profile')
|
||||
|
||||
class TestPOSSetting(unittest.TestCase):
|
||||
class TestPOSProfile(unittest.TestCase):
|
||||
pass
|
||||
@@ -1 +0,0 @@
|
||||
Standard settings for Point of Sales (POS) type of Sales Invoice.
|
||||
@@ -1,263 +0,0 @@
|
||||
{
|
||||
"allow_rename": 0,
|
||||
"autoname": "hash",
|
||||
"creation": "2013-05-24 12:15:51",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "User",
|
||||
"oldfieldname": "user",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "User",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"description": "",
|
||||
"fieldname": "territory",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Territory",
|
||||
"oldfieldname": "territory",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Territory",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Series",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "naming_series",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "[Select]",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "currency",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 0,
|
||||
"label": "Currency",
|
||||
"oldfieldname": "currency",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Currency",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "selling_price_list",
|
||||
"fieldtype": "Link",
|
||||
"label": "Price List",
|
||||
"oldfieldname": "price_list_name",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Price List",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Company",
|
||||
"oldfieldname": "company",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"oldfieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"description": "Create Stock Ledger Entries when you submit a Sales Invoice",
|
||||
"fieldname": "update_stock",
|
||||
"fieldtype": "Check",
|
||||
"label": "Update Stock",
|
||||
"permlevel": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 0,
|
||||
"label": "Customer",
|
||||
"oldfieldname": "customer_account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Customer",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "cash_bank_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Cash/Bank Account",
|
||||
"oldfieldname": "cash_bank_account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "income_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Income Account",
|
||||
"oldfieldname": "income_account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)",
|
||||
"fieldname": "expense_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"label": "Expense Account",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
"label": "Warehouse",
|
||||
"oldfieldname": "warehouse",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "cost_center",
|
||||
"fieldtype": "Link",
|
||||
"label": "Cost Center",
|
||||
"oldfieldname": "cost_center",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Cost Center",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "taxes_and_charges",
|
||||
"fieldtype": "Link",
|
||||
"label": "Taxes and Charges",
|
||||
"oldfieldname": "charge",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Sales Taxes and Charges Template",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "write_off_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Write Off Account",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "write_off_cost_center",
|
||||
"fieldtype": "Link",
|
||||
"label": "Write Off Cost Center",
|
||||
"options": "Cost Center",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "letter_head",
|
||||
"fieldtype": "Link",
|
||||
"label": "Letter Head",
|
||||
"oldfieldname": "letter_head",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Letter Head",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "tc_name",
|
||||
"fieldtype": "Link",
|
||||
"label": "Terms and Conditions",
|
||||
"oldfieldname": "tc_name",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Terms and Conditions",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "select_print_heading",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 0,
|
||||
"label": "Print Heading",
|
||||
"oldfieldname": "select_print_heading",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Print Heading",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
}
|
||||
],
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"modified": "2015-02-05 05:11:42.344181",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Setting",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"submit": 0
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "user"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
[]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -147,6 +147,7 @@ def get_pricing_rule_for_item(args):
|
||||
|
||||
if pricing_rule:
|
||||
item_details.pricing_rule = pricing_rule.name
|
||||
item_details.pricing_rule_for = pricing_rule.price_or_discount
|
||||
if pricing_rule.price_or_discount == "Price":
|
||||
item_details.update({
|
||||
"price_list_rate": pricing_rule.price/flt(args.conversion_rate) \
|
||||
@@ -205,9 +206,9 @@ def get_pricing_rules(args):
|
||||
|
||||
def filter_pricing_rules(args, pricing_rules):
|
||||
# filter for qty
|
||||
if pricing_rules and args.get("qty"):
|
||||
pricing_rules = filter(lambda x: (args.qty>=flt(x.min_qty)
|
||||
and (args.qty<=x.max_qty if x.max_qty else True)), pricing_rules)
|
||||
if pricing_rules:
|
||||
pricing_rules = filter(lambda x: (flt(args.get("qty"))>=flt(x.min_qty)
|
||||
and (flt(args.get("qty"))<=x.max_qty if x.max_qty else True)), pricing_rules)
|
||||
|
||||
# find pricing rule with highest priority
|
||||
if pricing_rules:
|
||||
|
||||
@@ -20,26 +20,18 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
this._super();
|
||||
|
||||
// Show / Hide button
|
||||
if(doc.docstatus==1 && doc.outstanding_amount > 0)
|
||||
this.frm.add_custom_button(__('Make Payment Entry'), this.make_bank_entry,
|
||||
frappe.boot.doctype_icons["Journal Entry"]);
|
||||
this.show_general_ledger();
|
||||
|
||||
if(doc.docstatus==1) {
|
||||
cur_frm.add_custom_button(__('View Ledger'), function() {
|
||||
frappe.route_options = {
|
||||
"voucher_no": doc.name,
|
||||
"from_date": doc.posting_date,
|
||||
"to_date": doc.posting_date,
|
||||
"company": doc.company,
|
||||
group_by_voucher: 0
|
||||
};
|
||||
frappe.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
}
|
||||
if(!doc.is_return) {
|
||||
if(doc.docstatus==1) {
|
||||
if(doc.outstanding_amount > 0) {
|
||||
this.frm.add_custom_button(__('Payment'), this.make_bank_entry).addClass("btn-primary");
|
||||
}
|
||||
cur_frm.add_custom_button(__('Debit Note'), this.make_debit_note);
|
||||
}
|
||||
|
||||
if(doc.docstatus===0) {
|
||||
cur_frm.add_custom_button(__('From Purchase Order'),
|
||||
function() {
|
||||
if(doc.docstatus===0) {
|
||||
cur_frm.add_custom_button(__('From Purchase Order'), function() {
|
||||
frappe.model.map_current_doc({
|
||||
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice",
|
||||
source_doctype: "Purchase Order",
|
||||
@@ -51,10 +43,9 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
company: cur_frm.doc.company
|
||||
}
|
||||
})
|
||||
}, "icon-download", "btn-default");
|
||||
});
|
||||
|
||||
cur_frm.add_custom_button(__('From Purchase Receipt'),
|
||||
function() {
|
||||
cur_frm.add_custom_button(__('From Purchase Receipt'), function() {
|
||||
frappe.model.map_current_doc({
|
||||
method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_invoice",
|
||||
source_doctype: "Purchase Receipt",
|
||||
@@ -64,8 +55,8 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
company: cur_frm.doc.company
|
||||
}
|
||||
})
|
||||
}, "icon-download", "btn-default");
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -109,7 +100,14 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
$.each(this.frm.doc["items"] || [], function(i, row) {
|
||||
if(row.purchase_receipt) frappe.model.clear_doc("Purchase Receipt", row.purchase_receipt)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
make_debit_note: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_debit_note",
|
||||
frm: cur_frm
|
||||
})
|
||||
},
|
||||
});
|
||||
|
||||
cur_frm.script_manager.make(erpnext.accounts.PurchaseInvoice);
|
||||
@@ -144,7 +142,7 @@ cur_frm.fields_dict['items'].grid.get_field("item_code").get_query = function(do
|
||||
return {
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters:{
|
||||
'is_purchase_item': 'Yes'
|
||||
'is_purchase_item': 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "naming_series",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "PINV-",
|
||||
"options": "PINV-\nPINV-RET-",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
@@ -29,7 +29,8 @@
|
||||
"options": "Supplier",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
"read_only": 0,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "supplier",
|
||||
@@ -37,7 +38,7 @@
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Name",
|
||||
"label": "Supplier Name",
|
||||
"oldfieldname": "supplier_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
@@ -112,7 +113,7 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "bill_date",
|
||||
@@ -125,7 +126,7 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
@@ -151,7 +152,29 @@
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "is_return",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Return",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "is_return",
|
||||
"fieldname": "return_against",
|
||||
"fieldtype": "Link",
|
||||
"label": "Return Against Purchase Invoice",
|
||||
"no_copy": 0,
|
||||
"options": "Purchase Invoice",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "currency_and_price_list",
|
||||
@@ -428,7 +451,7 @@
|
||||
"default": "Grand Total",
|
||||
"fieldname": "apply_discount_on",
|
||||
"fieldtype": "Select",
|
||||
"label": "Apply Discount On",
|
||||
"label": "Apply Additional Discount On",
|
||||
"options": "\nGrand Total\nNet Total",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
@@ -443,7 +466,7 @@
|
||||
{
|
||||
"fieldname": "discount_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Discount Amount",
|
||||
"label": "Additional Discount Amount",
|
||||
"options": "currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
@@ -452,7 +475,7 @@
|
||||
{
|
||||
"fieldname": "base_discount_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Discount Amount (Company Currency)",
|
||||
"label": "Additional Discount Amount (Company Currency)",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
@@ -556,7 +579,7 @@
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "write_off_amount",
|
||||
@@ -611,7 +634,7 @@
|
||||
{
|
||||
"fieldname": "advances_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Advances",
|
||||
"label": "",
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "icon-money",
|
||||
"permlevel": 0,
|
||||
@@ -665,7 +688,7 @@
|
||||
"depends_on": "supplier",
|
||||
"fieldname": "contact_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Contact Info",
|
||||
"label": "",
|
||||
"options": "icon-bullhorn",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
@@ -733,7 +756,7 @@
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
@@ -760,7 +783,7 @@
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "mode_of_payment",
|
||||
@@ -778,15 +801,6 @@
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "letter_head",
|
||||
"fieldtype": "Link",
|
||||
"label": "Letter Head",
|
||||
"options": "Letter Head",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "fiscal_year",
|
||||
"fieldtype": "Link",
|
||||
@@ -798,7 +812,7 @@
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "remarks",
|
||||
@@ -934,12 +948,21 @@
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.is_recurring==1",
|
||||
"fieldname": "recurring_print_format",
|
||||
"fieldtype": "Link",
|
||||
"label": "Recurring Print Format",
|
||||
"options": "Print Format",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
}
|
||||
],
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2015-05-15 14:20:47.718194",
|
||||
"modified": "2015-07-24 11:49:59.762109",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import cint, formatdate, flt
|
||||
from frappe.utils import cint, formatdate, flt, getdate
|
||||
from frappe import msgprint, _, throw
|
||||
from erpnext.setup.utils import get_company_currency
|
||||
import frappe.defaults
|
||||
@@ -37,13 +37,16 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
super(PurchaseInvoice, self).validate()
|
||||
|
||||
self.po_required()
|
||||
self.pr_required()
|
||||
if not self.is_return:
|
||||
self.po_required()
|
||||
self.pr_required()
|
||||
self.validate_supplier_invoice()
|
||||
self.validate_advance_jv("Purchase Order")
|
||||
|
||||
self.check_active_purchase_items()
|
||||
self.check_conversion_rate()
|
||||
self.validate_credit_to_acc()
|
||||
self.clear_unallocated_advances("Purchase Invoice Advance", "advances")
|
||||
self.validate_advance_jv("advances", "purchase_order")
|
||||
self.check_for_stopped_status()
|
||||
self.validate_with_previous_doc()
|
||||
self.validate_uom_is_integer("uom", "qty")
|
||||
@@ -70,13 +73,14 @@ class PurchaseInvoice(BuyingController):
|
||||
super(PurchaseInvoice, self).set_missing_values(for_validate)
|
||||
|
||||
def get_advances(self):
|
||||
super(PurchaseInvoice, self).get_advances(self.credit_to, "Supplier", self.supplier,
|
||||
"Purchase Invoice Advance", "advances", "debit", "purchase_order")
|
||||
if not self.is_return:
|
||||
super(PurchaseInvoice, self).get_advances(self.credit_to, "Supplier", self.supplier,
|
||||
"Purchase Invoice Advance", "advances", "debit", "purchase_order")
|
||||
|
||||
def check_active_purchase_items(self):
|
||||
for d in self.get('items'):
|
||||
if d.item_code: # extra condn coz item_code is not mandatory in PV
|
||||
if frappe.db.get_value("Item", d.item_code, "is_purchase_item") != 'Yes':
|
||||
if frappe.db.get_value("Item", d.item_code, "is_purchase_item") != 1:
|
||||
msgprint(_("Item {0} is not Purchase Item").format(d.item_code), raise_exception=True)
|
||||
|
||||
def check_conversion_rate(self):
|
||||
@@ -87,9 +91,7 @@ class PurchaseInvoice(BuyingController):
|
||||
throw(_("Conversion rate cannot be 0 or 1"))
|
||||
|
||||
def validate_credit_to_acc(self):
|
||||
root_type, account_type = frappe.db.get_value("Account", self.credit_to, ["root_type", "account_type"])
|
||||
if root_type != "Liability":
|
||||
frappe.throw(_("Credit To account must be a liability account"))
|
||||
account_type = frappe.db.get_value("Account", self.credit_to, "account_type")
|
||||
if account_type != "Payable":
|
||||
frappe.throw(_("Credit To account must be a Payable account"))
|
||||
|
||||
@@ -125,20 +127,11 @@ class PurchaseInvoice(BuyingController):
|
||||
}
|
||||
})
|
||||
|
||||
if cint(frappe.defaults.get_global_default('maintain_same_rate')):
|
||||
super(PurchaseInvoice, self).validate_with_previous_doc({
|
||||
"Purchase Order Item": {
|
||||
"ref_dn_field": "po_detail",
|
||||
"compare_fields": [["rate", "="]],
|
||||
"is_child_table": True,
|
||||
"allow_duplicate_prev_row_id": True
|
||||
},
|
||||
"Purchase Receipt Item": {
|
||||
"ref_dn_field": "pr_detail",
|
||||
"compare_fields": [["rate", "="]],
|
||||
"is_child_table": True
|
||||
}
|
||||
})
|
||||
if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
|
||||
self.validate_rate_with_reference_doc([
|
||||
["Purchase Order", "purchase_order", "po_detail"],
|
||||
["Purchase Receipt", "purchase_receipt", "pr_detail"]
|
||||
])
|
||||
|
||||
def set_against_expense_account(self):
|
||||
auto_accounting_for_stock = cint(frappe.defaults.get_global_default("auto_accounting_for_stock"))
|
||||
@@ -165,7 +158,7 @@ class PurchaseInvoice(BuyingController):
|
||||
elif item.expense_account not in against_accounts:
|
||||
# if no auto_accounting_for_stock or not a stock item
|
||||
against_accounts.append(item.expense_account)
|
||||
|
||||
|
||||
self.against_expense_account = ",".join(against_accounts)
|
||||
|
||||
def po_required(self):
|
||||
@@ -236,9 +229,11 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
# this sequence because outstanding may get -negative
|
||||
self.make_gl_entries()
|
||||
self.update_against_document_in_jv()
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
if not self.is_return:
|
||||
self.update_against_document_in_jv()
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
|
||||
self.update_project()
|
||||
|
||||
def make_gl_entries(self):
|
||||
@@ -260,7 +255,7 @@ class PurchaseInvoice(BuyingController):
|
||||
"against": self.against_expense_account,
|
||||
"credit": self.total_amount_to_pay,
|
||||
"remarks": self.remarks,
|
||||
"against_voucher": self.name,
|
||||
"against_voucher": self.return_against if cint(self.is_return) else self.name,
|
||||
"against_voucher_type": self.doctype,
|
||||
})
|
||||
)
|
||||
@@ -272,7 +267,7 @@ class PurchaseInvoice(BuyingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": tax.account_head,
|
||||
"against": self.credit_to,
|
||||
"against": self.supplier,
|
||||
"debit": tax.add_deduct_tax == "Add" and tax.base_tax_amount_after_discount_amount or 0,
|
||||
"credit": tax.add_deduct_tax == "Deduct" and tax.base_tax_amount_after_discount_amount or 0,
|
||||
"remarks": self.remarks,
|
||||
@@ -296,7 +291,7 @@ class PurchaseInvoice(BuyingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": item.expense_account,
|
||||
"against": self.credit_to,
|
||||
"against": self.supplier,
|
||||
"debit": item.base_net_amount,
|
||||
"remarks": self.remarks,
|
||||
"cost_center": item.cost_center
|
||||
@@ -316,7 +311,7 @@ class PurchaseInvoice(BuyingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": stock_received_but_not_billed,
|
||||
"against": self.credit_to,
|
||||
"against": self.supplier,
|
||||
"debit": flt(item.item_tax_amount, self.precision("item_tax_amount", item)),
|
||||
"remarks": self.remarks or "Accounting Entry for Stock"
|
||||
})
|
||||
@@ -342,7 +337,7 @@ class PurchaseInvoice(BuyingController):
|
||||
self.get_gl_dict({
|
||||
"account": expenses_included_in_valuation,
|
||||
"cost_center": cost_center,
|
||||
"against": self.credit_to,
|
||||
"against": self.supplier,
|
||||
"credit": applicable_amount,
|
||||
"remarks": self.remarks or "Accounting Entry for Stock"
|
||||
})
|
||||
@@ -356,7 +351,7 @@ class PurchaseInvoice(BuyingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": self.write_off_account,
|
||||
"against": self.credit_to,
|
||||
"against": self.supplier,
|
||||
"credit": flt(self.write_off_amount),
|
||||
"remarks": self.remarks,
|
||||
"cost_center": self.write_off_cost_center
|
||||
@@ -368,14 +363,15 @@ class PurchaseInvoice(BuyingController):
|
||||
make_gl_entries(gl_entries, cancel=(self.docstatus == 2))
|
||||
|
||||
def on_cancel(self):
|
||||
from erpnext.accounts.utils import remove_against_link_from_jv
|
||||
remove_against_link_from_jv(self.doctype, self.name, "against_voucher")
|
||||
if not self.is_return:
|
||||
from erpnext.accounts.utils import remove_against_link_from_jv
|
||||
remove_against_link_from_jv(self.doctype, self.name)
|
||||
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
self.make_gl_entries_on_cancel()
|
||||
self.update_project()
|
||||
|
||||
|
||||
def update_project(self):
|
||||
project_list = []
|
||||
for d in self.items:
|
||||
@@ -386,6 +382,17 @@ class PurchaseInvoice(BuyingController):
|
||||
project.save()
|
||||
project_list.append(d.project_name)
|
||||
|
||||
def validate_supplier_invoice(self):
|
||||
if self.bill_date:
|
||||
if getdate(self.bill_date) > getdate(self.posting_date):
|
||||
frappe.throw("Supplier Invoice Date cannot be greater than Posting Date")
|
||||
if self.bill_no:
|
||||
if cint(frappe.db.get_single_value("Accounts Settings", "check_supplier_invoice_uniqueness")):
|
||||
pi = frappe.db.exists("Purchase Invoice", {"bill_no": self.bill_no,
|
||||
"fiscal_year": self.fiscal_year, "name": ("!=", self.name)})
|
||||
if pi:
|
||||
frappe.throw("Supplier Invoice No exists in Purchase Invoice {0}".format(pi))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
|
||||
from erpnext.controllers.queries import get_match_cond
|
||||
@@ -401,4 +408,9 @@ def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
|
||||
and tabAccount.company = '%(company)s'
|
||||
and tabAccount.%(key)s LIKE '%(txt)s'
|
||||
%(mcond)s""" % {'company': filters['company'], 'key': searchfield,
|
||||
'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype)})
|
||||
'txt': "%%%s%%" % frappe.db.escape(txt), 'mcond':get_match_cond(doctype)})
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_debit_note(source_name, target_doc=None):
|
||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||
return make_return_doc("Purchase Invoice", source_name, target_doc)
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
// render
|
||||
frappe.listview_settings['Purchase Invoice'] = {
|
||||
add_fields: ["supplier", "supplier_name", "base_grand_total", "outstanding_amount", "due_date", "company",
|
||||
"currency"],
|
||||
"currency", "is_return"],
|
||||
get_indicator: function(doc) {
|
||||
if(flt(doc.outstanding_amount) > 0 && doc.docstatus==1) {
|
||||
if(cint(doc.is_return)==1) {
|
||||
return [__("Return"), "darkgrey", "is_return,=,1"];
|
||||
} else if(flt(doc.outstanding_amount) > 0 && doc.docstatus==1) {
|
||||
if(frappe.datetime.get_diff(doc.due_date) < 0) {
|
||||
return [__("Overdue"), "red", "outstanding_amount,>,0|due_date,<,Today"];
|
||||
} else {
|
||||
|
||||
@@ -218,23 +218,20 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
pi.load_from_db()
|
||||
|
||||
self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||
where against_voucher=%s""", pi.name))
|
||||
|
||||
self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||
where against_voucher=%s and debit=300""", pi.name))
|
||||
where reference_type='Purchase Invoice' and reference_name=%s and debit=300""", pi.name))
|
||||
|
||||
self.assertEqual(pi.outstanding_amount, 1212.30)
|
||||
|
||||
pi.cancel()
|
||||
|
||||
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||
where against_voucher=%s""", pi.name))
|
||||
self.assertFalse(frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||
where reference_type='Purchase Invoice' and reference_name=%s""", pi.name))
|
||||
|
||||
def test_recurring_invoice(self):
|
||||
from erpnext.controllers.tests.test_recurring_document import test_recurring_document
|
||||
test_recurring_document(self, test_records)
|
||||
|
||||
def test_total_purchase_cost_for_project(self):
|
||||
|
||||
def test_total_purchase_cost_for_project(self):
|
||||
purchase_invoice = frappe.new_doc('Purchase Invoice')
|
||||
purchase_invoice.update({
|
||||
"credit_to": "_Test Payable - _TC",
|
||||
@@ -260,20 +257,73 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
]
|
||||
})
|
||||
purchase_invoice.save()
|
||||
purchase_invoice.submit()
|
||||
purchase_invoice.submit()
|
||||
self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), 2000)
|
||||
|
||||
|
||||
purchase_invoice1 = frappe.copy_doc(purchase_invoice)
|
||||
purchase_invoice1.save()
|
||||
purchase_invoice1.submit()
|
||||
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), 4000)
|
||||
|
||||
purchase_invoice1.cancel()
|
||||
|
||||
purchase_invoice1.cancel()
|
||||
self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), 2000)
|
||||
|
||||
purchase_invoice.cancel()
|
||||
|
||||
purchase_invoice.cancel()
|
||||
self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), 0)
|
||||
|
||||
|
||||
def test_return_purchase_invoice(self):
|
||||
set_perpetual_inventory()
|
||||
|
||||
pi = make_purchase_invoice()
|
||||
|
||||
return_pi = make_purchase_invoice(is_return=1, return_against=pi.name, qty=-2)
|
||||
|
||||
|
||||
# check gl entries for return
|
||||
gl_entries = frappe.db.sql("""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type=%s and voucher_no=%s
|
||||
order by account desc""", ("Purchase Invoice", return_pi.name), as_dict=1)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
|
||||
expected_values = {
|
||||
"Creditors - _TC": [100.0, 0.0],
|
||||
"Stock Received But Not Billed - _TC": [0.0, 100.0],
|
||||
}
|
||||
|
||||
for gle in gl_entries:
|
||||
self.assertEquals(expected_values[gle.account][0], gle.debit)
|
||||
self.assertEquals(expected_values[gle.account][1], gle.credit)
|
||||
|
||||
set_perpetual_inventory(0)
|
||||
|
||||
def make_purchase_invoice(**args):
|
||||
pi = frappe.new_doc("Purchase Invoice")
|
||||
args = frappe._dict(args)
|
||||
if args.posting_date:
|
||||
pi.posting_date = args.posting_date
|
||||
if args.posting_time:
|
||||
pi.posting_time = args.posting_time
|
||||
pi.company = args.company or "_Test Company"
|
||||
pi.supplier = args.supplier or "_Test Supplier"
|
||||
pi.currency = args.currency or "INR"
|
||||
pi.is_return = args.is_return
|
||||
pi.return_against = args.return_against
|
||||
|
||||
pi.append("items", {
|
||||
"item_code": args.item or args.item_code or "_Test Item",
|
||||
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||
"qty": args.qty or 5,
|
||||
"rate": args.rate or 50,
|
||||
"conversion_factor": 1.0,
|
||||
"serial_no": args.serial_no,
|
||||
"stock_uom": "_Test UOM"
|
||||
})
|
||||
if not args.do_not_save:
|
||||
pi.insert()
|
||||
if not args.do_not_submit:
|
||||
pi.submit()
|
||||
return pi
|
||||
|
||||
test_records = frappe.get_test_records('Purchase Invoice')
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text",
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Text",
|
||||
@@ -49,6 +49,23 @@
|
||||
"read_only": 0,
|
||||
"width": "300px"
|
||||
},
|
||||
{
|
||||
"fieldname": "image",
|
||||
"fieldtype": "Attach",
|
||||
"hidden": 1,
|
||||
"label": "Image",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "image_view",
|
||||
"fieldtype": "Image",
|
||||
"label": "Image View",
|
||||
"options": "image",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "quantity_and_rate",
|
||||
"fieldtype": "Section Break",
|
||||
@@ -105,10 +122,11 @@
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "price_list_rate",
|
||||
"fieldname": "discount_percentage",
|
||||
"fieldtype": "Percent",
|
||||
"in_list_view": 1,
|
||||
"label": "Discount %",
|
||||
"label": "Discount on Price List Rate (%)",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 0
|
||||
@@ -451,7 +469,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-02-23 15:35:32.895515",
|
||||
"modified": "2015-07-02 03:00:44.496683",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice Item",
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax
|
||||
from erpnext.accounts.doctype.sales_taxes_and_charges_template.sales_taxes_and_charges_template \
|
||||
import valdiate_taxes_and_charges_template
|
||||
|
||||
class PurchaseTaxesandChargesTemplate(Document):
|
||||
def validate(self):
|
||||
for tax in self.get("taxes"):
|
||||
validate_taxes_and_charges(tax)
|
||||
validate_inclusive_tax(tax, self)
|
||||
valdiate_taxes_and_charges_template(self)
|
||||
|
||||
@@ -7,12 +7,13 @@ import frappe
|
||||
@frappe.whitelist()
|
||||
def get_items(price_list, sales_or_purchase, item=None):
|
||||
condition = ""
|
||||
order_by = ""
|
||||
args = {"price_list": price_list}
|
||||
|
||||
if sales_or_purchase == "Sales":
|
||||
condition = "i.is_sales_item='Yes'"
|
||||
condition = "i.is_sales_item=1"
|
||||
else:
|
||||
condition = "i.is_purchase_item='Yes'"
|
||||
condition = "i.is_purchase_item=1"
|
||||
|
||||
if item:
|
||||
# search serial no
|
||||
@@ -30,16 +31,25 @@ def get_items(price_list, sales_or_purchase, item=None):
|
||||
item_code[0]["barcode"] = item
|
||||
return item_code
|
||||
|
||||
condition += " and (CONCAT(i.name, i.item_name) like %(name)s or (i.variant_of like %(name)s))"
|
||||
args["name"] = "%%%s%%" % item
|
||||
condition += " and ((CONCAT(i.name, i.item_name) like %(name)s) or (i.variant_of like %(name)s) or (i.item_group like %(name)s))"
|
||||
order_by = """if(locate(%(_name)s, i.name), locate(%(_name)s, i.name), 99999),
|
||||
if(locate(%(_name)s, i.item_name), locate(%(_name)s, i.item_name), 99999),
|
||||
if(locate(%(_name)s, i.variant_of), locate(%(_name)s, i.variant_of), 99999),
|
||||
if(locate(%(_name)s, i.item_group), locate(%(_name)s, i.item_group), 99999),"""
|
||||
args["name"] = "%%%s%%" % frappe.db.escape(item)
|
||||
args["_name"] = item.replace("%", "")
|
||||
|
||||
# locate function is used to sort by closest match from the beginning of the value
|
||||
return frappe.db.sql("""select i.name, i.item_name, i.image,
|
||||
item_det.price_list_rate, item_det.currency
|
||||
from `tabItem` i LEFT JOIN
|
||||
(select item_code, price_list_rate, currency from
|
||||
`tabItem Price` where price_list=%s) item_det
|
||||
`tabItem Price` where price_list=%(price_list)s) item_det
|
||||
ON
|
||||
(item_det.item_code=i.name or item_det.item_code=i.variant_of)
|
||||
where
|
||||
ifnull(i.has_variants, 0) = 0 and
|
||||
%s""" % ('%(price_list)s', condition), args, as_dict=1)
|
||||
{condition}
|
||||
order by
|
||||
{order_by}
|
||||
i.name""".format(condition=condition, order_by=order_by), args, as_dict=1)
|
||||
|
||||
@@ -23,7 +23,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
this.frm.set_value("is_pos", 1);
|
||||
this.is_pos(function() {
|
||||
if (cint(frappe.defaults.get_user_defaults("fs_pos_view"))===1)
|
||||
erpnext.pos.toggle(me.frm);
|
||||
erpnext.pos.toggle(me.frm, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -41,20 +41,15 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
|
||||
cur_frm.dashboard.reset();
|
||||
|
||||
if(doc.docstatus==1) {
|
||||
cur_frm.add_custom_button('View Ledger', function() {
|
||||
frappe.route_options = {
|
||||
"voucher_no": doc.name,
|
||||
"from_date": doc.posting_date,
|
||||
"to_date": doc.posting_date,
|
||||
"company": doc.company,
|
||||
group_by_voucher: 0
|
||||
};
|
||||
frappe.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
this.frm.toggle_reqd("due_date", !this.frm.doc.is_return);
|
||||
|
||||
// var percent_paid = cint(flt(doc.base_grand_total - doc.outstanding_amount) / flt(doc.base_grand_total) * 100);
|
||||
// cur_frm.dashboard.add_progress(percent_paid + "% Paid", percent_paid);
|
||||
this.show_general_ledger();
|
||||
|
||||
if(doc.update_stock) this.show_stock_ledger();
|
||||
|
||||
if(doc.docstatus==1 && !doc.is_return) {
|
||||
cur_frm.add_custom_button(doc.update_stock ? __('Sales Return') : __('Credit Note'),
|
||||
this.make_sales_return);
|
||||
|
||||
if(cint(doc.update_stock)!=1) {
|
||||
// show Make Delivery Note button only if Sales Invoice is not created from Delivery Note
|
||||
@@ -65,24 +60,24 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
});
|
||||
|
||||
if(!from_delivery_note) {
|
||||
cur_frm.page.add_menu_item(__('Make Delivery'), cur_frm.cscript['Make Delivery Note'], "icon-truck")
|
||||
cur_frm.add_custom_button(__('Delivery'), cur_frm.cscript['Make Delivery Note']).addClass("btn-primary");
|
||||
}
|
||||
}
|
||||
|
||||
if(doc.outstanding_amount!=0) {
|
||||
cur_frm.add_custom_button(__('Make Payment Entry'), cur_frm.cscript.make_bank_entry, "icon-money");
|
||||
if(doc.outstanding_amount!=0 && !cint(doc.is_return)) {
|
||||
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry).addClass("btn-primary");
|
||||
}
|
||||
}
|
||||
|
||||
// Show buttons only when pos view is active
|
||||
if (doc.docstatus===0 && !this.pos_active) {
|
||||
if (cint(doc.docstatus==0) && cur_frm.page.current_view_name!=="pos" && !doc.is_return) {
|
||||
cur_frm.cscript.sales_order_btn();
|
||||
cur_frm.cscript.delivery_note_btn();
|
||||
}
|
||||
},
|
||||
|
||||
sales_order_btn: function() {
|
||||
this.$sales_order_btn = cur_frm.page.add_menu_item(__('From Sales Order'),
|
||||
this.$sales_order_btn = cur_frm.add_custom_button(__('From Sales Order'),
|
||||
function() {
|
||||
frappe.model.map_current_doc({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice",
|
||||
@@ -99,7 +94,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
},
|
||||
|
||||
delivery_note_btn: function() {
|
||||
this.$delivery_note_btn = cur_frm.page.add_menu_item(__('From Delivery Note'),
|
||||
this.$delivery_note_btn = cur_frm.add_custom_button(__('From Delivery Note'),
|
||||
function() {
|
||||
frappe.model.map_current_doc({
|
||||
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice",
|
||||
@@ -205,8 +200,14 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
|
||||
items_on_form_rendered: function() {
|
||||
erpnext.setup_serial_no();
|
||||
}
|
||||
},
|
||||
|
||||
make_sales_return: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_sales_return",
|
||||
frm: cur_frm
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// for backward compatibility: combine new and previous states
|
||||
@@ -253,7 +254,7 @@ cur_frm.cscript.mode_of_payment = function(doc) {
|
||||
if(r.message) {
|
||||
cur_frm.set_value("cash_bank_account", r.message["account"]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -283,16 +284,6 @@ cur_frm.cscript.make_bank_entry = function() {
|
||||
});
|
||||
}
|
||||
|
||||
cur_frm.fields_dict.debit_to.get_query = function(doc) {
|
||||
return{
|
||||
filters: {
|
||||
'report_type': 'Balance Sheet',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.fields_dict.cash_bank_account.get_query = function(doc) {
|
||||
return {
|
||||
filters: [
|
||||
@@ -369,15 +360,15 @@ cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(
|
||||
}
|
||||
|
||||
cur_frm.cscript.income_account = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "income_account");
|
||||
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "income_account");
|
||||
}
|
||||
|
||||
cur_frm.cscript.expense_account = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "expense_account");
|
||||
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "expense_account");
|
||||
}
|
||||
|
||||
cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "cost_center");
|
||||
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center");
|
||||
}
|
||||
|
||||
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
@@ -392,8 +383,6 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
cur_frm.set_query("debit_to", function(doc) {
|
||||
return{
|
||||
filters: [
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import frappe.defaults
|
||||
from frappe.utils import cint, cstr, flt
|
||||
from frappe.utils import cint, flt
|
||||
from frappe import _, msgprint, throw
|
||||
from erpnext.accounts.party import get_party_account, get_due_date
|
||||
from erpnext.controllers.stock_controller import update_gl_entries_after
|
||||
@@ -46,7 +46,7 @@ class SalesInvoice(SellingController):
|
||||
self.validate_debit_to_acc()
|
||||
self.validate_fixed_asset_account()
|
||||
self.clear_unallocated_advances("Sales Invoice Advance", "advances")
|
||||
self.validate_advance_jv("advances", "sales_order")
|
||||
self.validate_advance_jv("Sales Order")
|
||||
self.add_remarks()
|
||||
self.validate_write_off_account()
|
||||
|
||||
@@ -65,8 +65,8 @@ class SalesInvoice(SellingController):
|
||||
self.set_against_income_account()
|
||||
self.validate_c_form()
|
||||
self.validate_time_logs_are_submitted()
|
||||
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount",
|
||||
"items")
|
||||
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount", "items")
|
||||
self.update_packing_list()
|
||||
|
||||
def on_submit(self):
|
||||
super(SalesInvoice, self).on_submit()
|
||||
@@ -81,14 +81,16 @@ class SalesInvoice(SellingController):
|
||||
|
||||
self.check_prev_docstatus()
|
||||
|
||||
self.update_status_updater_args()
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||
self.check_credit_limit()
|
||||
if not self.is_return:
|
||||
self.update_status_updater_args()
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||
self.check_credit_limit()
|
||||
|
||||
# this sequence because outstanding may get -ve
|
||||
self.make_gl_entries()
|
||||
|
||||
if not cint(self.is_pos) == 1:
|
||||
if not cint(self.is_pos) == 1 and not self.is_return:
|
||||
self.update_against_document_in_jv()
|
||||
|
||||
self.update_time_log_batch(self.name)
|
||||
@@ -103,11 +105,13 @@ class SalesInvoice(SellingController):
|
||||
self.check_stop_sales_order("sales_order")
|
||||
|
||||
from erpnext.accounts.utils import remove_against_link_from_jv
|
||||
remove_against_link_from_jv(self.doctype, self.name, "against_invoice")
|
||||
remove_against_link_from_jv(self.doctype, self.name)
|
||||
|
||||
if not self.is_return:
|
||||
self.update_status_updater_args()
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||
|
||||
self.update_status_updater_args()
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||
self.validate_c_form_on_cancel()
|
||||
|
||||
self.make_gl_entries_on_cancel()
|
||||
@@ -139,7 +143,7 @@ class SalesInvoice(SellingController):
|
||||
|
||||
if not self.debit_to:
|
||||
self.debit_to = get_party_account(self.company, self.customer, "Customer")
|
||||
if not self.due_date:
|
||||
if not self.due_date and self.customer:
|
||||
self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company)
|
||||
|
||||
super(SalesInvoice, self).set_missing_values(for_validate)
|
||||
@@ -160,16 +164,17 @@ class SalesInvoice(SellingController):
|
||||
frappe.throw(_("Time Log Batch {0} must be 'Submitted'").format(d.time_log_batch))
|
||||
|
||||
def set_pos_fields(self, for_validate=False):
|
||||
"""Set retail related fields from pos settings"""
|
||||
"""Set retail related fields from POS Profiles"""
|
||||
if cint(self.is_pos) != 1:
|
||||
return
|
||||
|
||||
from erpnext.stock.get_item_details import get_pos_settings_item_details, get_pos_settings
|
||||
pos = get_pos_settings(self.company)
|
||||
from erpnext.stock.get_item_details import get_pos_profiles_item_details, get_pos_profiles
|
||||
pos = get_pos_profiles(self.company)
|
||||
|
||||
if pos:
|
||||
if not for_validate and not self.customer:
|
||||
self.customer = pos.customer
|
||||
self.mode_of_payment = pos.mode_of_payment
|
||||
# self.set_customer_defaults()
|
||||
|
||||
for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name',
|
||||
@@ -184,7 +189,7 @@ class SalesInvoice(SellingController):
|
||||
# set pos values in items
|
||||
for item in self.get("items"):
|
||||
if item.get('item_code'):
|
||||
for fname, val in get_pos_settings_item_details(pos,
|
||||
for fname, val in get_pos_profiles_item_details(pos,
|
||||
frappe._dict(item.as_dict()), pos).items():
|
||||
|
||||
if (not for_validate) or (for_validate and not item.get(fname)):
|
||||
@@ -199,8 +204,9 @@ class SalesInvoice(SellingController):
|
||||
self.set_taxes()
|
||||
|
||||
def get_advances(self):
|
||||
super(SalesInvoice, self).get_advances(self.debit_to, "Customer", self.customer,
|
||||
"Sales Invoice Advance", "advances", "credit", "sales_order")
|
||||
if not self.is_return:
|
||||
super(SalesInvoice, self).get_advances(self.debit_to, "Customer", self.customer,
|
||||
"Sales Invoice Advance", "advances", "credit", "sales_order")
|
||||
|
||||
def get_company_abbr(self):
|
||||
return frappe.db.sql("select abbr from tabCompany where name=%s", self.company)[0][0]
|
||||
@@ -236,21 +242,17 @@ class SalesInvoice(SellingController):
|
||||
reconcile_against_document(lst)
|
||||
|
||||
def validate_debit_to_acc(self):
|
||||
root_type, account_type = frappe.db.get_value("Account", self.debit_to, ["root_type", "account_type"])
|
||||
if root_type != "Asset":
|
||||
frappe.throw(_("Debit To account must be a liability account"))
|
||||
account_type = frappe.db.get_value("Account", self.debit_to, "account_type")
|
||||
if account_type != "Receivable":
|
||||
frappe.throw(_("Debit To account must be a Receivable account"))
|
||||
|
||||
def validate_fixed_asset_account(self):
|
||||
"""Validate Fixed Asset and whether Income Account Entered Exists"""
|
||||
for d in self.get('items'):
|
||||
item = frappe.db.sql("""select name,is_asset_item,is_sales_item from `tabItem`
|
||||
where name = %s""", d.item_code)
|
||||
acc = frappe.db.sql("""select account_type from `tabAccount`
|
||||
where name = %s and docstatus != 2""", d.income_account)
|
||||
if item and item[0][1] == 'Yes' and acc and acc[0][0] != 'Fixed Asset':
|
||||
msgprint(_("Account {0} must be of type 'Fixed Asset' as Item {1} is an Asset Item").format(acc[0][0], d.item_code), raise_exception=True)
|
||||
is_asset_item = frappe.db.get_value("Item", d.item_code, "is_asset_item")
|
||||
account_type = frappe.db.get_value("Account", d.income_account, "account_type")
|
||||
if is_asset_item == 1 and account_type != 'Fixed Asset':
|
||||
msgprint(_("Account {0} must be of type 'Fixed Asset' as Item {1} is an Asset Item").format(d.income_account, d.item_code), raise_exception=True)
|
||||
|
||||
def validate_with_previous_doc(self):
|
||||
super(SalesInvoice, self).validate_with_previous_doc({
|
||||
@@ -266,20 +268,11 @@ class SalesInvoice(SellingController):
|
||||
},
|
||||
})
|
||||
|
||||
if cint(frappe.defaults.get_global_default('maintain_same_sales_rate')):
|
||||
super(SalesInvoice, self).validate_with_previous_doc({
|
||||
"Sales Order Item": {
|
||||
"ref_dn_field": "so_detail",
|
||||
"compare_fields": [["rate", "="]],
|
||||
"is_child_table": True,
|
||||
"allow_duplicate_prev_row_id": True
|
||||
},
|
||||
"Delivery Note Item": {
|
||||
"ref_dn_field": "dn_detail",
|
||||
"compare_fields": [["rate", "="]],
|
||||
"is_child_table": True
|
||||
}
|
||||
})
|
||||
if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')):
|
||||
self.validate_rate_with_reference_doc([
|
||||
["Sales Order", "sales_order", "so_detail"],
|
||||
["Delivery Note", "delivery_note", "dn_detail"]
|
||||
])
|
||||
|
||||
def set_against_income_account(self):
|
||||
"""Set against account for debit to account"""
|
||||
@@ -296,11 +289,13 @@ class SalesInvoice(SellingController):
|
||||
|
||||
def so_dn_required(self):
|
||||
"""check in manage account if sales order / delivery note required or not."""
|
||||
if self.is_return:
|
||||
return
|
||||
dic = {'Sales Order':'so_required','Delivery Note':'dn_required'}
|
||||
for i in dic:
|
||||
if frappe.db.get_value('Selling Settings', None, dic[i]) == 'Yes':
|
||||
for d in self.get('items'):
|
||||
if frappe.db.get_value('Item', d.item_code, 'is_stock_item') == 'Yes' \
|
||||
if frappe.db.get_value('Item', d.item_code, 'is_stock_item') == 1 \
|
||||
and not d.get(i.lower().replace(' ','_')):
|
||||
msgprint(_("{0} is mandatory for Item {1}").format(i,d.item_code), raise_exception=1)
|
||||
|
||||
@@ -369,38 +364,31 @@ class SalesInvoice(SellingController):
|
||||
d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0
|
||||
d.projected_qty = bin and flt(bin[0]['projected_qty']) or 0
|
||||
|
||||
|
||||
def get_warehouse(self):
|
||||
user_pos_setting = frappe.db.sql("""select name, warehouse from `tabPOS Setting`
|
||||
where ifnull(user,'') = %s and company = %s""", (frappe.session['user'], self.company))
|
||||
warehouse = user_pos_setting[0][1] if user_pos_setting else None
|
||||
|
||||
if not warehouse:
|
||||
global_pos_setting = frappe.db.sql("""select name, warehouse from `tabPOS Setting`
|
||||
where ifnull(user,'') = '' and company = %s""", self.company)
|
||||
|
||||
if global_pos_setting:
|
||||
warehouse = global_pos_setting[0][1]
|
||||
elif not user_pos_setting:
|
||||
msgprint(_("POS Setting required to make POS Entry"), raise_exception=True)
|
||||
|
||||
return warehouse
|
||||
|
||||
def on_update(self):
|
||||
def update_packing_list(self):
|
||||
if cint(self.update_stock) == 1:
|
||||
# Set default warehouse from pos setting
|
||||
if cint(self.is_pos) == 1:
|
||||
w = self.get_warehouse()
|
||||
if w:
|
||||
for d in self.get('items'):
|
||||
if not d.warehouse:
|
||||
d.warehouse = cstr(w)
|
||||
|
||||
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
|
||||
make_packing_list(self, 'items')
|
||||
else:
|
||||
self.set('packed_items', [])
|
||||
|
||||
|
||||
def get_warehouse(self):
|
||||
user_pos_profile = frappe.db.sql("""select name, warehouse from `tabPOS Profile`
|
||||
where ifnull(user,'') = %s and company = %s""", (frappe.session['user'], self.company))
|
||||
warehouse = user_pos_profile[0][1] if user_pos_profile else None
|
||||
|
||||
if not warehouse:
|
||||
global_pos_profile = frappe.db.sql("""select name, warehouse from `tabPOS Profile`
|
||||
where ifnull(user,'') = '' and company = %s""", self.company)
|
||||
|
||||
if global_pos_profile:
|
||||
warehouse = global_pos_profile[0][1]
|
||||
elif not user_pos_profile:
|
||||
msgprint(_("POS Profile required to make POS Entry"), raise_exception=True)
|
||||
|
||||
return warehouse
|
||||
|
||||
def on_update(self):
|
||||
if cint(self.is_pos) == 1:
|
||||
if flt(self.paid_amount) == 0:
|
||||
if self.cash_bank_account:
|
||||
@@ -430,13 +418,19 @@ class SalesInvoice(SellingController):
|
||||
def update_stock_ledger(self):
|
||||
sl_entries = []
|
||||
for d in self.get_item_list():
|
||||
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes" \
|
||||
and d.warehouse:
|
||||
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 and d.warehouse and flt(d['qty']):
|
||||
self.update_reserved_qty(d)
|
||||
|
||||
incoming_rate = 0
|
||||
if cint(self.is_return) and self.return_against and self.docstatus==1:
|
||||
incoming_rate = self.get_incoming_rate_for_sales_return(d.item_code,
|
||||
self.return_against)
|
||||
|
||||
sl_entries.append(self.get_sl_entries(d, {
|
||||
"actual_qty": -1*flt(d.qty),
|
||||
"stock_uom": frappe.db.get_value("Item", d.item_code, "stock_uom")
|
||||
"stock_uom": frappe.db.get_value("Item", d.item_code, "stock_uom"),
|
||||
"incoming_rate": incoming_rate
|
||||
}))
|
||||
|
||||
self.make_sl_entries(sl_entries)
|
||||
|
||||
def make_gl_entries(self, repost_future_gle=True):
|
||||
@@ -445,16 +439,16 @@ class SalesInvoice(SellingController):
|
||||
if gl_entries:
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
|
||||
# if POS and amount is written off, there's no outstanding and hence no need to update it
|
||||
update_outstanding = cint(self.is_pos) and self.write_off_account \
|
||||
and 'No' or 'Yes'
|
||||
# if POS and amount is written off, updating outstanding amt after posting all gl entries
|
||||
update_outstanding = "No" if (cint(self.is_pos) or self.write_off_account) else "Yes"
|
||||
|
||||
make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
|
||||
update_outstanding=update_outstanding, merge_entries=False)
|
||||
|
||||
if update_outstanding == "No":
|
||||
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
||||
update_outstanding_amt(self.debit_to, "Customer", self.customer, self.doctype, self.name)
|
||||
update_outstanding_amt(self.debit_to, "Customer", self.customer,
|
||||
self.doctype, self.return_against if cint(self.is_return) else self.name)
|
||||
|
||||
if repost_future_gle and cint(self.update_stock) \
|
||||
and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
||||
@@ -495,7 +489,7 @@ class SalesInvoice(SellingController):
|
||||
"against": self.against_income_account,
|
||||
"debit": self.base_grand_total,
|
||||
"remarks": self.remarks,
|
||||
"against_voucher": self.name,
|
||||
"against_voucher": self.return_against if cint(self.is_return) else self.name,
|
||||
"against_voucher_type": self.doctype
|
||||
})
|
||||
)
|
||||
@@ -506,7 +500,7 @@ class SalesInvoice(SellingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": tax.account_head,
|
||||
"against": self.debit_to,
|
||||
"against": self.customer,
|
||||
"credit": flt(tax.base_tax_amount_after_discount_amount),
|
||||
"remarks": self.remarks,
|
||||
"cost_center": tax.cost_center
|
||||
@@ -520,7 +514,7 @@ class SalesInvoice(SellingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": item.income_account,
|
||||
"against": self.debit_to,
|
||||
"against": self.customer,
|
||||
"credit": item.base_net_amount,
|
||||
"remarks": self.remarks,
|
||||
"cost_center": item.cost_center
|
||||
@@ -530,7 +524,6 @@ class SalesInvoice(SellingController):
|
||||
# expense account gl entries
|
||||
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \
|
||||
and cint(self.update_stock):
|
||||
|
||||
gl_entries += super(SalesInvoice, self).get_gl_entries()
|
||||
|
||||
def make_pos_gl_entries(self, gl_entries):
|
||||
@@ -544,14 +537,14 @@ class SalesInvoice(SellingController):
|
||||
"against": self.cash_bank_account,
|
||||
"credit": self.paid_amount,
|
||||
"remarks": self.remarks,
|
||||
"against_voucher": self.name,
|
||||
"against_voucher": self.return_against if cint(self.is_return) else self.name,
|
||||
"against_voucher_type": self.doctype,
|
||||
})
|
||||
)
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": self.cash_bank_account,
|
||||
"against": self.debit_to,
|
||||
"against": self.customer,
|
||||
"debit": self.paid_amount,
|
||||
"remarks": self.remarks,
|
||||
})
|
||||
@@ -568,14 +561,14 @@ class SalesInvoice(SellingController):
|
||||
"against": self.write_off_account,
|
||||
"credit": self.write_off_amount,
|
||||
"remarks": self.remarks,
|
||||
"against_voucher": self.name,
|
||||
"against_voucher": self.return_against if cint(self.is_return) else self.name,
|
||||
"against_voucher_type": self.doctype,
|
||||
})
|
||||
)
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": self.write_off_account,
|
||||
"against": self.debit_to,
|
||||
"against": self.customer,
|
||||
"debit": self.write_off_amount,
|
||||
"remarks": self.remarks,
|
||||
"cost_center": self.write_off_cost_center
|
||||
@@ -590,7 +583,7 @@ def get_list_context(context=None):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_bank_cash_account(mode_of_payment, company):
|
||||
account = frappe.db.get_value("Mode of Payment Account",
|
||||
account = frappe.db.get_value("Mode of Payment Account",
|
||||
{"parent": mode_of_payment, "company": company}, "default_account")
|
||||
if not account:
|
||||
frappe.msgprint(_("Please set default Cash or Bank account in Mode of Payment {0}").format(mode_of_payment))
|
||||
@@ -614,7 +607,7 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
|
||||
and tabAccount.company = '%(company)s'
|
||||
and tabAccount.%(key)s LIKE '%(txt)s'
|
||||
%(mcond)s""" % {'company': filters['company'], 'key': searchfield,
|
||||
'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype)})
|
||||
'txt': "%%%s%%" % frappe.db.escape(txt), 'mcond':get_match_cond(doctype)})
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_delivery_note(source_name, target_doc=None):
|
||||
@@ -662,3 +655,9 @@ def make_delivery_note(source_name, target_doc=None):
|
||||
}, target_doc, set_missing_values)
|
||||
|
||||
return doclist
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_sales_return(source_name, target_doc=None):
|
||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||
return make_return_doc("Sales Invoice", source_name, target_doc)
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
// render
|
||||
frappe.listview_settings['Sales Invoice'] = {
|
||||
add_fields: ["customer", "customer_name", "base_grand_total", "outstanding_amount", "due_date", "company",
|
||||
"currency"],
|
||||
"currency", "is_return"],
|
||||
get_indicator: function(doc) {
|
||||
if(flt(doc.outstanding_amount)==0) {
|
||||
if(cint(doc.is_return)==1) {
|
||||
return [__("Return"), "darkgrey", "is_return,=,1"];
|
||||
} else if(flt(doc.outstanding_amount)==0) {
|
||||
return [__("Paid"), "green", "outstanding_amount,=,0"]
|
||||
} else if (flt(doc.outstanding_amount) > 0 && doc.due_date > frappe.datetime.get_today()) {
|
||||
return [__("Unpaid"), "orange", "outstanding_amount,>,0|due_date,>,Today"]
|
||||
|
||||
@@ -4,11 +4,9 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest, copy
|
||||
import time
|
||||
from erpnext.accounts.utils import get_stock_and_account_difference
|
||||
from frappe.utils import nowdate, add_days, flt
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
|
||||
from erpnext.projects.doctype.time_log_batch.test_time_log_batch import *
|
||||
|
||||
|
||||
class TestSalesInvoice(unittest.TestCase):
|
||||
def make(self):
|
||||
@@ -393,7 +391,8 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
import test_records as jv_test_records
|
||||
|
||||
jv = frappe.get_doc(frappe.copy_doc(jv_test_records[0]))
|
||||
jv.get("accounts")[0].against_invoice = w.name
|
||||
jv.get("accounts")[0].reference_type = w.doctype
|
||||
jv.get("accounts")[0].reference_name = w.name
|
||||
jv.insert()
|
||||
jv.submit()
|
||||
|
||||
@@ -402,32 +401,6 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
jv.cancel()
|
||||
self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 561.8)
|
||||
|
||||
def test_time_log_batch(self):
|
||||
delete_time_log_and_batch()
|
||||
time_log = create_time_log()
|
||||
tlb = create_time_log_batch(time_log)
|
||||
|
||||
tlb = frappe.get_doc("Time Log Batch", tlb.name)
|
||||
tlb.submit()
|
||||
|
||||
si = frappe.get_doc(frappe.copy_doc(test_records[0]))
|
||||
si.get("items")[0].time_log_batch = tlb.name
|
||||
si.insert()
|
||||
si.submit()
|
||||
|
||||
self.assertEquals(frappe.db.get_value("Time Log Batch", tlb.name, "status"), "Billed")
|
||||
|
||||
self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Billed")
|
||||
|
||||
si.cancel()
|
||||
|
||||
self.assertEquals(frappe.db.get_value("Time Log Batch", tlb.name, "status"), "Submitted")
|
||||
|
||||
self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Batched for Billing")
|
||||
|
||||
frappe.delete_doc("Sales Invoice", si.name)
|
||||
delete_time_log_and_batch()
|
||||
|
||||
def test_sales_invoice_gl_entry_without_aii(self):
|
||||
set_perpetual_inventory(0)
|
||||
si = frappe.copy_doc(test_records[1])
|
||||
@@ -462,7 +435,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
|
||||
def test_pos_gl_entry_with_aii(self):
|
||||
set_perpetual_inventory()
|
||||
self.make_pos_setting()
|
||||
self.make_pos_profile()
|
||||
|
||||
self._insert_purchase_receipt()
|
||||
|
||||
@@ -517,19 +490,19 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
|
||||
set_perpetual_inventory(0)
|
||||
|
||||
frappe.db.sql("delete from `tabPOS Setting`")
|
||||
frappe.db.sql("delete from `tabPOS Profile`")
|
||||
|
||||
def make_pos_setting(self):
|
||||
pos_setting = frappe.get_doc({
|
||||
def make_pos_profile(self):
|
||||
pos_profile = frappe.get_doc({
|
||||
"cash_bank_account": "_Test Account Bank Account - _TC",
|
||||
"company": "_Test Company",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"currency": "INR",
|
||||
"doctype": "POS Setting",
|
||||
"doctype": "POS Profile",
|
||||
"expense_account": "_Test Account Cost for Goods Sold - _TC",
|
||||
"income_account": "Sales - _TC",
|
||||
"name": "_Test POS Setting",
|
||||
"naming_series": "_T-POS Setting-",
|
||||
"name": "_Test POS Profile",
|
||||
"naming_series": "_T-POS Profile-",
|
||||
"selling_price_list": "_Test Price List",
|
||||
"territory": "_Test Territory",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
@@ -537,8 +510,8 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"write_off_cost_center": "_Test Write Off Cost Center - _TC"
|
||||
})
|
||||
|
||||
if not frappe.db.exists("POS Setting", "_Test POS Setting"):
|
||||
pos_setting.insert()
|
||||
if not frappe.db.exists("POS Profile", "_Test POS Profile"):
|
||||
pos_profile.insert()
|
||||
|
||||
def test_si_gl_entry_with_aii_and_update_stock_with_warehouse_but_no_account(self):
|
||||
set_perpetual_inventory()
|
||||
@@ -684,17 +657,17 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
si.load_from_db()
|
||||
|
||||
self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||
where against_invoice=%s""", si.name))
|
||||
where reference_name=%s""", si.name))
|
||||
|
||||
self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||
where against_invoice=%s and credit=300""", si.name))
|
||||
where reference_name=%s and credit=300""", si.name))
|
||||
|
||||
self.assertEqual(si.outstanding_amount, 261.8)
|
||||
|
||||
si.cancel()
|
||||
|
||||
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||
where against_invoice=%s""", si.name))
|
||||
where reference_name=%s""", si.name))
|
||||
|
||||
def test_recurring_invoice(self):
|
||||
from erpnext.controllers.tests.test_recurring_document import test_recurring_document
|
||||
@@ -757,19 +730,134 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
# hack! because stock ledger entires are already inserted and are not rolled back!
|
||||
self.assertRaises(SerialNoDuplicateError, si.cancel)
|
||||
|
||||
def test_invoice_due_date_against_customers_credit_days(self):
|
||||
# set customer's credit days
|
||||
frappe.db.set_value("Customer", "_Test Customer", "credit_days_based_on", "Fixed Days")
|
||||
frappe.db.set_value("Customer", "_Test Customer", "credit_days", 10)
|
||||
|
||||
si = create_sales_invoice()
|
||||
self.assertEqual(si.due_date, add_days(nowdate(), 10))
|
||||
|
||||
# set customer's credit days is last day of the next month
|
||||
frappe.db.set_value("Customer", "_Test Customer", "credit_days_based_on", "Last Day of the Next Month")
|
||||
|
||||
si1 = create_sales_invoice(posting_date="2015-07-05")
|
||||
self.assertEqual(si1.due_date, "2015-08-31")
|
||||
|
||||
def test_return_sales_invoice(self):
|
||||
set_perpetual_inventory()
|
||||
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
|
||||
|
||||
actual_qty_0 = get_qty_after_transaction()
|
||||
|
||||
si = create_sales_invoice(qty=5, rate=500, update_stock=1)
|
||||
|
||||
actual_qty_1 = get_qty_after_transaction()
|
||||
self.assertEquals(actual_qty_0 - 5, actual_qty_1)
|
||||
|
||||
# outgoing_rate
|
||||
outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Sales Invoice",
|
||||
"voucher_no": si.name}, "stock_value_difference") / 5
|
||||
|
||||
# return entry
|
||||
si1 = create_sales_invoice(is_return=1, return_against=si.name, qty=-2, rate=500, update_stock=1)
|
||||
|
||||
actual_qty_2 = get_qty_after_transaction()
|
||||
|
||||
self.assertEquals(actual_qty_1 + 2, actual_qty_2)
|
||||
|
||||
incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
|
||||
{"voucher_type": "Sales Invoice", "voucher_no": si1.name},
|
||||
["incoming_rate", "stock_value_difference"])
|
||||
|
||||
self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
|
||||
|
||||
|
||||
# Check gl entry
|
||||
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice",
|
||||
"voucher_no": si1.name, "account": "_Test Warehouse - _TC"}, "debit")
|
||||
|
||||
self.assertEquals(gle_warehouse_amount, stock_value_difference)
|
||||
|
||||
party_credited = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice",
|
||||
"voucher_no": si1.name, "account": "Debtors - _TC", "party": "_Test Customer"}, "credit")
|
||||
|
||||
self.assertEqual(party_credited, 1000)
|
||||
|
||||
# Check outstanding amount
|
||||
self.assertFalse(si1.outstanding_amount)
|
||||
self.assertEqual(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"), 1500)
|
||||
|
||||
set_perpetual_inventory(0)
|
||||
|
||||
def test_discount_on_net_total(self):
|
||||
si = frappe.copy_doc(test_records[2])
|
||||
si.apply_discount_on = "Net Total"
|
||||
si.discount_amount = 625
|
||||
si.insert()
|
||||
|
||||
expected_values = {
|
||||
"keys": ["price_list_rate", "discount_percentage", "rate", "amount",
|
||||
"base_price_list_rate", "base_rate", "base_amount",
|
||||
"net_rate", "base_net_rate", "net_amount", "base_net_amount"],
|
||||
"_Test Item Home Desktop 100": [50, 0, 50, 500, 50, 50, 500, 25, 25, 250, 250],
|
||||
"_Test Item Home Desktop 200": [150, 0, 150, 750, 150, 150, 750, 75, 75, 375, 375],
|
||||
}
|
||||
|
||||
# check if children are saved
|
||||
self.assertEquals(len(si.get("items")),
|
||||
len(expected_values)-1)
|
||||
|
||||
# check if item values are calculated
|
||||
for d in si.get("items"):
|
||||
for i, k in enumerate(expected_values["keys"]):
|
||||
self.assertEquals(d.get(k), expected_values[d.item_code][i])
|
||||
|
||||
# check net total
|
||||
self.assertEquals(si.base_total, 1250)
|
||||
self.assertEquals(si.total, 1250)
|
||||
self.assertEquals(si.base_net_total, 625)
|
||||
self.assertEquals(si.net_total, 625)
|
||||
|
||||
# check tax calculation
|
||||
expected_values = {
|
||||
"keys": ["tax_amount", "tax_amount_after_discount_amount",
|
||||
"base_tax_amount_after_discount_amount"],
|
||||
"_Test Account Shipping Charges - _TC": [100, 100, 100],
|
||||
"_Test Account Customs Duty - _TC": [62.5, 62.5, 62.5],
|
||||
"_Test Account Excise Duty - _TC": [70, 70, 70],
|
||||
"_Test Account Education Cess - _TC": [1.4, 1.4, 1.4],
|
||||
"_Test Account S&H Education Cess - _TC": [.7, 0.7, 0.7],
|
||||
"_Test Account CST - _TC": [17.2, 17.2, 17.2],
|
||||
"_Test Account VAT - _TC": [78.13, 78.13, 78.13],
|
||||
"_Test Account Discount - _TC": [-95.49, -95.49, -95.49]
|
||||
}
|
||||
|
||||
for d in si.get("taxes"):
|
||||
for i, k in enumerate(expected_values["keys"]):
|
||||
self.assertEquals(d.get(k), expected_values[d.account_head][i])
|
||||
|
||||
|
||||
self.assertEquals(si.total_taxes_and_charges, 234.44)
|
||||
self.assertEquals(si.base_grand_total, 859.44)
|
||||
self.assertEquals(si.grand_total, 859.44)
|
||||
|
||||
|
||||
def create_sales_invoice(**args):
|
||||
si = frappe.new_doc("Sales Invoice")
|
||||
args = frappe._dict(args)
|
||||
if args.posting_date:
|
||||
si.posting_date = args.posting_date
|
||||
if args.posting_time:
|
||||
si.posting_time = args.posting_time
|
||||
si.posting_date = args.posting_date or nowdate()
|
||||
|
||||
si.company = args.company or "_Test Company"
|
||||
si.customer = args.customer or "_Test Customer"
|
||||
si.debit_to = args.debit_to or "Debtors - _TC"
|
||||
si.update_stock = args.update_stock
|
||||
si.is_pos = args.is_pos
|
||||
si.is_return = args.is_return
|
||||
si.return_against = args.return_against
|
||||
si.currency="INR"
|
||||
si.conversion_rate = 1
|
||||
|
||||
si.append("items", {
|
||||
"item_code": args.item or args.item_code or "_Test Item",
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text",
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Text",
|
||||
@@ -68,6 +68,23 @@
|
||||
"reqd": 1,
|
||||
"width": "200px"
|
||||
},
|
||||
{
|
||||
"fieldname": "image",
|
||||
"fieldtype": "Attach",
|
||||
"hidden": 1,
|
||||
"label": "Image",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "image_view",
|
||||
"fieldtype": "Image",
|
||||
"label": "Image View",
|
||||
"options": "image",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "quantity_and_rate",
|
||||
"fieldtype": "Section Break",
|
||||
@@ -98,10 +115,11 @@
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "price_list_rate",
|
||||
"fieldname": "discount_percentage",
|
||||
"fieldtype": "Percent",
|
||||
"in_list_view": 1,
|
||||
"label": "Discount (%)",
|
||||
"label": "Discount on Price List Rate (%)",
|
||||
"oldfieldname": "adj_rate",
|
||||
"oldfieldtype": "Float",
|
||||
"permlevel": 0,
|
||||
@@ -504,7 +522,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-03-23 14:56:45.641026",
|
||||
"modified": "2015-07-02 02:59:08.413213",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Item",
|
||||
|
||||
@@ -5,21 +5,25 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax
|
||||
from frappe.utils.nestedset import get_root_of
|
||||
|
||||
class SalesTaxesandChargesTemplate(Document):
|
||||
def validate(self):
|
||||
if self.is_default == 1:
|
||||
frappe.db.sql("""update `tabSales Taxes and Charges Template`
|
||||
set is_default = 0
|
||||
where ifnull(is_default,0) = 1
|
||||
and name != %s and company = %s""",
|
||||
(self.name, self.company))
|
||||
valdiate_taxes_and_charges_template(self)
|
||||
|
||||
# at least one territory
|
||||
self.validate_table_has_rows("territories")
|
||||
def valdiate_taxes_and_charges_template(doc):
|
||||
if not doc.is_default and not frappe.get_all(doc.doctype, filters={"is_default": 1}):
|
||||
doc.is_default = 1
|
||||
|
||||
for tax in self.get("taxes"):
|
||||
validate_taxes_and_charges(tax)
|
||||
validate_inclusive_tax(tax, self)
|
||||
if doc.is_default == 1:
|
||||
frappe.db.sql("""update `tab{0}` set is_default = 0
|
||||
where ifnull(is_default,0) = 1 and name != %s and company = %s""".format(doc.doctype),
|
||||
(doc.name, doc.company))
|
||||
|
||||
if doc.meta.get_field("territories"):
|
||||
if not doc.territories:
|
||||
doc.append("territories", {"territory": get_root_of("Territory") })
|
||||
|
||||
for tax in doc.get("taxes"):
|
||||
validate_taxes_and_charges(tax)
|
||||
validate_inclusive_tax(tax, doc)
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import flt, cstr
|
||||
from frappe.utils import flt, cstr, cint
|
||||
from frappe import _
|
||||
from frappe.model.meta import get_field_precision
|
||||
from erpnext.accounts.utils import validate_expense_against_budget
|
||||
|
||||
|
||||
class StockAccountInvalidTransaction(frappe.ValidationError): pass
|
||||
|
||||
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True,
|
||||
update_outstanding='Yes'):
|
||||
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes'):
|
||||
if gl_map:
|
||||
if not cancel:
|
||||
gl_map = process_gl_map(gl_map, merge_entries)
|
||||
@@ -50,33 +50,28 @@ def merge_similar_entries(gl_map):
|
||||
merged_gl_map.append(entry)
|
||||
|
||||
# filter zero debit and credit entries
|
||||
merged_gl_map = filter(lambda x: flt(x.debit)!=0 or flt(x.credit)!=0, merged_gl_map)
|
||||
merged_gl_map = filter(lambda x: flt(x.debit, 9)!=0 or flt(x.credit, 9)!=0, merged_gl_map)
|
||||
return merged_gl_map
|
||||
|
||||
def check_if_in_list(gle, gl_map):
|
||||
for e in gl_map:
|
||||
if e.account == gle.account and \
|
||||
cstr(e.get('against_voucher'))==cstr(gle.get('against_voucher')) \
|
||||
and cstr(e.get('against_voucher_type')) == \
|
||||
cstr(gle.get('against_voucher_type')) \
|
||||
and cstr(e.get('cost_center')) == cstr(gle.get('cost_center')):
|
||||
return e
|
||||
if e.account == gle.account \
|
||||
and cstr(e.get('party_type'))==cstr(gle.get('party_type')) \
|
||||
and cstr(e.get('party'))==cstr(gle.get('party')) \
|
||||
and cstr(e.get('against_voucher'))==cstr(gle.get('against_voucher')) \
|
||||
and cstr(e.get('against_voucher_type')) == cstr(gle.get('against_voucher_type')) \
|
||||
and cstr(e.get('cost_center')) == cstr(gle.get('cost_center')):
|
||||
return e
|
||||
|
||||
def save_entries(gl_map, adv_adj, update_outstanding):
|
||||
validate_account_for_auto_accounting_for_stock(gl_map)
|
||||
|
||||
total_debit = total_credit = 0.0
|
||||
round_off_debit_credit(gl_map)
|
||||
|
||||
for entry in gl_map:
|
||||
make_entry(entry, adv_adj, update_outstanding)
|
||||
# check against budget
|
||||
validate_expense_against_budget(entry)
|
||||
|
||||
# update total debit / credit
|
||||
total_debit += flt(entry.debit)
|
||||
total_credit += flt(entry.credit)
|
||||
|
||||
validate_total_debit_credit(total_debit, total_credit, gl_map)
|
||||
|
||||
def make_entry(args, adv_adj, update_outstanding):
|
||||
args.update({"doctype": "GL Entry"})
|
||||
gle = frappe.get_doc(args)
|
||||
@@ -85,18 +80,62 @@ def make_entry(args, adv_adj, update_outstanding):
|
||||
gle.run_method("on_update_with_args", adv_adj, update_outstanding)
|
||||
gle.submit()
|
||||
|
||||
def validate_total_debit_credit(total_debit, total_credit, gl_map):
|
||||
if abs(total_debit - total_credit) > 0.005:
|
||||
frappe.throw(_("Debit and Credit not equal for {0} #{1}. Difference is {2}.").format(gl_map[0].voucher_type, gl_map[0].voucher_no, total_debit - total_credit))
|
||||
|
||||
def validate_account_for_auto_accounting_for_stock(gl_map):
|
||||
if gl_map[0].voucher_type=="Journal Entry":
|
||||
aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
|
||||
where account_type = 'Warehouse' and ifnull(warehouse, '')!=''""")]
|
||||
if cint(frappe.db.get_single_value("Accounts Settings", "auto_accounting_for_stock")) \
|
||||
and gl_map[0].voucher_type=="Journal Entry":
|
||||
aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
|
||||
where account_type = 'Warehouse' and ifnull(warehouse, '')!=''""")]
|
||||
|
||||
for entry in gl_map:
|
||||
if entry.account in aii_accounts:
|
||||
frappe.throw(_("Account: {0} can only be updated via Stock Transactions").format(entry.account), StockAccountInvalidTransaction)
|
||||
for entry in gl_map:
|
||||
if entry.account in aii_accounts:
|
||||
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
|
||||
.format(entry.account), StockAccountInvalidTransaction)
|
||||
|
||||
def round_off_debit_credit(gl_map):
|
||||
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
|
||||
currency=frappe.db.get_value("Company", gl_map[0].company, "default_currency", cache=True))
|
||||
|
||||
debit_credit_diff = 0.0
|
||||
for entry in gl_map:
|
||||
entry.debit = flt(entry.debit, precision)
|
||||
entry.credit = flt(entry.credit, precision)
|
||||
debit_credit_diff += entry.debit - entry.credit
|
||||
|
||||
debit_credit_diff = flt(debit_credit_diff, precision)
|
||||
if abs(debit_credit_diff) >= (5.0 / (10**precision)):
|
||||
frappe.throw(_("Debit and Credit not equal for {0} #{1}. Difference is {2}.")
|
||||
.format(gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff))
|
||||
|
||||
elif abs(debit_credit_diff) >= (1.0 / (10**precision)):
|
||||
make_round_off_gle(gl_map, debit_credit_diff)
|
||||
|
||||
def make_round_off_gle(gl_map, debit_credit_diff):
|
||||
round_off_account, round_off_cost_center = frappe.db.get_value("Company", gl_map[0].company,
|
||||
["round_off_account", "round_off_cost_center"]) or [None, None]
|
||||
if not round_off_account:
|
||||
frappe.throw(_("Please mention Round Off Account in Company"))
|
||||
|
||||
if not round_off_cost_center:
|
||||
frappe.throw(_("Please mention Round Off Cost Center in Company"))
|
||||
|
||||
|
||||
round_off_gle = frappe._dict()
|
||||
for k in ["voucher_type", "voucher_no", "company",
|
||||
"posting_date", "remarks", "fiscal_year", "is_opening"]:
|
||||
round_off_gle[k] = gl_map[0][k]
|
||||
|
||||
round_off_gle.update({
|
||||
"account": round_off_account,
|
||||
"debit": abs(debit_credit_diff) if debit_credit_diff < 0 else 0,
|
||||
"credit": debit_credit_diff if debit_credit_diff > 0 else 0,
|
||||
"cost_center": round_off_cost_center,
|
||||
"party_type": None,
|
||||
"party": None,
|
||||
"against_voucher_type": None,
|
||||
"against_voucher": None
|
||||
})
|
||||
|
||||
gl_map.append(round_off_gle)
|
||||
|
||||
|
||||
def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
|
||||
|
||||
@@ -55,7 +55,7 @@ frappe.pages["Accounts Browser"].on_page_load = function(wrapper){
|
||||
.change(function() {
|
||||
var ctype = frappe.get_route()[1] || 'Account';
|
||||
erpnext.account_chart = new erpnext.AccountsChart(ctype, $(this).val(),
|
||||
chart_area.get(0));
|
||||
chart_area.get(0), wrapper.page);
|
||||
})
|
||||
|
||||
// load up companies
|
||||
@@ -75,19 +75,23 @@ frappe.pages["Accounts Browser"].on_page_show = function(wrapper){
|
||||
// set route
|
||||
var ctype = frappe.get_route()[1] || 'Account';
|
||||
|
||||
|
||||
|
||||
if(erpnext.account_chart && erpnext.account_chart.ctype != ctype) {
|
||||
wrapper.$company_select.change();
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.AccountsChart = Class.extend({
|
||||
init: function(ctype, company, wrapper) {
|
||||
init: function(ctype, company, wrapper, page) {
|
||||
$(wrapper).empty();
|
||||
var me = this;
|
||||
me.ctype = ctype;
|
||||
me.can_create = frappe.model.can_create(this.ctype);
|
||||
me.can_delete = frappe.model.can_delete(this.ctype);
|
||||
me.can_write = frappe.model.can_write(this.ctype);
|
||||
me.page = page;
|
||||
me.set_title();
|
||||
|
||||
// __("Accounts"), __("Cost Centers")
|
||||
|
||||
@@ -169,9 +173,9 @@ erpnext.AccountsChart = Class.extend({
|
||||
set_title: function(val) {
|
||||
var chart_str = this.ctype=="Account" ? __("Chart of Accounts") : __("Chart of Cost Centers");
|
||||
if(val) {
|
||||
wrapper.page.set_title(chart_str + " - " + cstr(val));
|
||||
this.page.set_title(chart_str + " - " + cstr(val));
|
||||
} else {
|
||||
wrapper.page.set_title(chart_str);
|
||||
this.page.set_title(chart_str);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -198,7 +202,7 @@ erpnext.AccountsChart = Class.extend({
|
||||
title:__('New Account'),
|
||||
fields: [
|
||||
{fieldtype:'Data', fieldname:'account_name', label:__('New Account Name'), reqd:true,
|
||||
description: __("Name of new Account. Note: Please don't create accounts for Customers and Suppliers, they are created automatically from the Customer and Supplier master")},
|
||||
description: __("Name of new Account. Note: Please don't create accounts for Customers and Suppliers")},
|
||||
{fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
|
||||
description: __('Further accounts can be made under Groups, but entries can be made against non-Groups')},
|
||||
{fieldtype:'Select', fieldname:'account_type', label:__('Account Type'),
|
||||
|
||||
@@ -35,7 +35,7 @@ frappe.pages['pos'].on_page_load = function(wrapper) {
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: "/api/resource/POS Setting",
|
||||
url: "/api/resource/POS Profile",
|
||||
success: function(data) {
|
||||
if(!data.data.length) {
|
||||
page.main.find(".pos-setting-message").removeClass('hide');
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<button class="btn btn-primary btn-lg">{%= __("Start") %}</button>
|
||||
</p>
|
||||
<p class="pos-setting-message hide">
|
||||
<a class="btn btn-default btn-sm" href="#Form/POS Setting/New POS Setting">
|
||||
{%= __("Make new POS Setting") %}</a>
|
||||
<a class="btn btn-default btn-sm" href="#Form/POS Profile/New POS Profile">
|
||||
{%= __("Make new POS Profile") %}</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import datetime
|
||||
from frappe import _, msgprint, scrub
|
||||
from frappe.defaults import get_user_permissions
|
||||
from frappe.utils import add_days, getdate, formatdate, flt
|
||||
from frappe.utils import add_days, getdate, formatdate, flt, get_first_day, date_diff, nowdate
|
||||
from erpnext.utilities.doctype.address.address import get_address_display
|
||||
from erpnext.utilities.doctype.contact.contact import get_contact_details
|
||||
|
||||
@@ -16,12 +17,16 @@ def get_party_details(party=None, account=None, party_type="Customer", company=N
|
||||
|
||||
if not party:
|
||||
return {}
|
||||
|
||||
if not frappe.db.exists(party_type, party):
|
||||
frappe.throw(_("{0}: {1} does not exists").format(party_type, party))
|
||||
|
||||
return _get_party_details(party, account, party_type,
|
||||
company, posting_date, price_list, currency, doctype)
|
||||
|
||||
def _get_party_details(party=None, account=None, party_type="Customer", company=None,
|
||||
posting_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False):
|
||||
|
||||
out = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, doctype))
|
||||
|
||||
party = out[party_type.lower()]
|
||||
@@ -69,9 +74,17 @@ def set_contact_details(out, party, party_type):
|
||||
{party_type.lower(): party.name, "is_primary_contact":1}, "name")
|
||||
|
||||
if not out.contact_person:
|
||||
return
|
||||
|
||||
out.update(get_contact_details(out.contact_person))
|
||||
out.update({
|
||||
"contact_person": None,
|
||||
"contact_display": None,
|
||||
"contact_email": None,
|
||||
"contact_mobile": None,
|
||||
"contact_phone": None,
|
||||
"contact_designation": None,
|
||||
"contact_department": None
|
||||
})
|
||||
else:
|
||||
out.update(get_contact_details(out.contact_person))
|
||||
|
||||
def set_other_values(out, party, party_type):
|
||||
# copy
|
||||
@@ -154,43 +167,54 @@ def get_party_account(company, party, party_type):
|
||||
|
||||
return account
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_due_date(posting_date, party_type, party, company):
|
||||
"""Set Due Date = Posting Date + Credit Days"""
|
||||
due_date = None
|
||||
if posting_date:
|
||||
credit_days = get_credit_days(party_type, party, company)
|
||||
due_date = add_days(posting_date, credit_days) if credit_days else posting_date
|
||||
|
||||
if posting_date and party:
|
||||
due_date = posting_date
|
||||
if party_type=="Customer":
|
||||
credit_days_based_on, credit_days = get_credit_days(party_type, party, company)
|
||||
if credit_days_based_on == "Fixed Days" and credit_days:
|
||||
due_date = add_days(posting_date, credit_days)
|
||||
elif credit_days_based_on == "Last Day of the Next Month":
|
||||
due_date = (get_first_day(posting_date, 0, 2) + datetime.timedelta(-1)).strftime("%Y-%m-%d")
|
||||
else:
|
||||
credit_days = get_credit_days(party_type, party, company)
|
||||
if credit_days:
|
||||
due_date = add_days(posting_date, credit_days)
|
||||
|
||||
return due_date
|
||||
|
||||
def get_credit_days(party_type, party, company):
|
||||
if not party:
|
||||
return None
|
||||
|
||||
party_group_doctype = "Customer Group" if party_type=="Customer" else "Supplier Type"
|
||||
credit_days, party_group = frappe.db.get_value(party_type, party, ["credit_days", frappe.scrub(party_group_doctype)])
|
||||
|
||||
if not credit_days:
|
||||
credit_days = frappe.db.get_value(party_group_doctype, party_group, "credit_days") or \
|
||||
frappe.db.get_value("Company", company, "credit_days")
|
||||
|
||||
return credit_days
|
||||
|
||||
def validate_due_date(posting_date, due_date, party_type, party, company):
|
||||
credit_days = get_credit_days(party_type, party, company)
|
||||
|
||||
posting_date, due_date = getdate(posting_date), getdate(due_date)
|
||||
diff = (due_date - posting_date).days
|
||||
|
||||
if diff < 0:
|
||||
frappe.throw(_("Due Date cannot be before Posting Date"))
|
||||
elif credit_days is not None and diff > flt(credit_days):
|
||||
is_credit_controller = frappe.db.get_value("Accounts Settings", None,
|
||||
"credit_controller") in frappe.get_roles()
|
||||
|
||||
if is_credit_controller:
|
||||
msgprint(_("Note: Due / Reference Date exceeds allowed customer credit days by {0} day(s)")
|
||||
.format(diff - flt(credit_days)))
|
||||
if party_type and party:
|
||||
if party_type == "Customer":
|
||||
credit_days_based_on, credit_days, customer_group = \
|
||||
frappe.db.get_value(party_type, party, ["credit_days_based_on", "credit_days", "customer_group"])
|
||||
|
||||
if not credit_days_based_on:
|
||||
credit_days_based_on, credit_days = \
|
||||
frappe.db.get_value("Customer Group", customer_group, ["credit_days_based_on", "credit_days"]) \
|
||||
or frappe.db.get_value("Company", company, ["credit_days_based_on", "credit_days"])
|
||||
|
||||
return credit_days_based_on, credit_days
|
||||
else:
|
||||
max_due_date = formatdate(add_days(posting_date, credit_days))
|
||||
frappe.throw(_("Due / Reference Date cannot be after {0}").format(max_due_date))
|
||||
credit_days, supplier_type = frappe.db.get_value(party_type, party, ["credit_days", "supplier_type"])
|
||||
if not credit_days:
|
||||
credit_days = frappe.db.get_value("Supplier Type", supplier_type, "credit_days") \
|
||||
or frappe.db.get_value("Company", company, "credit_days")
|
||||
|
||||
return credit_days
|
||||
|
||||
def validate_due_date(posting_date, due_date, party_type, party, company):
|
||||
if getdate(due_date) < getdate(posting_date):
|
||||
frappe.throw(_("Due Date cannot be before Posting Date"))
|
||||
else:
|
||||
default_due_date = get_due_date(posting_date, party_type, party, company)
|
||||
if default_due_date != posting_date and getdate(due_date) > getdate(default_due_date):
|
||||
is_credit_controller = frappe.db.get_single_value("Accounts Settings", "credit_controller") in frappe.get_roles()
|
||||
if is_credit_controller:
|
||||
msgprint(_("Note: Due / Reference Date exceeds allowed customer credit days by {0} day(s)")
|
||||
.format(date_diff(due_date, default_due_date)))
|
||||
else:
|
||||
frappe.throw(_("Due / Reference Date cannot be after {0}").format(formatdate(default_due_date)))
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"creation": "2012-04-11 13:16:56",
|
||||
"doc_type": "Journal Entry",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format",
|
||||
"html": "<div style=\"position: relative\">\n\n\t{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Payment Advice\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n{%- for label, value in (\n (_(\"Voucher Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Reference / Cheque No.\"), doc.cheque_no),\n (_(\"Reference / Cheque Date\"), frappe.utils.formatdate(doc.cheque_date))\n ) -%}\n <div class=\"row\">\n <div class=\"col-xs-4\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-8\">{{ value }}</div>\n </div>\n{%- endfor -%}\n\t<hr>\n\t<p>{{ _(\"This amount is in full / part settlement of the listed bills\") }}:</p>\n{%- for label, value in (\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"total_amount\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"References\"), doc.remark)\n ) -%}\n <div class=\"row\">\n <div class=\"col-xs-4\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-8\">{{ value }}</div>\n </div>\n {%- endfor -%}\n <hr>\n\t<div style=\"position: absolute; top: 14cm; left: 0cm;\">\n\t\tPrepared By</div>\n\t<div style=\"position: absolute; top: 14cm; left: 5.5cm;\">\n\t\tAuthorised Signatory</div>\n\t<div style=\"position: absolute; top: 14cm; left: 11cm;\">\n\t\tReceived Payment as Above</div>\n\t<div style=\"position: absolute; top: 16.4cm; left: 5.9cm;\">\n\t\t<strong>_____________</strong></div>\n\t<div style=\"position: absolute; top: 16.7cm; left: 6cm;\">\n\t\t<strong>A/C Payee</strong></div>\n\t<div style=\"position: absolute; top: 16.7cm; left: 5.9cm;\">\n\t\t<strong>_____________</strong></div>\n\t<div style=\"position: absolute; top: 16.9cm; left: 12cm;\">\n\t\t{{ frappe.utils.formatdate(doc.cheque_date) }}</div>\n\t<div style=\"position: absolute; top: 17.9cm; left: 1cm;\">\n\t\t{{ doc.pay_to_recd_from }}</div>\n\t<div style=\"position: absolute; top: 18.6cm; left: 1cm; width: 7cm;\">\n\t\t{{ doc.total_amount_in_words }}</div>\n\t<div style=\"position: absolute; top: 19.7cm; left: 12cm;\">\n\t\t{{ doc.total_amount }}</div>\n</div>",
|
||||
"idx": 1,
|
||||
"modified": "2015-01-12 11:03:17.032512",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cheque Printing Format",
|
||||
"owner": "Administrator",
|
||||
"print_format_type": "Server",
|
||||
"creation": "2012-04-11 13:16:56",
|
||||
"custom_format": 1,
|
||||
"doc_type": "Journal Entry",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format",
|
||||
"html": "<div style=\"position: relative\">\n\n\t{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Payment Advice\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n{%- for label, value in (\n (_(\"Voucher Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Reference / Cheque No.\"), doc.cheque_no),\n (_(\"Reference / Cheque Date\"), frappe.utils.formatdate(doc.cheque_date))\n ) -%}\n <div class=\"row\">\n <div class=\"col-xs-4\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-8\">{{ value }}</div>\n </div>\n{%- endfor -%}\n\t<hr>\n\t<p>{{ _(\"This amount is in full / part settlement of the listed bills\") }}:</p>\n{%- for label, value in (\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"total_amount\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"References\"), doc.remark)\n ) -%}\n <div class=\"row\">\n <div class=\"col-xs-4\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-8\">{{ value }}</div>\n </div>\n {%- endfor -%}\n <hr>\n\t<div style=\"position: absolute; top: 14cm; left: 0cm;\">\n\t\tPrepared By</div>\n\t<div style=\"position: absolute; top: 14cm; left: 5.5cm;\">\n\t\tAuthorised Signatory</div>\n\t<div style=\"position: absolute; top: 14cm; left: 11cm;\">\n\t\tReceived Payment as Above</div>\n\t<div style=\"position: absolute; top: 16.4cm; left: 5.9cm;\">\n\t\t<strong>_____________</strong></div>\n\t<div style=\"position: absolute; top: 16.7cm; left: 6cm;\">\n\t\t<strong>A/C Payee</strong></div>\n\t<div style=\"position: absolute; top: 16.7cm; left: 5.9cm;\">\n\t\t<strong>_____________</strong></div>\n\t<div style=\"position: absolute; top: 16.9cm; left: 12cm;\">\n\t\t{{ frappe.utils.formatdate(doc.cheque_date) }}</div>\n\t<div style=\"position: absolute; top: 17.9cm; left: 1cm;\">\n\t\t{{ doc.pay_to_recd_from }}</div>\n\t<div style=\"position: absolute; top: 18.6cm; left: 1cm; width: 7cm;\">\n\t\t{{ doc.total_amount_in_words }}</div>\n\t<div style=\"position: absolute; top: 19.7cm; left: 12cm;\">\n\t\t{{ doc.get_formatted(\"total_amount\") }}</div>\n</div>",
|
||||
"idx": 1,
|
||||
"modified": "2015-05-29 01:57:51.203850",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Cheque Printing Format",
|
||||
"owner": "Administrator",
|
||||
"print_format_type": "Server",
|
||||
"standard": "Yes"
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
{
|
||||
"creation": "2014-08-28 11:11:39.796473",
|
||||
"disabled": 0,
|
||||
"doc_type": "Journal Entry",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format",
|
||||
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Credit Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Credit To\"), doc.pay_to_recd_from),\n (_(\"Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"total_amount\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n\n <div class=\"row\">\n <div class=\"col-xs-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n\n",
|
||||
"idx": 2,
|
||||
"modified": "2015-01-12 11:02:25.716825",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Credit Note",
|
||||
"owner": "Administrator",
|
||||
"parent": "Journal Entry",
|
||||
"parentfield": "__print_formats",
|
||||
"parenttype": "DocType",
|
||||
"print_format_type": "Server",
|
||||
"creation": "2014-08-28 11:11:39.796473",
|
||||
"custom_format": 0,
|
||||
"disabled": 0,
|
||||
"doc_type": "Journal Entry",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format",
|
||||
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Credit Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Credit To\"), doc.pay_to_recd_from),\n (_(\"Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"total_amount\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n\n <div class=\"row\">\n <div class=\"col-xs-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n\n",
|
||||
"idx": 2,
|
||||
"modified": "2015-07-22 17:42:01.560817",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Credit Note",
|
||||
"owner": "Administrator",
|
||||
"parent": "Journal Entry",
|
||||
"parentfield": "__print_formats",
|
||||
"parenttype": "DocType",
|
||||
"print_format_type": "Server",
|
||||
"standard": "Yes"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"creation": "2015-07-22 17:45:22.220567",
|
||||
"custom_format": 1,
|
||||
"disabled": 0,
|
||||
"doc_type": "Sales Invoice",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format",
|
||||
"font": "Default",
|
||||
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 6in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{{ doc.select_print_heading or _(\"Credit Note\") }}<br>\n</p>\n\n<hr>\n\n{%- for label, value in (\n (_(\"Receipt No\"), doc.name),\n (_(\"Date\"), doc.get_formatted(\"posting_date\")),\n\t(_(\"Customer\"), doc.customer_name),\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"grand_total\", absolute_value=True) + \"</strong><br>\" + (doc.in_words or \"\")),\n\t(_(\"Against\"), doc.return_against),\n (_(\"Remarks\"), doc.remarks)\n) -%}\n\n\t\t<div class=\"row\">\n\t\t <div class=\"col-xs-4\"><label class=\"text-right\">{{ label }}</label></div>\n\t\t <div class=\"col-xs-8\">{{ value }}</div>\n\t\t</div>\n{%- endfor -%}\n\n<hr>\n<br>\n<p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n</p>",
|
||||
"modified": "2015-07-22 17:45:22.220567",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Credit Note - Negative Invoice",
|
||||
"owner": "Administrator",
|
||||
"print_format_builder": 0,
|
||||
"print_format_type": "Server",
|
||||
"standard": "Yes"
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"add_total_row": 1,
|
||||
"apply_user_permissions": 1,
|
||||
"creation": "2013-04-22 16:16:03",
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 1,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2014-06-03 07:18:10.985354",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Payable",
|
||||
"owner": "Administrator",
|
||||
"ref_doctype": "Purchase Invoice",
|
||||
"report_name": "Accounts Payable",
|
||||
"report_type": "Report Builder"
|
||||
}
|
||||
"add_total_row": 1,
|
||||
"apply_user_permissions": 1,
|
||||
"creation": "2013-04-22 16:16:03",
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 1,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2015-07-24 01:08:20.996267",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Payable",
|
||||
"owner": "Administrator",
|
||||
"ref_doctype": "Purchase Invoice",
|
||||
"report_name": "Accounts Payable",
|
||||
"report_type": "Script Report"
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ class ReceivablePayableReport(object):
|
||||
currency_precision = get_currency_precision() or 2
|
||||
dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit"
|
||||
|
||||
voucher_details = self.get_voucher_details()
|
||||
voucher_details = self.get_voucher_details(args.get("party_type"))
|
||||
|
||||
future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type"))
|
||||
|
||||
@@ -153,23 +153,26 @@ class ReceivablePayableReport(object):
|
||||
|
||||
return self.party_map
|
||||
|
||||
def get_voucher_details(self):
|
||||
def get_voucher_details(self, party_type):
|
||||
voucher_details = frappe._dict()
|
||||
|
||||
if party_type == "Customer":
|
||||
for si in frappe.db.sql("""select name, due_date
|
||||
from `tabSales Invoice` where docstatus=1""", as_dict=1):
|
||||
voucher_details.setdefault(si.name, si)
|
||||
|
||||
for si in frappe.db.sql("""select name, due_date
|
||||
from `tabSales Invoice` where docstatus=1""", as_dict=1):
|
||||
voucher_details.setdefault(si.name, si)
|
||||
|
||||
for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date
|
||||
from `tabPurchase Invoice` where docstatus=1""", as_dict=1):
|
||||
voucher_details.setdefault(pi.name, pi)
|
||||
if party_type == "Supplier":
|
||||
for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date
|
||||
from `tabPurchase Invoice` where docstatus=1""", as_dict=1):
|
||||
voucher_details.setdefault(pi.name, pi)
|
||||
|
||||
return voucher_details
|
||||
|
||||
def get_gl_entries(self, party_type):
|
||||
if not hasattr(self, "gl_entries"):
|
||||
conditions, values = self.prepare_conditions(party_type)
|
||||
self.gl_entries = frappe.db.sql("""select * from `tabGL Entry`
|
||||
self.gl_entries = frappe.db.sql("""select name, posting_date, account, party_type, party, debit, credit,
|
||||
voucher_type, voucher_no, against_voucher_type, against_voucher from `tabGL Entry`
|
||||
where docstatus < 2 and party_type=%s {0} order by posting_date, party"""
|
||||
.format(conditions), values, as_dict=True)
|
||||
|
||||
@@ -187,7 +190,7 @@ class ReceivablePayableReport(object):
|
||||
|
||||
if self.filters.get(party_type_field):
|
||||
conditions.append("party=%s")
|
||||
values.append(self.filters.get(party_type_field))
|
||||
values.append(self.filters.get(party_type_field))
|
||||
|
||||
return " and ".join(conditions), values
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ def execute(filters=None):
|
||||
def get_provisional_profit_loss(asset, liability, equity, period_list):
|
||||
if asset and (liability or equity):
|
||||
provisional_profit_loss = {
|
||||
"account_name": _("Provisional Profit / Loss (Credit)"),
|
||||
"account_name": "'" + _("Provisional Profit / Loss (Credit)") + "'",
|
||||
"account": None,
|
||||
"warn_if_negative": True
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ def execute(filters=None):
|
||||
data += [
|
||||
get_balance_row(_("System Balance"), balance_as_per_system),
|
||||
[""]*len(columns),
|
||||
["", _("Amounts not reflected in bank"), total_debit, total_credit, "", "", "", ""],
|
||||
["", '"' + _("Amounts not reflected in bank") + '"', total_debit, total_credit, "", "", "", ""],
|
||||
get_balance_row(_("Amounts not reflected in system"), amounts_not_reflected_in_system),
|
||||
[""]*len(columns),
|
||||
get_balance_row(_("Expected balance as per bank"), bank_bal)
|
||||
@@ -68,6 +68,6 @@ def get_entries(filters):
|
||||
|
||||
def get_balance_row(label, amount):
|
||||
if amount > 0:
|
||||
return ["", label, amount, 0, "", "", "", ""]
|
||||
return ["", '"' + label + '"', amount, 0, "", "", "", ""]
|
||||
else:
|
||||
return ["", label, 0, abs(amount), "", "", "", ""]
|
||||
return ["", '"' + label + '"', 0, abs(amount), "", "", "", ""]
|
||||
|
||||
@@ -83,7 +83,7 @@ def get_data(company, root_type, balance_must_be, period_list, ignore_closing_en
|
||||
gl_entries_by_account = get_gl_entries(company, period_list[0]["from_date"], period_list[-1]["to_date"],
|
||||
accounts[0].lft, accounts[0].rgt, ignore_closing_entries=ignore_closing_entries)
|
||||
|
||||
calculate_values(accounts, gl_entries_by_account, period_list)
|
||||
calculate_values(accounts_by_name, gl_entries_by_account, period_list)
|
||||
accumulate_values_into_parents(accounts, accounts_by_name, period_list)
|
||||
out = prepare_data(accounts, balance_must_be, period_list)
|
||||
|
||||
@@ -92,16 +92,14 @@ def get_data(company, root_type, balance_must_be, period_list, ignore_closing_en
|
||||
|
||||
return out
|
||||
|
||||
def calculate_values(accounts, gl_entries_by_account, period_list):
|
||||
for d in accounts:
|
||||
for name in ([d.name] + (d.collapsed_children or [])):
|
||||
for entry in gl_entries_by_account.get(name, []):
|
||||
for period in period_list:
|
||||
entry.posting_date = getdate(entry.posting_date)
|
||||
|
||||
# check if posting date is within the period
|
||||
if entry.posting_date <= period.to_date:
|
||||
d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit)
|
||||
def calculate_values(accounts_by_name, gl_entries_by_account, period_list):
|
||||
for entries in gl_entries_by_account.values():
|
||||
for entry in entries:
|
||||
d = accounts_by_name.get(entry.account)
|
||||
for period in period_list:
|
||||
# check if posting date is within the period
|
||||
if entry.posting_date <= period.to_date:
|
||||
d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit)
|
||||
|
||||
|
||||
def accumulate_values_into_parents(accounts, accounts_by_name, period_list):
|
||||
@@ -146,7 +144,7 @@ def prepare_data(accounts, balance_must_be, period_list):
|
||||
|
||||
def add_total_row(out, balance_must_be, period_list):
|
||||
row = {
|
||||
"account_name": _("Total ({0})").format(balance_must_be),
|
||||
"account_name": "'" + _("Total ({0})").format(balance_must_be) + "'",
|
||||
"account": None
|
||||
}
|
||||
for period in period_list:
|
||||
@@ -159,22 +157,8 @@ def add_total_row(out, balance_must_be, period_list):
|
||||
out.append({})
|
||||
|
||||
def get_accounts(company, root_type):
|
||||
# root lft, rgt
|
||||
root_account = frappe.db.sql("""select lft, rgt from `tabAccount`
|
||||
where company=%s and root_type=%s and ifnull(parent_account, '') = ''
|
||||
order by lft limit 1""",
|
||||
(company, root_type), as_dict=True)
|
||||
|
||||
if not root_account:
|
||||
return None
|
||||
|
||||
lft, rgt = root_account[0].lft, root_account[0].rgt
|
||||
|
||||
accounts = frappe.db.sql("""select * from `tabAccount`
|
||||
where company=%(company)s and lft >= %(lft)s and rgt <= %(rgt)s order by lft""",
|
||||
{ "company": company, "lft": lft, "rgt": rgt }, as_dict=True)
|
||||
|
||||
return accounts
|
||||
return frappe.db.sql("""select name, parent_account, lft, rgt, root_type, report_type, account_name from `tabAccount`
|
||||
where company=%s and root_type=%s order by lft""", (company, root_type), as_dict=True)
|
||||
|
||||
def filter_accounts(accounts, depth=10):
|
||||
parent_children_map = {}
|
||||
@@ -196,18 +180,10 @@ def filter_accounts(accounts, depth=10):
|
||||
filtered_accounts.append(child)
|
||||
add_to_list(child.name, level + 1)
|
||||
|
||||
else:
|
||||
# include all children at level lower than the depth
|
||||
parent_account = accounts_by_name[parent]
|
||||
parent_account["collapsed_children"] = []
|
||||
for d in accounts:
|
||||
if d.lft > parent_account.lft and d.rgt < parent_account.rgt:
|
||||
parent_account["collapsed_children"].append(d.name)
|
||||
|
||||
add_to_list(None, 0)
|
||||
|
||||
return filtered_accounts, accounts_by_name
|
||||
|
||||
|
||||
def sort_root_accounts(roots):
|
||||
"""Sort root types as Asset, Liability, Equity, Income, Expense"""
|
||||
|
||||
@@ -234,7 +210,7 @@ def get_gl_entries(company, from_date, to_date, root_lft, root_rgt, ignore_closi
|
||||
if from_date:
|
||||
additional_conditions.append("and posting_date >= %(from_date)s")
|
||||
|
||||
gl_entries = frappe.db.sql("""select * from `tabGL Entry`
|
||||
gl_entries = frappe.db.sql("""select posting_date, account, debit, credit, is_opening from `tabGL Entry`
|
||||
where company=%(company)s
|
||||
{additional_conditions}
|
||||
and posting_date <= %(to_date)s
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<div style="margin-bottom: 7px;" class="text-center">
|
||||
{%= frappe.boot.letter_heads[frappe.defaults.get_default("letter_head")] %}
|
||||
{%= frappe.boot.letter_heads[filters.letter_head || frappe.defaults.get_default("letter_head")] %}
|
||||
</div>
|
||||
<h2 class="text-center">{%= __("Statement of Account") %}</h2>
|
||||
<h4 class="text-center">{%= filters.account && (filters.account + ", ") || "" %} {%= filters.company %}</h4>
|
||||
<h4 class="text-center">{%= (filters.party || filters.account) && ((filters.party || filters.account) + ", ") || "" %} {%= filters.company %}</h4>
|
||||
<h5 class="text-center">
|
||||
{%= dateutil.str_to_user(filters.from_date) %}
|
||||
{%= __("to") %}
|
||||
@@ -26,15 +26,20 @@
|
||||
<td>{%= dateutil.str_to_user(data[i][__("Posting Date")]) %}</td>
|
||||
<td>{%= data[i][__("Voucher Type")] %}
|
||||
<br>{%= data[i][__("Voucher No")] %}</td>
|
||||
<td>{%= data[i][__("Account")] %}
|
||||
<br>{%= __("Against") %}: {%= data[i][__("Against Account")] %}
|
||||
<td>
|
||||
{% if(!(filters.party || filters.account)) { %}
|
||||
{%= data[i][__("Party")] || data[i][__("Account")] %}
|
||||
<br>
|
||||
{% } %}
|
||||
|
||||
{{ __("Against") }}: {%= data[i][__("Against Account")] %}
|
||||
<br>{%= __("Remarks") %}: {%= data[i][__("Remarks")] %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i][__("Debit")]) %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i][__("Credit")]) %}</td>
|
||||
{% } else { %}
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td><b>{%= data[i][__("Account")] || " " %}</b></td>
|
||||
<td><b>{%= frappe.format(data[i][__("Account")], {fieldtype: "Link"}) || " " %}</b></td>
|
||||
<td style="text-align: right">
|
||||
{%= data[i][__("Account")] && format_currency(data[i][__("Debit")]) %}</td>
|
||||
<td style="text-align: right">
|
||||
|
||||
@@ -53,13 +53,9 @@ frappe.query_reports["General Ledger"] = {
|
||||
{
|
||||
"fieldname":"party_type",
|
||||
"label": __("Party Type"),
|
||||
"fieldtype": "Link",
|
||||
"options": "DocType",
|
||||
"get_query": function() {
|
||||
return {
|
||||
filters: {"name": ["in", ["Customer", "Supplier"]]}
|
||||
}
|
||||
}
|
||||
"fieldtype": "Select",
|
||||
"options": ["", "Customer", "Supplier"],
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"fieldname":"party",
|
||||
@@ -84,6 +80,13 @@ frappe.query_reports["General Ledger"] = {
|
||||
"fieldname":"group_by_account",
|
||||
"label": __("Group by Account"),
|
||||
"fieldtype": "Check",
|
||||
},
|
||||
{
|
||||
"fieldname":"letter_head",
|
||||
"label": __("Letter Head"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Letter Head",
|
||||
"default": frappe.defaults.get_default("letter_head"),
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import flt, getdate
|
||||
from frappe.utils import flt, getdate, cstr
|
||||
from frappe import _
|
||||
|
||||
def execute(filters=None):
|
||||
account_details = {}
|
||||
for acc in frappe.db.sql("""select name, is_group from tabAccount""", as_dict=1):
|
||||
account_details.setdefault(acc.name, acc)
|
||||
account_details.setdefault(acc.name, acc)
|
||||
|
||||
validate_filters(filters, account_details)
|
||||
validate_party(filters)
|
||||
@@ -66,7 +66,7 @@ def get_gl_entries(filters):
|
||||
|
||||
gl_entries = frappe.db.sql("""select posting_date, account, party_type, party,
|
||||
sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit,
|
||||
voucher_type, voucher_no, cost_center, remarks, is_opening, against
|
||||
voucher_type, voucher_no, cost_center, remarks, against, is_opening
|
||||
from `tabGL Entry`
|
||||
where company=%(company)s {conditions}
|
||||
{group_by_condition}
|
||||
@@ -82,8 +82,6 @@ def get_conditions(filters):
|
||||
lft, rgt = frappe.db.get_value("Account", filters["account"], ["lft", "rgt"])
|
||||
conditions.append("""account in (select name from tabAccount
|
||||
where lft>=%s and rgt<=%s and docstatus<2)""" % (lft, rgt))
|
||||
else:
|
||||
conditions.append("posting_date between %(from_date)s and %(to_date)s")
|
||||
|
||||
if filters.get("voucher_no"):
|
||||
conditions.append("voucher_no=%(voucher_no)s")
|
||||
@@ -93,6 +91,9 @@ def get_conditions(filters):
|
||||
|
||||
if filters.get("party"):
|
||||
conditions.append("party=%(party)s")
|
||||
|
||||
if not (filters.get("account") or filters.get("party") or filters.get("group_by_account")):
|
||||
conditions.append("posting_date >=%(from_date)s")
|
||||
|
||||
from frappe.desk.reportview import build_match_conditions
|
||||
match_conditions = build_match_conditions("GL Entry")
|
||||
@@ -107,31 +108,31 @@ def get_data_with_opening_closing(filters, account_details, gl_entries):
|
||||
opening, total_debit, total_credit, gle_map = get_accountwise_gle(filters, gl_entries, gle_map)
|
||||
|
||||
# Opening for filtered account
|
||||
if filters.get("account"):
|
||||
data += [get_balance_row("Opening", opening), {}]
|
||||
if filters.get("account") or filters.get("party"):
|
||||
data += [get_balance_row(_("Opening"), opening), {}]
|
||||
|
||||
for acc, acc_dict in gle_map.items():
|
||||
if acc_dict.entries:
|
||||
# Opening for individual ledger, if grouped by account
|
||||
if filters.get("group_by_account"):
|
||||
data.append(get_balance_row("Opening", acc_dict.opening))
|
||||
data.append(get_balance_row(_("Opening"), acc_dict.opening))
|
||||
|
||||
data += acc_dict.entries
|
||||
|
||||
# Totals and closing for individual ledger, if grouped by account
|
||||
if filters.get("group_by_account"):
|
||||
data += [{"account": "Totals", "debit": acc_dict.total_debit,
|
||||
data += [{"account": "'" + _("Totals") + "'", "debit": acc_dict.total_debit,
|
||||
"credit": acc_dict.total_credit},
|
||||
get_balance_row("Closing (Opening + Totals)",
|
||||
get_balance_row(_("Closing (Opening + Totals)"),
|
||||
(acc_dict.opening + acc_dict.total_debit - acc_dict.total_credit)), {}]
|
||||
|
||||
# Total debit and credit between from and to date
|
||||
if total_debit or total_credit:
|
||||
data.append({"account": "Totals", "debit": total_debit, "credit": total_credit})
|
||||
data.append({"account": "'" + _("Totals") + "'", "debit": total_debit, "credit": total_credit})
|
||||
|
||||
# Closing for filtered account
|
||||
if filters.get("account"):
|
||||
data.append(get_balance_row("Closing (Opening + Totals)",
|
||||
if filters.get("account") or filters.get("party"):
|
||||
data.append(get_balance_row(_("Closing (Opening + Totals)"),
|
||||
(opening + total_debit - total_credit)))
|
||||
|
||||
return data
|
||||
@@ -150,13 +151,15 @@ def initialize_gle_map(gl_entries):
|
||||
|
||||
def get_accountwise_gle(filters, gl_entries, gle_map):
|
||||
opening, total_debit, total_credit = 0, 0, 0
|
||||
|
||||
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
|
||||
for gle in gl_entries:
|
||||
amount = flt(gle.debit, 3) - flt(gle.credit, 3)
|
||||
if filters.get("account") and gle.posting_date < getdate(filters.from_date):
|
||||
if (filters.get("account") or filters.get("party") or filters.get("group_by_account")) \
|
||||
and (gle.posting_date < from_date or cstr(gle.is_opening) == "Yes"):
|
||||
gle_map[gle.account].opening += amount
|
||||
opening += amount
|
||||
elif gle.posting_date <= getdate(filters.to_date):
|
||||
if filters.get("account") or filters.get("party"):
|
||||
opening += amount
|
||||
elif gle.posting_date <= to_date:
|
||||
gle_map[gle.account].entries.append(gle)
|
||||
gle_map[gle.account].total_debit += flt(gle.debit, 3)
|
||||
gle_map[gle.account].total_credit += flt(gle.credit, 3)
|
||||
@@ -168,7 +171,7 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
|
||||
|
||||
def get_balance_row(label, balance):
|
||||
return {
|
||||
"account": label,
|
||||
"account": "'" + label + "'",
|
||||
"debit": balance if balance > 0 else 0,
|
||||
"credit": -1*balance if balance < 0 else 0,
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ def execute(filters=None):
|
||||
source = gross_profit_data.grouped_data if filters.get("group_by") != "Invoice" else gross_profit_data.data
|
||||
|
||||
group_wise_columns = frappe._dict({
|
||||
"invoice": ["name", "posting_date", "posting_time", "item_code", "item_name", "brand", "description", \
|
||||
"invoice": ["parent", "customer", "posting_date", "posting_time", "item_code", "item_name", "brand", "description", \
|
||||
"warehouse", "qty", "base_rate", "buying_rate", "base_amount",
|
||||
"buying_amount", "gross_profit", "gross_profit_percent", "project"],
|
||||
"item_code": ["item_code", "item_name", "brand", "description", "warehouse", "qty", "base_rate",
|
||||
@@ -50,7 +50,7 @@ def execute(filters=None):
|
||||
def get_columns(group_wise_columns, filters):
|
||||
columns = []
|
||||
column_map = frappe._dict({
|
||||
"name": _("Sales Invoice") + ":Link/Sales Invoice:120",
|
||||
"parent": _("Sales Invoice") + ":Link/Sales Invoice:120",
|
||||
"posting_date": _("Posting Date") + ":Date",
|
||||
"posting_time": _("Posting Time"),
|
||||
"item_code": _("Item Code") + ":Link/Item",
|
||||
@@ -86,23 +86,23 @@ class GrossProfitGenerator(object):
|
||||
self.filters = frappe._dict(filters)
|
||||
self.load_invoice_items()
|
||||
self.load_stock_ledger_entries()
|
||||
self.load_sales_bom()
|
||||
self.load_product_bundle()
|
||||
self.load_non_stock_items()
|
||||
self.process()
|
||||
|
||||
def process(self):
|
||||
self.grouped = {}
|
||||
for row in self.si_list:
|
||||
if self.skip_row(row, self.sales_boms):
|
||||
if self.skip_row(row, self.product_bundles):
|
||||
continue
|
||||
|
||||
row.base_amount = flt(row.base_net_amount)
|
||||
|
||||
sales_boms = self.sales_boms.get(row.parenttype, {}).get(row.name, frappe._dict())
|
||||
product_bundles = self.product_bundles.get(row.parenttype, {}).get(row.parent, frappe._dict())
|
||||
|
||||
# get buying amount
|
||||
if row.item_code in sales_boms:
|
||||
row.buying_amount = self.get_buying_amount_from_sales_bom(row, sales_boms[row.item_code])
|
||||
if row.item_code in product_bundles:
|
||||
row.buying_amount = self.get_buying_amount_from_product_bundle(row, product_bundles[row.item_code])
|
||||
else:
|
||||
row.buying_amount = self.get_buying_amount(row, row.item_code)
|
||||
|
||||
@@ -152,13 +152,13 @@ class GrossProfitGenerator(object):
|
||||
|
||||
self.grouped_data.append(new_row)
|
||||
|
||||
def skip_row(self, row, sales_boms):
|
||||
def skip_row(self, row, product_bundles):
|
||||
if self.filters.get("group_by") != "Invoice" and not row.get(scrub(self.filters.get("group_by"))):
|
||||
return True
|
||||
|
||||
def get_buying_amount_from_sales_bom(self, row, sales_bom):
|
||||
def get_buying_amount_from_product_bundle(self, row, product_bundle):
|
||||
buying_amount = 0.0
|
||||
for bom_item in sales_bom[row.item_code]:
|
||||
for bom_item in product_bundle:
|
||||
if bom_item.get("parent_detail_docname")==row.item_row:
|
||||
buying_amount += self.get_buying_amount(row, bom_item.item_code)
|
||||
|
||||
@@ -174,16 +174,16 @@ class GrossProfitGenerator(object):
|
||||
return flt(row.qty) * item_rate
|
||||
|
||||
else:
|
||||
if row.dn_detail:
|
||||
row.parenttype = "Delivery Note"
|
||||
row.parent = row.delivery_note
|
||||
row.item_row = row.dn_detail
|
||||
|
||||
my_sle = self.sle.get((item_code, row.warehouse))
|
||||
my_sle = self.sle.get((item_code, row.warehouse))
|
||||
if (row.update_stock or row.dn_detail) and my_sle:
|
||||
parenttype, parent, item_row = row.parenttype, row.parent, row.item_row
|
||||
if row.dn_detail:
|
||||
parenttype, parent, item_row = "Delivery Note", row.delivery_note, row.dn_detail
|
||||
|
||||
for i, sle in enumerate(my_sle):
|
||||
# find the stock valution rate from stock ledger entry
|
||||
if sle.voucher_type == row.parenttype and row.parent == sle.voucher_no and \
|
||||
sle.voucher_detail_no == row.item_row:
|
||||
if sle.voucher_type == parenttype and parent == sle.voucher_no and \
|
||||
sle.voucher_detail_no == item_row:
|
||||
previous_stock_value = len(my_sle) > i+1 and \
|
||||
flt(my_sle[i+1].stock_value) or 0.0
|
||||
return previous_stock_value - flt(sle.stock_value)
|
||||
@@ -215,7 +215,7 @@ class GrossProfitGenerator(object):
|
||||
if self.filters.to_date:
|
||||
conditions += " and posting_date <= %(to_date)s"
|
||||
|
||||
self.si_list = frappe.db.sql("""select item.parenttype, si.name,
|
||||
self.si_list = frappe.db.sql("""select item.parenttype, item.parent,
|
||||
si.posting_date, si.posting_time, si.project_name, si.update_stock,
|
||||
si.customer, si.customer_group, si.territory,
|
||||
item.item_code, item.item_name, item.description, item.warehouse,
|
||||
@@ -246,15 +246,15 @@ class GrossProfitGenerator(object):
|
||||
|
||||
self.sle[(r.item_code, r.warehouse)].append(r)
|
||||
|
||||
def load_sales_bom(self):
|
||||
self.sales_boms = {}
|
||||
def load_product_bundle(self):
|
||||
self.product_bundles = {}
|
||||
|
||||
for d in frappe.db.sql("""select parenttype, parent, parent_item,
|
||||
item_code, warehouse, -1*qty as total_qty, parent_detail_docname
|
||||
from `tabPacked Item` where docstatus=1""", as_dict=True):
|
||||
self.sales_boms.setdefault(d.parenttype, frappe._dict()).setdefault(d.parent,
|
||||
self.product_bundles.setdefault(d.parenttype, frappe._dict()).setdefault(d.parent,
|
||||
frappe._dict()).setdefault(d.parent_item, []).append(d)
|
||||
|
||||
def load_non_stock_items(self):
|
||||
self.non_stock_items = frappe.db.sql_list("""select name from tabItem
|
||||
where ifnull(is_stock_item, 'No')='No'""")
|
||||
where is_stock_item=0""")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import msgprint, _
|
||||
from frappe import _
|
||||
from frappe.utils import flt
|
||||
|
||||
def execute(filters=None):
|
||||
@@ -23,7 +23,7 @@ def execute(filters=None):
|
||||
purchase_receipt = d.purchase_receipt
|
||||
elif d.po_detail:
|
||||
purchase_receipt = ", ".join(frappe.db.sql_list("""select distinct parent
|
||||
from `tabPurchase Receipt Item` where docstatus=1 and po_detail=%s""", d.po_detail))
|
||||
from `tabPurchase Receipt Item` where docstatus=1 and prevdoc_detail_docname=%s""", d.po_detail))
|
||||
|
||||
expense_account = d.expense_account or aii_account_map.get(d.company)
|
||||
row = [d.item_code, d.item_name, d.item_group, d.parent, d.posting_date, d.supplier,
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
|
||||
frappe.query_reports["Payment Period Based On Invoice Date"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname:"company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
reqd: 1,
|
||||
default: frappe.defaults.get_user_default("company")
|
||||
},
|
||||
{
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
@@ -23,27 +31,28 @@ frappe.query_reports["Payment Period Based On Invoice Date"] = {
|
||||
default: "Incoming"
|
||||
},
|
||||
{
|
||||
fieldname:"account",
|
||||
label: __("Account"),
|
||||
fieldtype: "Link",
|
||||
options: "Account",
|
||||
get_query: function() {
|
||||
"fieldname":"party_type",
|
||||
"label": __("Party Type"),
|
||||
"fieldtype": "Link",
|
||||
"options": "DocType",
|
||||
"get_query": function() {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.get_account_list",
|
||||
filters: {
|
||||
"report_type": "Balance Sheet",
|
||||
company: frappe.query_report.filters_by_name.company.get_value()
|
||||
}
|
||||
filters: {"name": ["in", ["Customer", "Supplier"]]}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldname:"company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
reqd: 1,
|
||||
default: frappe.defaults.get_user_default("company")
|
||||
"fieldname":"party",
|
||||
"label": __("Party"),
|
||||
"fieldtype": "Dynamic Link",
|
||||
"get_options": function() {
|
||||
var party_type = frappe.query_report.filters_by_name.party_type.get_value();
|
||||
var party = frappe.query_report.filters_by_name.party.get_value();
|
||||
if(party && !party_type) {
|
||||
frappe.throw(__("Please select Party Type first"));
|
||||
}
|
||||
return party_type;
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,27 +9,26 @@ from frappe.utils import flt
|
||||
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
validate_filters(filters)
|
||||
|
||||
columns = get_columns()
|
||||
columns = get_columns(filters)
|
||||
entries = get_entries(filters)
|
||||
invoice_posting_date_map = get_invoice_posting_date_map(filters)
|
||||
against_date = ""
|
||||
outstanding_amount = 0.0
|
||||
|
||||
data = []
|
||||
for d in entries:
|
||||
if d.against_voucher:
|
||||
against_date = d.against_voucher and invoice_posting_date_map[d.against_voucher] or ""
|
||||
outstanding_amount = flt(d.debit) or -1 * flt(d.credit)
|
||||
against_date = invoice_posting_date_map.get(d.reference_name) or ""
|
||||
if d.reference_type=="Purchase Invoice":
|
||||
payment_amount = flt(d.debit) or -1 * flt(d.credit)
|
||||
else:
|
||||
against_date = d.against_invoice and invoice_posting_date_map[d.against_invoice] or ""
|
||||
outstanding_amount = flt(d.credit) or -1 * flt(d.debit)
|
||||
payment_amount = flt(d.credit) or -1 * flt(d.debit)
|
||||
|
||||
row = [d.name, d.account, d.posting_date, d.against_voucher or d.against_invoice,
|
||||
row = [d.name, d.party_type, d.party, d.posting_date, d.reference_name,
|
||||
against_date, d.debit, d.credit, d.cheque_no, d.cheque_date, d.remark]
|
||||
|
||||
if d.against_voucher or d.against_invoice:
|
||||
row += get_ageing_data(30, 60, 90, d.posting_date, against_date, outstanding_amount)
|
||||
if d.reference_name:
|
||||
row += get_ageing_data(30, 60, 90, d.posting_date, against_date, payment_amount)
|
||||
else:
|
||||
row += ["", "", "", "", ""]
|
||||
|
||||
@@ -37,50 +36,55 @@ def execute(filters=None):
|
||||
|
||||
return columns, data
|
||||
|
||||
def get_columns():
|
||||
return [_("Journal Entry") + ":Link/Journal Entry:140", _("Account") + ":Link/Account:140",
|
||||
_("Posting Date") + ":Date:100", _("Against Invoice") + ":Link/Purchase Invoice:130",
|
||||
def validate_filters(filters):
|
||||
if (filters.get("payment_type") == "Incoming" and filters.get("party_type") == "Supplier") or \
|
||||
(filters.get("payment_type") == "Outgoing" and filters.get("party_type") == "Customer"):
|
||||
frappe.throw(_("{0} payment entries can not be filtered by {1}")\
|
||||
.format(filters.payment_type, filters.party_type))
|
||||
|
||||
def get_columns(filters):
|
||||
return [_("Journal Entry") + ":Link/Journal Entry:140",
|
||||
_("Party Type") + "::100", _("Party") + ":Dynamic Link/Party Type:140",
|
||||
_("Posting Date") + ":Date:100",
|
||||
_("Against Invoice") + (":Link/Purchase Invoice:130" if filters.get("payment_type") == "Outgoing" else ":Link/Sales Invoice:130"),
|
||||
_("Against Invoice Posting Date") + ":Date:130", _("Debit") + ":Currency:120", _("Credit") + ":Currency:120",
|
||||
_("Reference No") + "::100", _("Reference Date") + ":Date:100", _("Remarks") + "::150", _("Age") +":Int:40",
|
||||
"0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", _("90-Above") + ":Currency:100"
|
||||
]
|
||||
|
||||
def get_conditions(filters):
|
||||
conditions = ""
|
||||
party = None
|
||||
conditions = []
|
||||
|
||||
if filters.get("account"):
|
||||
party = filters["account"]
|
||||
else:
|
||||
conditions += " and company = '%s'" % frappe.db.escape(filters["company"])
|
||||
if not filters.get("party_type"):
|
||||
if filters.get("payment_type") == "Outgoing":
|
||||
filters["party_type"] = "Supplier"
|
||||
else:
|
||||
filters["party_type"] = "Customer"
|
||||
|
||||
account_type = "Receivable" if filters.get("payment_type") == "Incoming" else "Payable"
|
||||
if filters.get("party_type"):
|
||||
conditions.append("jvd.party_type=%(party_type)s")
|
||||
|
||||
conditions += """ and account in
|
||||
(select name from tabAccount
|
||||
where account_type = '{0}'
|
||||
and company='{1}')""".format(account_type, frappe.db.escape(filters["company"]))
|
||||
if filters.get("party"):
|
||||
conditions.append("jvd.party=%(party)s")
|
||||
|
||||
if party:
|
||||
conditions += " and jvd.party = '%s'" % frappe.db.escape(party)
|
||||
else:
|
||||
conditions += " and ifnull(jvd.party, '') != ''"
|
||||
if filters.get("company"):
|
||||
conditions.append("jv.company=%(company)s")
|
||||
|
||||
if filters.get("from_date"):
|
||||
conditions += " and jv.posting_date >= '%s'" % filters["from_date"]
|
||||
conditions.append("jv.posting_date >= %(from_date)s")
|
||||
if filters.get("to_date"):
|
||||
conditions += " and jv.posting_date <= '%s'" % filters["to_date"]
|
||||
conditions.append("jv.posting_date <= %(to_date)s")
|
||||
|
||||
return conditions
|
||||
return "and {}".format(" and ".join(conditions)) if conditions else ""
|
||||
|
||||
def get_entries(filters):
|
||||
conditions = get_conditions(filters)
|
||||
entries = frappe.db.sql("""select jv.name, jvd.account, jv.posting_date,
|
||||
jvd.against_voucher, jvd.against_invoice, jvd.debit, jvd.credit,
|
||||
entries = frappe.db.sql("""select jv.name, jvd.party_type, jvd.party, jv.posting_date,
|
||||
jvd.reference_type, jvd.reference_name, jvd.debit, jvd.credit,
|
||||
jv.cheque_no, jv.cheque_date, jv.remark
|
||||
from `tabJournal Entry Account` jvd, `tabJournal Entry` jv
|
||||
where jvd.parent = jv.name and jv.docstatus=1 %s order by jv.name DESC""" %
|
||||
conditions, as_dict=1, debug=1)
|
||||
conditions, filters, as_dict=1)
|
||||
|
||||
return entries
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ def execute(filters=None):
|
||||
def get_net_profit_loss(income, expense, period_list):
|
||||
if income and expense:
|
||||
net_profit_loss = {
|
||||
"account_name": _("Net Profit / Loss"),
|
||||
"account_name": "'" + _("Net Profit / Loss") + "'",
|
||||
"account": None,
|
||||
"warn_if_negative": True
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ def execute(filters=None):
|
||||
invoice_list = get_invoices(filters)
|
||||
columns, expense_accounts, tax_accounts = get_columns(invoice_list)
|
||||
|
||||
|
||||
if not invoice_list:
|
||||
msgprint(_("No record found"))
|
||||
return columns, invoice_list
|
||||
@@ -30,7 +29,8 @@ def execute(filters=None):
|
||||
purchase_receipt = list(set(invoice_po_pr_map.get(inv.name, {}).get("purchase_receipt", [])))
|
||||
project_name = list(set(invoice_po_pr_map.get(inv.name, {}).get("project_name", [])))
|
||||
|
||||
row = [inv.name, inv.posting_date, inv.supplier, inv.supplier_name, supplier_details.get(inv.supplier),
|
||||
row = [inv.name, inv.posting_date, inv.supplier, inv.supplier_name,
|
||||
supplier_details.get(inv.supplier),
|
||||
inv.credit_to, ", ".join(project_name), inv.bill_no, inv.bill_date, inv.remarks,
|
||||
", ".join(purchase_order), ", ".join(purchase_receipt)]
|
||||
|
||||
@@ -54,8 +54,7 @@ def execute(filters=None):
|
||||
|
||||
# total tax, grand total, outstanding amount & rounded total
|
||||
row += [total_tax, inv.base_grand_total, flt(inv.base_grand_total, 2), inv.outstanding_amount]
|
||||
data.append(row)
|
||||
# raise Exception
|
||||
data.append(row)
|
||||
|
||||
return columns, data
|
||||
|
||||
@@ -107,7 +106,7 @@ def get_conditions(filters):
|
||||
|
||||
def get_invoices(filters):
|
||||
conditions = get_conditions(filters)
|
||||
return frappe.db.sql("""select name, posting_date, credit_to, supplier, supplier_name
|
||||
return frappe.db.sql("""select name, posting_date, credit_to, supplier, supplier_name,
|
||||
bill_no, bill_date, remarks, base_net_total, base_grand_total, outstanding_amount
|
||||
from `tabPurchase Invoice` where docstatus = 1 %s
|
||||
order by posting_date desc, name desc""" % conditions, filters, as_dict=1)
|
||||
@@ -144,7 +143,7 @@ def get_invoice_tax_map(invoice_list, invoice_expense_map, expense_accounts):
|
||||
return invoice_expense_map, invoice_tax_map
|
||||
|
||||
def get_invoice_po_pr_map(invoice_list):
|
||||
pi_items = frappe.db.sql("""select parent, purchase_order, purchase_receipt, po_detail
|
||||
pi_items = frappe.db.sql("""select parent, purchase_order, purchase_receipt, po_detail,
|
||||
project_name from `tabPurchase Invoice Item` where parent in (%s)
|
||||
and (ifnull(purchase_order, '') != '' or ifnull(purchase_receipt, '') != '')""" %
|
||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
|
||||
@@ -160,7 +159,7 @@ def get_invoice_po_pr_map(invoice_list):
|
||||
pr_list = [d.purchase_receipt]
|
||||
elif d.po_detail:
|
||||
pr_list = frappe.db.sql_list("""select distinct parent from `tabPurchase Receipt Item`
|
||||
where docstatus=1 and po_detail=%s""", d.pr_detail)
|
||||
where docstatus=1 and prevdoc_detail_docname=%s""", d.po_detail)
|
||||
|
||||
if pr_list:
|
||||
invoice_po_pr_map.setdefault(d.parent, frappe._dict()).setdefault("purchase_receipt", pr_list)
|
||||
|
||||
@@ -30,7 +30,8 @@ def execute(filters=None):
|
||||
delivery_note = list(set(invoice_so_dn_map.get(inv.name, {}).get("delivery_note", [])))
|
||||
|
||||
row = [inv.name, inv.posting_date, inv.customer, inv.customer_name,
|
||||
customer_map.get(inv.customer)["customer_group"], customer_map.get(inv.customer)["territory"],
|
||||
customer_map.get(inv.customer, {}).get("customer_group"),
|
||||
customer_map.get(inv.customer, {}).get("territory"),
|
||||
inv.debit_to, inv.project_name, inv.remarks, ", ".join(sales_order), ", ".join(delivery_note)]
|
||||
|
||||
# map income values
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import cint, flt, getdate, formatdate
|
||||
from frappe.utils import cint, flt, getdate, formatdate, cstr
|
||||
from erpnext.accounts.report.financial_statements import filter_accounts, get_gl_entries
|
||||
|
||||
value_fields = ("opening_debit", "opening_credit", "debit", "credit", "closing_debit", "closing_credit")
|
||||
|
||||
def execute(filters):
|
||||
def execute(filters=None):
|
||||
validate_filters(filters)
|
||||
data = get_data(filters)
|
||||
columns = get_columns()
|
||||
@@ -45,8 +45,8 @@ def validate_filters(filters):
|
||||
filters.to_date = filters.year_end_date
|
||||
|
||||
def get_data(filters):
|
||||
accounts = frappe.db.sql("""select * from `tabAccount` where company=%s order by lft""",
|
||||
filters.company, as_dict=True)
|
||||
accounts = frappe.db.sql("""select name, parent_account, account_name, root_type, report_type, lft, rgt
|
||||
from `tabAccount` where company=%s order by lft""", filters.company, as_dict=True)
|
||||
|
||||
if not accounts:
|
||||
return None
|
||||
@@ -56,17 +56,58 @@ def get_data(filters):
|
||||
min_lft, max_rgt = frappe.db.sql("""select min(lft), max(rgt) from `tabAccount`
|
||||
where company=%s""", (filters.company,))[0]
|
||||
|
||||
gl_entries_by_account = get_gl_entries(filters.company, None, filters.to_date, min_lft, max_rgt,
|
||||
gl_entries_by_account = get_gl_entries(filters.company, filters.from_date, filters.to_date, min_lft, max_rgt,
|
||||
ignore_closing_entries=not flt(filters.with_period_closing_entry))
|
||||
|
||||
total_row = calculate_values(accounts, gl_entries_by_account, filters)
|
||||
opening_balances = get_opening_balances(filters)
|
||||
|
||||
total_row = calculate_values(accounts, gl_entries_by_account, opening_balances, filters)
|
||||
accumulate_values_into_parents(accounts, accounts_by_name)
|
||||
|
||||
data = prepare_data(accounts, filters, total_row)
|
||||
|
||||
return data
|
||||
|
||||
def get_opening_balances(filters):
|
||||
balance_sheet_opening = get_rootwise_opening_balances(filters, "Balance Sheet")
|
||||
pl_opening = get_rootwise_opening_balances(filters, "Profit and Loss")
|
||||
|
||||
balance_sheet_opening.update(pl_opening)
|
||||
return balance_sheet_opening
|
||||
|
||||
|
||||
def get_rootwise_opening_balances(filters, report_type):
|
||||
additional_conditions = " and posting_date >= %(year_start_date)s" \
|
||||
if report_type == "Profit and Loss" else ""
|
||||
|
||||
if not flt(filters.with_period_closing_entry):
|
||||
additional_conditions += " and ifnull(voucher_type, '')!='Period Closing Voucher'"
|
||||
|
||||
gle = frappe.db.sql("""
|
||||
select
|
||||
account, sum(ifnull(debit, 0)) as opening_debit, sum(ifnull(credit, 0)) as opening_credit
|
||||
from `tabGL Entry`
|
||||
where
|
||||
company=%(company)s
|
||||
{additional_conditions}
|
||||
and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes')
|
||||
and account in (select name from `tabAccount` where report_type=%(report_type)s)
|
||||
group by account""".format(additional_conditions=additional_conditions),
|
||||
{
|
||||
"company": filters.company,
|
||||
"from_date": filters.from_date,
|
||||
"report_type": report_type,
|
||||
"year_start_date": filters.year_start_date
|
||||
},
|
||||
as_dict=True)
|
||||
|
||||
opening = frappe._dict()
|
||||
for d in gle:
|
||||
opening.setdefault(d.account, d)
|
||||
|
||||
return opening
|
||||
|
||||
def calculate_values(accounts, gl_entries_by_account, filters):
|
||||
def calculate_values(accounts, gl_entries_by_account, opening_balances, filters):
|
||||
init = {
|
||||
"opening_debit": 0.0,
|
||||
"opening_credit": 0.0,
|
||||
@@ -87,30 +128,18 @@ def calculate_values(accounts, gl_entries_by_account, filters):
|
||||
for d in accounts:
|
||||
d.update(init.copy())
|
||||
|
||||
# add opening
|
||||
d["opening_debit"] = opening_balances.get(d.name, {}).get("opening_debit", 0)
|
||||
d["opening_credit"] = opening_balances.get(d.name, {}).get("opening_credit", 0)
|
||||
|
||||
for entry in gl_entries_by_account.get(d.name, []):
|
||||
posting_date = getdate(entry.posting_date)
|
||||
|
||||
# opening
|
||||
if posting_date < filters.from_date:
|
||||
is_valid_opening = (d.root_type in ("Asset", "Liability", "Equity") or
|
||||
(filters.year_start_date <= posting_date < filters.from_date))
|
||||
|
||||
if is_valid_opening:
|
||||
d["opening_debit"] += flt(entry.debit)
|
||||
d["opening_credit"] += flt(entry.credit)
|
||||
|
||||
elif posting_date <= filters.to_date:
|
||||
|
||||
if entry.is_opening == "Yes" and d.root_type in ("Asset", "Liability", "Equity"):
|
||||
d["opening_debit"] += flt(entry.debit)
|
||||
d["opening_credit"] += flt(entry.credit)
|
||||
|
||||
else:
|
||||
d["debit"] += flt(entry.debit)
|
||||
d["credit"] += flt(entry.credit)
|
||||
if cstr(entry.is_opening) != "Yes":
|
||||
d["debit"] += flt(entry.debit)
|
||||
d["credit"] += flt(entry.credit)
|
||||
|
||||
total_row["debit"] += d["debit"]
|
||||
total_row["credit"] += d["credit"]
|
||||
|
||||
|
||||
return total_row
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ def get_fiscal_years(transaction_date=None, fiscal_year=None, label="Date", verb
|
||||
# if year start date is 2012-04-01, year end date should be 2013-03-31 (hence subdate)
|
||||
cond = " ifnull(disabled, 0) = 0"
|
||||
if fiscal_year:
|
||||
cond = " and fy.name = %(fiscal_year)s"
|
||||
cond += " and fy.name = %(fiscal_year)s"
|
||||
else:
|
||||
cond = " and %(transaction_date)s >= fy.year_start_date and %(transaction_date)s <= fy.year_end_date"
|
||||
cond += " and %(transaction_date)s >= fy.year_start_date and %(transaction_date)s <= fy.year_end_date"
|
||||
|
||||
if company:
|
||||
cond += """ and (not exists(select name from `tabFiscal Year Company` fyc where fyc.parent = fy.name)
|
||||
@@ -91,7 +91,7 @@ def get_balance_on(account=None, date=None, party_type=None, party=None):
|
||||
# different filter for group and ledger - improved performance
|
||||
if acc.is_group:
|
||||
cond.append("""exists (
|
||||
select * from `tabAccount` ac where ac.name = gle.account
|
||||
select name from `tabAccount` ac where ac.name = gle.account
|
||||
and ac.lft >= %s and ac.rgt <= %s
|
||||
)""" % (acc.lft, acc.rgt))
|
||||
else:
|
||||
@@ -142,13 +142,6 @@ def reconcile_against_document(args):
|
||||
for d in args:
|
||||
check_if_jv_modified(d)
|
||||
validate_allocated_amount(d)
|
||||
against_fld = {
|
||||
'Journal Entry' : 'against_jv',
|
||||
'Sales Invoice' : 'against_invoice',
|
||||
'Purchase Invoice' : 'against_voucher'
|
||||
}
|
||||
|
||||
d['against_fld'] = against_fld[d['against_voucher_type']]
|
||||
|
||||
# cancel JV
|
||||
jv_obj = frappe.get_doc('Journal Entry', d['voucher_no'])
|
||||
@@ -173,8 +166,7 @@ def check_if_jv_modified(args):
|
||||
select t2.{dr_or_cr} from `tabJournal Entry` t1, `tabJournal Entry Account` t2
|
||||
where t1.name = t2.parent and t2.account = %(account)s
|
||||
and t2.party_type = %(party_type)s and t2.party = %(party)s
|
||||
and ifnull(t2.against_voucher, '')=''
|
||||
and ifnull(t2.against_invoice, '')='' and ifnull(t2.against_jv, '')=''
|
||||
and ifnull(t2.reference_type, '') in ("", "Sales Order", "Purchase Order")
|
||||
and t1.name = %(voucher_no)s and t2.name = %(voucher_detail_no)s
|
||||
and t1.docstatus=1 """.format(dr_or_cr = args.get("dr_or_cr")), args)
|
||||
|
||||
@@ -193,7 +185,12 @@ def update_against_doc(d, jv_obj):
|
||||
"""
|
||||
jv_detail = jv_obj.get("accounts", {"name": d["voucher_detail_no"]})[0]
|
||||
jv_detail.set(d["dr_or_cr"], d["allocated_amt"])
|
||||
jv_detail.set(d["against_fld"], d["against_voucher"])
|
||||
|
||||
original_reference_type = jv_detail.reference_type
|
||||
original_reference_name = jv_detail.reference_name
|
||||
|
||||
jv_detail.set("reference_type", d["against_voucher_type"])
|
||||
jv_detail.set("reference_name", d["against_voucher"])
|
||||
|
||||
if d['allocated_amt'] < d['unadjusted_amt']:
|
||||
jvd = frappe.db.sql("""select cost_center, balance, against_account, is_advance
|
||||
@@ -208,6 +205,8 @@ def update_against_doc(d, jv_obj):
|
||||
ch.set(d['dr_or_cr'], flt(d['unadjusted_amt']) - flt(d['allocated_amt']))
|
||||
ch.set(d['dr_or_cr']== 'debit' and 'credit' or 'debit', 0)
|
||||
ch.against_account = cstr(jvd[0][2])
|
||||
ch.reference_type = original_reference_type
|
||||
ch.reference_name = original_reference_name
|
||||
ch.is_advance = cstr(jvd[0][3])
|
||||
ch.docstatus = 1
|
||||
|
||||
@@ -215,15 +214,16 @@ def update_against_doc(d, jv_obj):
|
||||
jv_obj.flags.ignore_validate_update_after_submit = True
|
||||
jv_obj.save()
|
||||
|
||||
def remove_against_link_from_jv(ref_type, ref_no, against_field):
|
||||
def remove_against_link_from_jv(ref_type, ref_no):
|
||||
linked_jv = frappe.db.sql_list("""select parent from `tabJournal Entry Account`
|
||||
where `%s`=%s and docstatus < 2""" % (against_field, "%s"), (ref_no))
|
||||
where reference_type=%s and reference_name=%s and docstatus < 2""", (ref_type, ref_no))
|
||||
|
||||
if linked_jv:
|
||||
frappe.db.sql("""update `tabJournal Entry Account` set `%s`=null,
|
||||
frappe.db.sql("""update `tabJournal Entry Account`
|
||||
set reference_type=null, reference_name = null,
|
||||
modified=%s, modified_by=%s
|
||||
where `%s`=%s and docstatus < 2""" % (against_field, "%s", "%s", against_field, "%s"),
|
||||
(now(), frappe.session.user, ref_no))
|
||||
where reference_type=%s and reference_name=%s
|
||||
and docstatus < 2""", (now(), frappe.session.user, ref_type, ref_no))
|
||||
|
||||
frappe.db.sql("""update `tabGL Entry`
|
||||
set against_voucher_type=null, against_voucher=null,
|
||||
@@ -397,7 +397,7 @@ def get_outstanding_invoices(amount_query, account, party_type, party):
|
||||
|
||||
for d in outstanding_voucher_list:
|
||||
payment_amount = frappe.db.sql("""
|
||||
select ifnull(sum(ifnull({amount_query}, 0)), 0)
|
||||
select ifnull(sum({amount_query}), 0)
|
||||
from
|
||||
`tabGL Entry`
|
||||
where
|
||||
|
||||
@@ -44,12 +44,12 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
if(me.frm.doc.is_subcontracted == "Yes") {
|
||||
return{
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters:{ 'is_sub_contracted_item': 'Yes' }
|
||||
filters:{ 'is_sub_contracted_item': 1 }
|
||||
}
|
||||
} else {
|
||||
return{
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters: { 'is_purchase_item': 'Yes' }
|
||||
filters: { 'is_purchase_item': 1 }
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -70,10 +70,6 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
erpnext.utils.get_address_display(this.frm);
|
||||
},
|
||||
|
||||
contact_person: function() {
|
||||
erpnext.utils.get_contact_details(this.frm);
|
||||
},
|
||||
|
||||
buying_price_list: function() {
|
||||
this.apply_price_list();
|
||||
},
|
||||
@@ -168,8 +164,10 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
frappe.model.round_floats_in(this.frm.doc, ["base_grand_total", "total_advance", "write_off_amount"]);
|
||||
this.frm.doc.total_amount_to_pay = flt(this.frm.doc.base_grand_total - this.frm.doc.write_off_amount,
|
||||
precision("total_amount_to_pay"));
|
||||
this.frm.doc.outstanding_amount = flt(this.frm.doc.total_amount_to_pay - this.frm.doc.total_advance,
|
||||
precision("outstanding_amount"));
|
||||
if (!this.frm.doc.is_return) {
|
||||
this.frm.doc.outstanding_amount = flt(this.frm.doc.total_amount_to_pay - this.frm.doc.total_advance,
|
||||
precision("outstanding_amount"));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -41,8 +41,7 @@ class PurchaseCommon(BuyingController):
|
||||
def validate_for_items(self, obj):
|
||||
items = []
|
||||
for d in obj.get("items"):
|
||||
# validation for valid qty
|
||||
if flt(d.qty) < 0 or (d.parenttype != 'Purchase Receipt' and not flt(d.qty)):
|
||||
if not d.qty:
|
||||
frappe.throw(_("Please enter quantity for Item {0}").format(d.item_code))
|
||||
|
||||
# udpate with latest quantities
|
||||
@@ -57,24 +56,25 @@ class PurchaseCommon(BuyingController):
|
||||
d.set(x, f_lst[x])
|
||||
|
||||
item = frappe.db.sql("""select is_stock_item, is_purchase_item,
|
||||
is_sub_contracted_item, end_of_life from `tabItem` where name=%s""", d.item_code)
|
||||
is_sub_contracted_item, end_of_life from `tabItem` where name=%s""",
|
||||
d.item_code, as_dict=1)[0]
|
||||
|
||||
from erpnext.stock.doctype.item.item import validate_end_of_life
|
||||
validate_end_of_life(d.item_code, item[0][3])
|
||||
validate_end_of_life(d.item_code, item.end_of_life)
|
||||
|
||||
# validate stock item
|
||||
if item[0][0]=='Yes' and d.qty and not d.warehouse:
|
||||
if item.is_stock_item==1 and d.qty and not d.warehouse:
|
||||
frappe.throw(_("Warehouse is mandatory for stock Item {0} in row {1}").format(d.item_code, d.idx))
|
||||
|
||||
# validate purchase item
|
||||
if not (obj.doctype=="Material Request" and getattr(obj, "material_request_type", None)=="Material Transfer"):
|
||||
if item[0][1] != 'Yes' and item[0][2] != 'Yes':
|
||||
if item.is_purchase_item != 1 and item.is_sub_contracted_item != 1:
|
||||
frappe.throw(_("{0} must be a Purchased or Sub-Contracted Item in row {1}").format(d.item_code, d.idx))
|
||||
|
||||
items.append(cstr(d.item_code))
|
||||
if items and len(items) != len(set(items)):
|
||||
frappe.msgprint(_("Warning: Same item has been entered multiple times."))
|
||||
|
||||
|
||||
|
||||
def check_for_stopped_status(self, doctype, docname):
|
||||
stopped = frappe.db.sql("""select name from `tab%s` where name = %s and
|
||||
|
||||
@@ -5,45 +5,53 @@ frappe.provide("erpnext.buying");
|
||||
|
||||
{% include 'buying/doctype/purchase_common/purchase_common.js' %};
|
||||
|
||||
frappe.ui.form.on("Purchase Order", {
|
||||
onload: function(frm) {
|
||||
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
||||
return erpnext.queries.warehouse(frm.doc);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend({
|
||||
refresh: function(doc, cdt, cdn) {
|
||||
var me = this;
|
||||
this._super();
|
||||
// this.frm.dashboard.reset();
|
||||
|
||||
if(doc.docstatus == 1 && doc.status != 'Stopped'){
|
||||
// cur_frm.dashboard.add_progress(cint(doc.per_received) + __("% Received"),
|
||||
// doc.per_received);
|
||||
// cur_frm.dashboard.add_progress(cint(doc.per_billed) + __("% Billed"),
|
||||
// doc.per_billed);
|
||||
if(doc.docstatus == 1 && doc.status != 'Stopped') {
|
||||
|
||||
if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100)
|
||||
cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order']);
|
||||
|
||||
if(flt(doc.per_billed)==0) {
|
||||
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry);
|
||||
}
|
||||
|
||||
if(flt(doc.per_received, 2) < 100) {
|
||||
cur_frm.add_custom_button(__('Make Purchase Receipt'),
|
||||
this.make_purchase_receipt);
|
||||
cur_frm.add_custom_button(__('Receive'), this.make_purchase_receipt).addClass("btn-primary");
|
||||
|
||||
if(doc.is_subcontracted==="Yes") {
|
||||
cur_frm.add_custom_button(__('Transfer Material to Supplier'),
|
||||
function() { me.make_stock_entry() });
|
||||
cur_frm.add_custom_button(__('Transfer Material to Supplier'), this.make_stock_entry);
|
||||
}
|
||||
}
|
||||
|
||||
if(flt(doc.per_billed, 2) < 100)
|
||||
cur_frm.add_custom_button(__('Make Invoice'), this.make_purchase_invoice,
|
||||
frappe.boot.doctype_icons["Purchase Invoice"]);
|
||||
if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100)
|
||||
cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order'],
|
||||
"icon-exclamation", "btn-default");
|
||||
cur_frm.add_custom_button(__('Invoice'), this.make_purchase_invoice);
|
||||
|
||||
|
||||
} else if(doc.docstatus===0) {
|
||||
cur_frm.cscript.add_from_mappers();
|
||||
}
|
||||
|
||||
if(doc.docstatus == 1 && doc.status == 'Stopped')
|
||||
cur_frm.add_custom_button(__('Unstop Purchase Order'),
|
||||
cur_frm.cscript['Unstop Purchase Order'], "icon-check");
|
||||
cur_frm.add_custom_button(__('Unstop'), cur_frm.cscript['Unstop Purchase Order']);
|
||||
},
|
||||
|
||||
make_stock_entry: function() {
|
||||
var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; }),
|
||||
me = this;
|
||||
var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; });
|
||||
var me = this;
|
||||
|
||||
if(items.length===1) {
|
||||
me._make_stock_entry(items[0]);
|
||||
return;
|
||||
@@ -96,7 +104,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
company: cur_frm.doc.company
|
||||
}
|
||||
})
|
||||
}, "icon-download", "btn-default"
|
||||
}
|
||||
);
|
||||
|
||||
cur_frm.add_custom_button(__('From Supplier Quotation'),
|
||||
@@ -110,7 +118,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
company: cur_frm.doc.company
|
||||
}
|
||||
})
|
||||
}, "icon-download", "btn-default"
|
||||
}
|
||||
);
|
||||
|
||||
cur_frm.add_custom_button(__('For Supplier'),
|
||||
@@ -122,7 +130,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
docstatus: ["!=", 2],
|
||||
}
|
||||
})
|
||||
}, "icon-download", "btn-default"
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
@@ -133,7 +141,21 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
items_add: function(doc, cdt, cdn) {
|
||||
var row = frappe.get_doc(cdt, cdn);
|
||||
this.frm.script_manager.copy_from_first_row("items", row, ["schedule_date"]);
|
||||
},
|
||||
|
||||
make_bank_entry: function() {
|
||||
return frappe.call({
|
||||
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_payment_entry_from_purchase_order",
|
||||
args: {
|
||||
"purchase_order": cur_frm.doc.name
|
||||
},
|
||||
callback: function(r) {
|
||||
var doclist = frappe.model.sync(r.message);
|
||||
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// for backward compatibility: combine new and previous states
|
||||
@@ -249,7 +271,7 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
|
||||
|
||||
cur_frm.cscript.schedule_date = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "schedule_date");
|
||||
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "schedule_date");
|
||||
}
|
||||
|
||||
frappe.provide("erpnext.buying");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -153,7 +153,7 @@ class PurchaseOrder(BuyingController):
|
||||
item_wh_list = []
|
||||
for d in self.get("items"):
|
||||
if (not po_item_rows or d.name in po_item_rows) and [d.item_code, d.warehouse] not in item_wh_list \
|
||||
and frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes" and d.warehouse:
|
||||
and frappe.db.get_value("Item", d.item_code, "is_stock_item") and d.warehouse:
|
||||
item_wh_list.append([d.item_code, d.warehouse])
|
||||
|
||||
for item_code, warehouse in item_wh_list:
|
||||
|
||||
@@ -5,14 +5,19 @@ frappe.listview_settings['Purchase Order'] = {
|
||||
if(doc.status==="Stopped") {
|
||||
return [__("Stopped"), "darkgrey", "status,=,Stopped"];
|
||||
} else if(flt(doc.per_received) < 100 && doc.status!=="Stopped") {
|
||||
return [__("Not Received"), "orange", "per_received,<,100|status,!=,Stopped"];
|
||||
if(flt(doc.per_billed) < 100) {
|
||||
return [__("To Receive and Bill"), "orange",
|
||||
"per_received,<,100|per_billed,<,100|status,!=,Stopped"];
|
||||
} else {
|
||||
return [__("To Receive"), "orange",
|
||||
"per_received,<,100|per_billed,=,100|status,!=,Stopped"];
|
||||
}
|
||||
} else if(flt(doc.per_received) == 100 && flt(doc.per_billed) < 100 && doc.status!=="Stopped") {
|
||||
return [__("To Bill"), "orange", "per_received,=,100|per_billed,<,100|status,!=,Stopped"];
|
||||
} else if(flt(doc.per_received) == 100 && flt(doc.per_billed) == 100 && doc.status!=="Stopped") {
|
||||
return [__("Completed"), "green", "per_received,=,100|per_billed,=,100|status,!=,Stopped"];
|
||||
}
|
||||
},
|
||||
order_by: "per_received asc, modified desc",
|
||||
onload: function(listview) {
|
||||
var method = "erpnext.buying.doctype.purchase_order.purchase_order.stop_or_unstop_purchase_orders";
|
||||
|
||||
|
||||
@@ -80,6 +80,8 @@ def create_purchase_order(**args):
|
||||
po.company = args.company or "_Test Company"
|
||||
po.supplier = args.customer or "_Test Supplier"
|
||||
po.is_subcontracted = args.is_subcontracted or "No"
|
||||
po.currency = args.currency or frappe.db.get_value("Company", po.company, "default_currency")
|
||||
po.conversion_factor = args.conversion_factor or 1
|
||||
|
||||
po.append("items", {
|
||||
"item_code": args.item or args.item_code or "_Test Item",
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Small Text",
|
||||
@@ -192,10 +192,11 @@
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "price_list_rate",
|
||||
"fieldname": "discount_percentage",
|
||||
"fieldtype": "Percent",
|
||||
"in_list_view": 1,
|
||||
"label": "Discount %",
|
||||
"label": "Discount on Price List Rate (%)",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 0
|
||||
@@ -537,7 +538,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-05-14 14:54:16.899713",
|
||||
"modified": "2015-06-02 14:19:21.459032",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order Item",
|
||||
|
||||
@@ -57,3 +57,7 @@ cur_frm.fields_dict['item_serial_no'].get_query = function(doc, cdt, cdn) {
|
||||
|
||||
return { filters: filter }
|
||||
}
|
||||
|
||||
cur_frm.add_fetch('item_code', 'item_name', 'item_name');
|
||||
cur_frm.add_fetch('item_code', 'description', 'description');
|
||||
|
||||
|
||||
@@ -127,6 +127,14 @@
|
||||
"permlevel": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item Name",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
@@ -219,7 +227,7 @@
|
||||
"icon": "icon-search",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2015-04-14 07:37:07.331291",
|
||||
"modified": "2015-06-08 02:40:25.121948",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Quality Inspection",
|
||||
|
||||
@@ -31,7 +31,6 @@ class QualityInspection(Document):
|
||||
(self.name, self.modified, self.purchase_receipt_no,
|
||||
self.item_code))
|
||||
|
||||
|
||||
def on_cancel(self):
|
||||
if self.purchase_receipt_no:
|
||||
frappe.db.sql("""update `tabPurchase Receipt Item` t1, `tabPurchase Receipt` t2
|
||||
@@ -39,7 +38,6 @@ class QualityInspection(Document):
|
||||
where t1.parent = %s and t1.item_code = %s and t1.parent = t2.name""",
|
||||
(self.modified, self.purchase_receipt_no, self.item_code))
|
||||
|
||||
|
||||
def item_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
if filters.get("from"):
|
||||
from frappe.desk.reportview import get_match_cond
|
||||
|
||||
@@ -46,6 +46,8 @@ cur_frm.cscript.make_dashboard = function(doc) {
|
||||
+ '</b> / <span class="text-muted">' + __("Total Unpaid") + ": <b>"
|
||||
+ format_currency(r.message.total_unpaid, r.message.company_currency[0])
|
||||
+ '</b></span>');
|
||||
} else {
|
||||
cur_frm.dashboard.set_headline("");
|
||||
}
|
||||
}
|
||||
cur_frm.dashboard.set_badge_count(r.message);
|
||||
|
||||
@@ -1,247 +1,254 @@
|
||||
{
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-01-10 16:34:11",
|
||||
"description": "Supplier of Goods or Services.",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-01-10 16:34:11",
|
||||
"description": "Supplier of Goods or Services.",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "basic_info",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "",
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "icon-user",
|
||||
"fieldname": "basic_info",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "",
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "icon-user",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"label": "Series",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "naming_series",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "SUPP-",
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"label": "Series",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "naming_series",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "SUPP-",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "supplier_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "Supplier Name",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "supplier_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"fieldname": "supplier_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "Supplier Name",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "supplier_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "supplier_type",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Supplier Type",
|
||||
"oldfieldname": "supplier_type",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Supplier Type",
|
||||
"permlevel": 0,
|
||||
"fieldname": "supplier_type",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Supplier Type",
|
||||
"oldfieldname": "supplier_type",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Supplier Type",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "address_contacts",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Address & Contacts",
|
||||
"oldfieldtype": "Column Break",
|
||||
"options": "icon-map-marker",
|
||||
"fieldname": "is_frozen",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Frozen",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "address_contacts",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Address & Contacts",
|
||||
"oldfieldtype": "Column Break",
|
||||
"options": "icon-map-marker",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "address_html",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Address HTML",
|
||||
"permlevel": 0,
|
||||
"fieldname": "address_html",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Address HTML",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"fieldname": "column_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "contact_html",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Contact HTML",
|
||||
"permlevel": 0,
|
||||
"fieldname": "contact_html",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Contact HTML",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "default_payable_accounts",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Default Payable Accounts",
|
||||
"fieldname": "default_payable_accounts",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Default Payable Accounts",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"description": "Mention if non-standard receivable account applicable",
|
||||
"fieldname": "accounts",
|
||||
"fieldtype": "Table",
|
||||
"label": "Accounts",
|
||||
"options": "Party Account",
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"description": "Mention if non-standard receivable account applicable",
|
||||
"fieldname": "accounts",
|
||||
"fieldtype": "Table",
|
||||
"label": "Accounts",
|
||||
"options": "Party Account",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "more_info",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "More Info",
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "icon-file-text",
|
||||
"fieldname": "more_info",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "More Info",
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "icon-file-text",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "default_currency",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Default Currency",
|
||||
"no_copy": 1,
|
||||
"options": "Currency",
|
||||
"fieldname": "default_currency",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Default Currency",
|
||||
"no_copy": 1,
|
||||
"options": "Currency",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "default_price_list",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Price List",
|
||||
"options": "Price List",
|
||||
"fieldname": "default_price_list",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Price List",
|
||||
"options": "Price List",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "default_taxes_and_charges",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Taxes and Charges",
|
||||
"options": "Purchase Taxes and Charges Template",
|
||||
"fieldname": "default_taxes_and_charges",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Taxes and Charges",
|
||||
"options": "Purchase Taxes and Charges Template",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "credit_days",
|
||||
"fieldtype": "Int",
|
||||
"label": "Credit Days",
|
||||
"fieldname": "credit_days",
|
||||
"fieldtype": "Int",
|
||||
"label": "Credit Days",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break2",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"fieldname": "column_break2",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "website",
|
||||
"fieldtype": "Data",
|
||||
"label": "Website",
|
||||
"oldfieldname": "website",
|
||||
"oldfieldtype": "Data",
|
||||
"fieldname": "website",
|
||||
"fieldtype": "Data",
|
||||
"label": "Website",
|
||||
"oldfieldname": "website",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"description": "Statutory info and other general information about your Supplier",
|
||||
"fieldname": "supplier_details",
|
||||
"fieldtype": "Text",
|
||||
"label": "Supplier Details",
|
||||
"oldfieldname": "supplier_details",
|
||||
"oldfieldtype": "Code",
|
||||
"description": "Statutory info and other general information about your Supplier",
|
||||
"fieldname": "supplier_details",
|
||||
"fieldtype": "Text",
|
||||
"label": "Supplier Details",
|
||||
"oldfieldname": "supplier_details",
|
||||
"oldfieldtype": "Code",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "communications",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Communications",
|
||||
"options": "Communication",
|
||||
"permlevel": 0,
|
||||
"fieldname": "communications",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Communications",
|
||||
"options": "Communication",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
}
|
||||
],
|
||||
"icon": "icon-user",
|
||||
"idx": 1,
|
||||
"modified": "2015-02-24 17:35:03.821319",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"icon": "icon-user",
|
||||
"idx": 1,
|
||||
"modified": "2015-07-17 09:39:05.318826",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase User"
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Manager",
|
||||
"submit": 0,
|
||||
"amend": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Manager",
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Master Manager",
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"amend": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Master Manager",
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"role": "Material User"
|
||||
},
|
||||
"apply_user_permissions": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"role": "Stock User"
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Material Manager"
|
||||
},
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Stock Manager"
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"apply_user_permissions": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"role": "Accounts User"
|
||||
},
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager"
|
||||
}
|
||||
],
|
||||
"search_fields": "supplier_name, supplier_type",
|
||||
],
|
||||
"search_fields": "supplier_name, supplier_type",
|
||||
"title_field": "supplier_name"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Small Text",
|
||||
@@ -121,10 +121,11 @@
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "price_list_rate",
|
||||
"fieldname": "discount_percentage",
|
||||
"fieldtype": "Percent",
|
||||
"in_list_view": 1,
|
||||
"label": "Discount %",
|
||||
"label": "Discount on Price List Rate (%)",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 0
|
||||
@@ -412,7 +413,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-05-14 14:54:36.253819",
|
||||
"modified": "2015-06-02 14:19:33.922968",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Quotation Item",
|
||||
|
||||
3
erpnext/change_log/current/readme.md
Normal file
3
erpnext/change_log/current/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Leave change log files in this folder for user release notes.
|
||||
|
||||
(this file is just a place holder, don't delete it)
|
||||
8
erpnext/change_log/v5/v5_0_11.md
Normal file
8
erpnext/change_log/v5/v5_0_11.md
Normal file
@@ -0,0 +1,8 @@
|
||||
- Watch help videos in new module "Learn"
|
||||
- Letter head and Terms removed from Purchase Invoice
|
||||
- Renaming Discount fields to "Discount on Price List Rate"
|
||||
- Backup manager: You you can choose which backup to download
|
||||
- "Reserved Warehouse" is renamed "Delivery Warehouse" in Sales Order
|
||||
- Timezone fixes: See all time-stamps in Events etc in your timezone, if you are not in the system timezone.
|
||||
- POS Setting is renamed to POS Profile
|
||||
- Fixes to POS
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user