mirror of
https://github.com/frappe/erpnext.git
synced 2025-12-03 18:35:36 +00:00
Compare commits
554 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc35138356 | ||
|
|
08617f7700 | ||
|
|
cfecf3c5b1 | ||
|
|
831100b657 | ||
|
|
f296a2f58a | ||
|
|
aae557e8a1 | ||
|
|
0f92c4b85b | ||
|
|
217df1761d | ||
|
|
d355741462 | ||
|
|
7b6ed4f16e | ||
|
|
c5a682e9d9 | ||
|
|
b4fa105555 | ||
|
|
e1aef6f0db | ||
|
|
6f35d2b52d | ||
|
|
197f57c050 | ||
|
|
c74fa7546b | ||
|
|
233ef8752d | ||
|
|
afd9e7546f | ||
|
|
8b1532d691 | ||
|
|
a887c29e06 | ||
|
|
7114b72be8 | ||
|
|
92ab345daf | ||
|
|
79dd4d707b | ||
|
|
a3a733fa91 | ||
|
|
7a9b014f72 | ||
|
|
61b4a98356 | ||
|
|
46db69b304 | ||
|
|
a0be41322d | ||
|
|
05f29988f4 | ||
|
|
d7903de51c | ||
|
|
0e31cc9ff8 | ||
|
|
32280a11aa | ||
|
|
a2f9d2f89c | ||
|
|
5fc5355b96 | ||
|
|
30c73e6b35 | ||
|
|
7a6b88c791 | ||
|
|
9c42124fbc | ||
|
|
0378b15412 | ||
|
|
3f86369604 | ||
|
|
cc99d92116 | ||
|
|
f880975438 | ||
|
|
daa8db4d95 | ||
|
|
9ff39e2d1b | ||
|
|
9d70c5d13f | ||
|
|
a9a82919e7 | ||
|
|
723ed07642 | ||
|
|
86b531aea6 | ||
|
|
781a420593 | ||
|
|
08f709c2a2 | ||
|
|
a849f6e21e | ||
|
|
6ff8387d56 | ||
|
|
2af9ff9c33 | ||
|
|
01905cad2f | ||
|
|
58260e4f0a | ||
|
|
a01869bb20 | ||
|
|
3a92615f23 | ||
|
|
eca8db7405 | ||
|
|
58c4cfc0d7 | ||
|
|
ab52a4db75 | ||
|
|
c8d3a8c0f5 | ||
|
|
aab88eee3e | ||
|
|
d9f4c83567 | ||
|
|
b96dd366ce | ||
|
|
597ec83af7 | ||
|
|
e802bdd186 | ||
|
|
3a949bb298 | ||
|
|
1e920dd0d8 | ||
|
|
09536f402e | ||
|
|
581f26b7a0 | ||
|
|
0418a2f70a | ||
|
|
5e3338744c | ||
|
|
da3762700c | ||
|
|
2c9fccd8ba | ||
|
|
286c4fa640 | ||
|
|
a144e002db | ||
|
|
553dabaa08 | ||
|
|
55d0d32c77 | ||
|
|
1f93745eef | ||
|
|
e3a02dd5f6 | ||
|
|
153733414f | ||
|
|
ac535f0ce9 | ||
|
|
3886529787 | ||
|
|
d2cd713b89 | ||
|
|
6b378e1669 | ||
|
|
a4fc30bbe4 | ||
|
|
b4b0e4424d | ||
|
|
f3bdcc2a84 | ||
|
|
19901c14c9 | ||
|
|
714d686e50 | ||
|
|
094dc1dee6 | ||
|
|
cdcf424ba5 | ||
|
|
2a2b884e32 | ||
|
|
c1e00f4daa | ||
|
|
0a22aab6bb | ||
|
|
43c6d1a518 | ||
|
|
090219814e | ||
|
|
510dc60bf0 | ||
|
|
12d520a366 | ||
|
|
a06a527fe6 | ||
|
|
9a7681535f | ||
|
|
8e1a612b3b | ||
|
|
21085bf2be | ||
|
|
8e9413829d | ||
|
|
8208f878ff | ||
|
|
a7130649cd | ||
|
|
b2d9ffa4ca | ||
|
|
cc4f13a862 | ||
|
|
60681baf80 | ||
|
|
ea6049078a | ||
|
|
d83e8c56b2 | ||
|
|
e0ade62e38 | ||
|
|
c78b921412 | ||
|
|
9e9e415c5f | ||
|
|
0692e5eb78 | ||
|
|
3fa5eec07b | ||
|
|
ab1bf1af19 | ||
|
|
15e0861e82 | ||
|
|
aa493a25f8 | ||
|
|
1c2915f74b | ||
|
|
391b3b67cb | ||
|
|
0361c50503 | ||
|
|
517a3071cf | ||
|
|
0e30e705c5 | ||
|
|
940df7563b | ||
|
|
f390872944 | ||
|
|
cfd18d4e03 | ||
|
|
6c73439e7f | ||
|
|
2389e2c438 | ||
|
|
c2341ca8e3 | ||
|
|
3b810ea8da | ||
|
|
f85d6aeecd | ||
|
|
a13762b05f | ||
|
|
dd5a0a1f26 | ||
|
|
a6ad0b0ec8 | ||
|
|
077e20f7ae | ||
|
|
73c6d2e44c | ||
|
|
d7a13ceb10 | ||
|
|
6eadd6657d | ||
|
|
0c890a110d | ||
|
|
0f420baaba | ||
|
|
b32d96fc24 | ||
|
|
cfc9e18749 | ||
|
|
25d6d08329 | ||
|
|
9bf4c754c8 | ||
|
|
79b02db156 | ||
|
|
e55dd7233d | ||
|
|
3ba969ad58 | ||
|
|
f93cb0a6ba | ||
|
|
e23cfd22ca | ||
|
|
0d1b022ea0 | ||
|
|
aca3772f7d | ||
|
|
569815b5ad | ||
|
|
80b696ce25 | ||
|
|
ab7570b7e5 | ||
|
|
c87f8c6f00 | ||
|
|
c5c4de885b | ||
|
|
a970bcc56d | ||
|
|
5e2d822509 | ||
|
|
6be1475882 | ||
|
|
43f05d1de1 | ||
|
|
26bb028ec4 | ||
|
|
1637f0aeaf | ||
|
|
353f64caf8 | ||
|
|
5afb00a7f4 | ||
|
|
b0ec0f545e | ||
|
|
7088513da9 | ||
|
|
8908d4ee8f | ||
|
|
8133970944 | ||
|
|
dac7ede911 | ||
|
|
b052498348 | ||
|
|
d62de6c8e5 | ||
|
|
d37cc9a5d0 | ||
|
|
c7062d8be7 | ||
|
|
1435e30ad5 | ||
|
|
b2ff0bda32 | ||
|
|
ff42d7b5ed | ||
|
|
35a4cae2f6 | ||
|
|
a76cafecb0 | ||
|
|
715ecc31c8 | ||
|
|
09145674ec | ||
|
|
11eebddb79 | ||
|
|
7d7417af29 | ||
|
|
6edb6e0b09 | ||
|
|
e057575661 | ||
|
|
b7b5eeb92b | ||
|
|
85731053fd | ||
|
|
9f3eb9e077 | ||
|
|
5ac8dbfceb | ||
|
|
f4f2301e5b | ||
|
|
7888336524 | ||
|
|
b8c2e02c67 | ||
|
|
a9e9efbd23 | ||
|
|
2f175e6d85 | ||
|
|
df817a858b | ||
|
|
4a73059ed3 | ||
|
|
552615525c | ||
|
|
25e408fd2a | ||
|
|
375a6f67ae | ||
|
|
01095799e8 | ||
|
|
ead8d82a84 | ||
|
|
2c229c6403 | ||
|
|
5fb78a375d | ||
|
|
8fcad571f5 | ||
|
|
53d7e667dd | ||
|
|
7395716476 | ||
|
|
c068b6a885 | ||
|
|
02d28c5908 | ||
|
|
90d0d24d1a | ||
|
|
6aab14f9cf | ||
|
|
163dbdca34 | ||
|
|
dcc99a2644 | ||
|
|
f5297cf386 | ||
|
|
9f7fd16882 | ||
|
|
5296ab1f87 | ||
|
|
e42c14f2cb | ||
|
|
4ef10fd6c3 | ||
|
|
4c0d0e226b | ||
|
|
094caaa03e | ||
|
|
ce51553d29 | ||
|
|
f41fc21274 | ||
|
|
1f49b77529 | ||
|
|
a0012f8c48 | ||
|
|
4b1c3ad7ac | ||
|
|
a063803224 | ||
|
|
63c7fd90a5 | ||
|
|
c9c02c7c85 | ||
|
|
bc7ef1937e | ||
|
|
75b63c5b4c | ||
|
|
625191d20a | ||
|
|
1417c7e828 | ||
|
|
a4bbc68945 | ||
|
|
2d7a591c61 | ||
|
|
448a5e1c9c | ||
|
|
7be75adc3f | ||
|
|
fafee7cf61 | ||
|
|
16aa23e454 | ||
|
|
a4d5c5414d | ||
|
|
b104e3595c | ||
|
|
5a06dd1ed1 | ||
|
|
27fe55efe1 | ||
|
|
9089b242ba | ||
|
|
98e511d236 | ||
|
|
93784d3804 | ||
|
|
d29fde0bf3 | ||
|
|
8326925fe8 | ||
|
|
a924b636a4 | ||
|
|
3526ed975c | ||
|
|
d0faec3cc0 | ||
|
|
661a5ce332 | ||
|
|
b289aa3548 | ||
|
|
4ed521162e | ||
|
|
8865d05b4c | ||
|
|
4df46737ef | ||
|
|
09ac547a80 | ||
|
|
c1bbaf07a4 | ||
|
|
73a081d806 | ||
|
|
e1df414f8b | ||
|
|
cefef3b62d | ||
|
|
bd4ee60d1e | ||
|
|
f6a9eec23a | ||
|
|
5742d0836e | ||
|
|
0555223797 | ||
|
|
de93efb304 | ||
|
|
6856033d3c | ||
|
|
0735165ef3 | ||
|
|
1aa5462f36 | ||
|
|
f83514418e | ||
|
|
3c13e8e8b9 | ||
|
|
de0955b8ed | ||
|
|
82af75b853 | ||
|
|
d3ce4f815d | ||
|
|
85bf9203ed | ||
|
|
db12f75681 | ||
|
|
3763169978 | ||
|
|
36a8c431f5 | ||
|
|
5a67431daa | ||
|
|
c4e92b3004 | ||
|
|
2d90e8a2de | ||
|
|
4dacb89da6 | ||
|
|
c552d74746 | ||
|
|
2697c2d869 | ||
|
|
4a950abf2e | ||
|
|
7f10f4eea1 | ||
|
|
5c93260eec | ||
|
|
485d9c133a | ||
|
|
891d9aeee9 | ||
|
|
51f0d6d409 | ||
|
|
80374be724 | ||
|
|
619bf561da | ||
|
|
13c15d0222 | ||
|
|
3d31bccaf6 | ||
|
|
3959bf34ee | ||
|
|
1897ed38df | ||
|
|
126c4efb2c | ||
|
|
7d0bc2bd5a | ||
|
|
0c70ae44c3 | ||
|
|
024dc4a4c9 | ||
|
|
e3567ff31b | ||
|
|
97842ca804 | ||
|
|
d14799a9fa | ||
|
|
e534221245 | ||
|
|
4acfec901e | ||
|
|
a981a8a153 | ||
|
|
11e1c60cd3 | ||
|
|
fe7baae9f7 | ||
|
|
da64113b9a | ||
|
|
fb76cb7a78 | ||
|
|
1bd69b4490 | ||
|
|
62d51d82ea | ||
|
|
6ddc554965 | ||
|
|
5a6fc77751 | ||
|
|
733db826ec | ||
|
|
6643156df6 | ||
|
|
6022f2bcf8 | ||
|
|
b890492dc0 | ||
|
|
6ea108f01d | ||
|
|
628bed1f5a | ||
|
|
4c0e3aa097 | ||
|
|
631e334a3f | ||
|
|
8f4d92eba2 | ||
|
|
2f4193757e | ||
|
|
cba64988df | ||
|
|
17e6fce486 | ||
|
|
05fb3f2d75 | ||
|
|
af6360b273 | ||
|
|
043a47a9c0 | ||
|
|
23e424911c | ||
|
|
a5fbeaa3d3 | ||
|
|
8aeb4b04bd | ||
|
|
f3b07495f6 | ||
|
|
70f89462a8 | ||
|
|
bbc7f474c3 | ||
|
|
26fe30685a | ||
|
|
7bdd27f7e2 | ||
|
|
96ec4aeda0 | ||
|
|
cce65d41b8 | ||
|
|
a44d46e535 | ||
|
|
4f16d17d21 | ||
|
|
759bb0eb62 | ||
|
|
d7aa71aa70 | ||
|
|
32207ad722 | ||
|
|
8a32ad206a | ||
|
|
16bd2ed967 | ||
|
|
393b12a37f | ||
|
|
d1332f6c24 | ||
|
|
f36fa088f8 | ||
|
|
bb63103183 | ||
|
|
7760db7563 | ||
|
|
0ea1e67ce7 | ||
|
|
587b52dcd4 | ||
|
|
efcdf2fd42 | ||
|
|
010a05df48 | ||
|
|
58d565a882 | ||
|
|
b655b07f20 | ||
|
|
afb59fa5c0 | ||
|
|
cb4b86512d | ||
|
|
49f919a4fc | ||
|
|
4a9127f9a6 | ||
|
|
c4a670c8c8 | ||
|
|
a26e2c064a | ||
|
|
3889d0f0a0 | ||
|
|
4e81fb20b9 | ||
|
|
dfba52b834 | ||
|
|
f665e42e2a | ||
|
|
560cc66a36 | ||
|
|
d08953b72b | ||
|
|
34e4ac2398 | ||
|
|
3dbaa3c2d9 | ||
|
|
613d82e12f | ||
|
|
4f2fa173c9 | ||
|
|
d36e635e60 | ||
|
|
e86d21ea15 | ||
|
|
b6fda118b9 | ||
|
|
2c607e5562 | ||
|
|
95fce2395a | ||
|
|
0f0dcd9035 | ||
|
|
ce291c253b | ||
|
|
e85c6ad236 | ||
|
|
df16cdcf31 | ||
|
|
00303858df | ||
|
|
6f54a7b7d8 | ||
|
|
fba8bfc0d0 | ||
|
|
4db4f21d16 | ||
|
|
abf9ef0244 | ||
|
|
22ad81fb57 | ||
|
|
923c5462a2 | ||
|
|
753b3d1c28 | ||
|
|
b9046edb85 | ||
|
|
7932eba733 | ||
|
|
5ba9c82922 | ||
|
|
fc48ce7073 | ||
|
|
8b9a84b568 | ||
|
|
cc4e6a25f6 | ||
|
|
17923863de | ||
|
|
32efea5e38 | ||
|
|
87a2c1d27d | ||
|
|
c581d67bba | ||
|
|
1865e0df7c | ||
|
|
308ae1f155 | ||
|
|
2b54cee4aa | ||
|
|
ba47f89702 | ||
|
|
0ea32faf3d | ||
|
|
7be0736154 | ||
|
|
97bf12734a | ||
|
|
4bccd692e5 | ||
|
|
07f8e6bbfc | ||
|
|
15c7a05879 | ||
|
|
82e76b2c0c | ||
|
|
d6757b7af6 | ||
|
|
b380a02d09 | ||
|
|
64980fed59 | ||
|
|
7df8c0ef82 | ||
|
|
28fe73640b | ||
|
|
7cfe247b2e | ||
|
|
332b4171c0 | ||
|
|
e5544b8c86 | ||
|
|
38e5e7f616 | ||
|
|
a595346769 | ||
|
|
8dace802dc | ||
|
|
ac6259dfe8 | ||
|
|
f801cc953b | ||
|
|
c117048fde | ||
|
|
73fd508ccf | ||
|
|
7cc972969f | ||
|
|
734c32b970 | ||
|
|
fa862e6814 | ||
|
|
d333d2e6eb | ||
|
|
3b78a018aa | ||
|
|
cc581d21f0 | ||
|
|
dca60888ce | ||
|
|
b2465c7a69 | ||
|
|
14477c7f51 | ||
|
|
f0ee3d26a7 | ||
|
|
2e87202b3b | ||
|
|
1024b55f99 | ||
|
|
9ba7b678fe | ||
|
|
a8c8e6b78a | ||
|
|
ce107086e7 | ||
|
|
49d1449d2b | ||
|
|
2f6789e54d | ||
|
|
f2893e5701 | ||
|
|
870410c9d5 | ||
|
|
30bca30f20 | ||
|
|
80f1d5f63d | ||
|
|
76d4fa9f2b | ||
|
|
e17c9d9978 | ||
|
|
e8883e20cd | ||
|
|
af4d588f64 | ||
|
|
4f0a4a1a2d | ||
|
|
7f7a1b48ed | ||
|
|
f094662f5e | ||
|
|
e2fc03e561 | ||
|
|
3987b4b714 | ||
|
|
e889a58724 | ||
|
|
1638994436 | ||
|
|
ff99492481 | ||
|
|
a65af7a2f5 | ||
|
|
6ba48c58e8 | ||
|
|
3b4f481ca4 | ||
|
|
548e93b2d3 | ||
|
|
76eb9b32b3 | ||
|
|
0ac4cfa9b1 | ||
|
|
dc34393b8a | ||
|
|
023a865e1e | ||
|
|
d2a7ec1add | ||
|
|
564ee5399c | ||
|
|
2518a2ab16 | ||
|
|
df3e8853ae | ||
|
|
a0b7ff60b8 | ||
|
|
97383716e6 | ||
|
|
f788117b3e | ||
|
|
6784335e2c | ||
|
|
c5c9dc5f6d | ||
|
|
819e24ddde | ||
|
|
313ed4feeb | ||
|
|
5157fa9233 | ||
|
|
774b96495f | ||
|
|
ea4c2c9e7d | ||
|
|
b42bbf1b6f | ||
|
|
c768febac6 | ||
|
|
0449d30423 | ||
|
|
f17dfb0ebe | ||
|
|
13273412d1 | ||
|
|
f198b1d032 | ||
|
|
9512a43d44 | ||
|
|
50db128ff1 | ||
|
|
5eaf7d0517 | ||
|
|
760b01912a | ||
|
|
4c331206f1 | ||
|
|
f62e789173 | ||
|
|
02181c017a | ||
|
|
7fece8f431 | ||
|
|
bd7a165318 | ||
|
|
4114365017 | ||
|
|
aace25ac2b | ||
|
|
697f1186c0 | ||
|
|
55bee7a393 | ||
|
|
c151b58acd | ||
|
|
ef73452abe | ||
|
|
ff73090ad2 | ||
|
|
b63adcbac7 | ||
|
|
f492d5f61d | ||
|
|
4ac386d0fe | ||
|
|
4753bd4519 | ||
|
|
76815cf2be | ||
|
|
936d147b4b | ||
|
|
20090306f6 | ||
|
|
a1a7beb12e | ||
|
|
9f2847e86c | ||
|
|
44d8224a3b | ||
|
|
5ba438af80 | ||
|
|
3d6b51089c | ||
|
|
f817663f11 | ||
|
|
bf5ea691cf | ||
|
|
91578757ff | ||
|
|
48e206d983 | ||
|
|
bed6f4748e | ||
|
|
ee2b523b31 | ||
|
|
88bd0674ed | ||
|
|
4ff2b0114f | ||
|
|
e7cc6649eb | ||
|
|
4d19d344b6 | ||
|
|
e7bc2beea0 | ||
|
|
cd416a3135 | ||
|
|
2a0e8e24ec | ||
|
|
c75300dc43 | ||
|
|
8d36b362d1 | ||
|
|
4c57fae726 | ||
|
|
2d1b5b0769 | ||
|
|
1d7646f31f | ||
|
|
1a19746904 | ||
|
|
e7fec6e659 | ||
|
|
c45e271b3e | ||
|
|
422d483baf | ||
|
|
c56f771c81 | ||
|
|
89923b84b1 | ||
|
|
c936f07a1e | ||
|
|
aea2fbf82d | ||
|
|
7a1ea42271 | ||
|
|
58438f4e5b | ||
|
|
f6d18e81e9 | ||
|
|
e8f3050e27 | ||
|
|
cbe63ec418 | ||
|
|
94899981d3 | ||
|
|
6a4dae3a9d | ||
|
|
57c6b49d1a | ||
|
|
eae7424984 | ||
|
|
e394cec194 | ||
|
|
818492387a | ||
|
|
31cb24f48d | ||
|
|
590d8d3d3e | ||
|
|
6025e498f2 | ||
|
|
09cad814cd | ||
|
|
c75a2b1eed |
20
MANIFEST.in
20
MANIFEST.in
@@ -1,20 +0,0 @@
|
||||
include MANIFEST.in
|
||||
include requirements.txt
|
||||
include *.json
|
||||
include *.md
|
||||
include *.py
|
||||
include *.txt
|
||||
include .travis.yml
|
||||
recursive-include erpnext *.txt
|
||||
recursive-include erpnext *.css
|
||||
recursive-include erpnext *.csv
|
||||
recursive-include erpnext *.html
|
||||
recursive-include erpnext *.ico
|
||||
recursive-include erpnext *.js
|
||||
recursive-include erpnext *.json
|
||||
recursive-include erpnext *.md
|
||||
recursive-include erpnext *.png
|
||||
recursive-include erpnext *.py
|
||||
recursive-include erpnext *.svg
|
||||
recursive-include erpnext/public *
|
||||
recursive-exclude * *.pyc
|
||||
@@ -5,7 +5,7 @@ import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
from frappe.utils import getdate
|
||||
|
||||
__version__ = '11.1.20'
|
||||
__version__ = '11.1.35'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
|
||||
@@ -42,15 +42,14 @@ frappe.ui.form.on('Account', {
|
||||
// show / hide convert buttons
|
||||
frm.trigger('add_toolbar_buttons');
|
||||
}
|
||||
frm.add_custom_button(__('Update Account Name / Number'), function () {
|
||||
frm.trigger("update_account_number");
|
||||
});
|
||||
}
|
||||
|
||||
if(!frm.doc.__islocal) {
|
||||
frm.add_custom_button(__('Merge Account'), function () {
|
||||
frm.trigger("merge_account");
|
||||
});
|
||||
if (frm.has_perm('write')) {
|
||||
frm.add_custom_button(__('Update Account Name / Number'), function () {
|
||||
frm.trigger("update_account_number");
|
||||
});
|
||||
frm.add_custom_button(__('Merge Account'), function () {
|
||||
frm.trigger("merge_account");
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
account_type: function (frm) {
|
||||
|
||||
@@ -105,20 +105,27 @@ class Account(NestedSet):
|
||||
descendants = get_descendants_of('Company', self.company)
|
||||
if not descendants: return
|
||||
|
||||
acc_name_map = {}
|
||||
acc_name = frappe.db.get_value('Account', self.parent_account, "account_name")
|
||||
parent_acc_name_map = {}
|
||||
parent_acc_name = frappe.db.get_value('Account', self.parent_account, "account_name")
|
||||
for d in frappe.db.get_values('Account',
|
||||
{"company": ["in", descendants], "account_name": acc_name},
|
||||
{"company": ["in", descendants], "account_name": parent_acc_name},
|
||||
["company", "name"], as_dict=True):
|
||||
acc_name_map[d["company"]] = d["name"]
|
||||
parent_acc_name_map[d["company"]] = d["name"]
|
||||
|
||||
if not acc_name_map: return
|
||||
if not parent_acc_name_map: return
|
||||
|
||||
for company in descendants:
|
||||
if not parent_acc_name_map.get(company):
|
||||
frappe.throw(_("While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA")
|
||||
.format(company, parent_acc_name))
|
||||
|
||||
doc = frappe.copy_doc(self)
|
||||
doc.flags.ignore_root_company_validation = True
|
||||
doc.update({"company": company, "account_currency": None,
|
||||
"parent": acc_name_map[company], "parent_account": acc_name_map[company]})
|
||||
doc.update({
|
||||
"company": company,
|
||||
"account_currency": None,
|
||||
"parent_account": parent_acc_name_map[company]
|
||||
})
|
||||
doc.save()
|
||||
frappe.msgprint(_("Account {0} is added in the child company {1}")
|
||||
.format(doc.name, company))
|
||||
@@ -261,7 +268,7 @@ def update_account_number(name, account_name, account_number=None):
|
||||
|
||||
new_name = get_account_autoname(account_number, account_name, account.company)
|
||||
if name != new_name:
|
||||
frappe.rename_doc("Account", name, new_name, ignore_permissions=1)
|
||||
frappe.rename_doc("Account", name, new_name, force=1)
|
||||
return new_name
|
||||
|
||||
@frappe.whitelist()
|
||||
@@ -280,7 +287,7 @@ def merge_account(old, new, is_group, root_type, company):
|
||||
frappe.db.set_value("Account", new, "parent_account",
|
||||
frappe.db.get_value("Account", old, "parent_account"))
|
||||
|
||||
frappe.rename_doc("Account", old, new, merge=1, ignore_permissions=1)
|
||||
frappe.rename_doc("Account", old, new, merge=1, force=1)
|
||||
|
||||
return new
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"country_code": "de",
|
||||
"name": "Germany - Kontenplan SKR04",
|
||||
"name": "SKR04 ohne Kontonummern",
|
||||
"tree": {
|
||||
"Bilanz - Aktiva": {
|
||||
"Anlageverm\u00f6gen": {
|
||||
@@ -1383,8 +1383,7 @@
|
||||
"Sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge 1": {
|
||||
"Diskontertr\u00e4ge": {},
|
||||
"Diskontertr\u00e4ge aus verbundenen Unternehmen": {},
|
||||
"Laufende Ertr\u00e4ge aus Anteilen an Kapitalgesellschaften 100% / 50% steuerfrei": {},
|
||||
"Laufende Ertr\u00e4ge aus Anteilen an Kapitalgesellschaften 100% / 50% steuerfrei": {},
|
||||
"Laufende Ertr\u00e4ge aus Anteilen an Kapitalgesellschaften 100% / 50% steuerfrei": {},
|
||||
"Sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge 2": {},
|
||||
"Sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge aus verbundenen Unternehmen": {},
|
||||
"Sonstige Zinsertr\u00e4ge": {},
|
||||
@@ -1703,4 +1702,4 @@
|
||||
"root_type": "Asset"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,24 +38,24 @@
|
||||
"Kas": {
|
||||
"Kas Mata Uang Lain": {
|
||||
"Kas USD": {
|
||||
"account_number": "1112.0010",
|
||||
"account_number": "1112.001",
|
||||
"account_type": "Cash"
|
||||
},
|
||||
"account_number": "1112.000"
|
||||
},
|
||||
"Kas Rupiah": {
|
||||
"Kas Besar": {
|
||||
"account_number": "1111.0020",
|
||||
"account_number": "1111.002",
|
||||
"account_type": "Cash"
|
||||
},
|
||||
"Kas Kecil": {
|
||||
"account_number": "1111.0010",
|
||||
"account_number": "1111.001",
|
||||
"account_type": "Cash"
|
||||
},
|
||||
"account_number": "1111.000",
|
||||
"account_type": "Cash"
|
||||
},
|
||||
"account_number": "1110.0000"
|
||||
"account_number": "1110.000"
|
||||
},
|
||||
"Pendapatan Yang Akan di Terima": {
|
||||
"Pendapatan Yang di Terima": {
|
||||
@@ -98,7 +98,7 @@
|
||||
},
|
||||
"account_number": "1130.000"
|
||||
},
|
||||
"account_number": "1100.0000"
|
||||
"account_number": "1100.000"
|
||||
},
|
||||
"Aktiva Tetap": {
|
||||
"Aktiva": {
|
||||
@@ -121,20 +121,20 @@
|
||||
"Investasi": {
|
||||
"Investasi": {
|
||||
"Deposito": {
|
||||
"account_number": "1231.003",
|
||||
"account_number": "1231.300",
|
||||
"is_group": 1
|
||||
},
|
||||
"Investai Saham": {
|
||||
"Investasi Saham": {
|
||||
"Investasi Saham": {
|
||||
"account_number": "1231.0011"
|
||||
"account_number": "1231.101"
|
||||
},
|
||||
"account_number": "1231.001"
|
||||
"account_number": "1231.100"
|
||||
},
|
||||
"Investasi Perumahan": {
|
||||
"Investasi Perumahan": {
|
||||
"account_number": "1231.0021"
|
||||
"account_number": "1231.201"
|
||||
},
|
||||
"account_number": "1231.002"
|
||||
"account_number": "1231.200"
|
||||
},
|
||||
"account_number": "1231.000"
|
||||
},
|
||||
@@ -142,7 +142,7 @@
|
||||
},
|
||||
"account_number": "1200.000"
|
||||
},
|
||||
"account_number": "1000.0000",
|
||||
"account_number": "1000.000",
|
||||
"root_type": "Asset"
|
||||
},
|
||||
"Beban": {
|
||||
@@ -684,4 +684,4 @@
|
||||
"root_type": "Income"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Account Subtype', {
|
||||
refresh: function() {
|
||||
|
||||
}
|
||||
});
|
||||
134
erpnext/accounts/doctype/account_subtype/account_subtype.json
Normal file
134
erpnext/accounts/doctype/account_subtype/account_subtype.json
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:account_subtype",
|
||||
"beta": 0,
|
||||
"creation": "2018-10-25 15:46:08.054586",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "account_subtype",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Account Subtype",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-10-25 15:47:03.841390",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account Subtype",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class AccountSubtype(Document):
|
||||
pass
|
||||
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Account Subtype", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Account Subtype
|
||||
() => frappe.tests.make('Account Subtype', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
class TestAccountSubtype(unittest.TestCase):
|
||||
pass
|
||||
0
erpnext/accounts/doctype/account_type/__init__.py
Normal file
0
erpnext/accounts/doctype/account_type/__init__.py
Normal file
8
erpnext/accounts/doctype/account_type/account_type.js
Normal file
8
erpnext/accounts/doctype/account_type/account_type.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Account Type', {
|
||||
refresh: function() {
|
||||
|
||||
}
|
||||
});
|
||||
134
erpnext/accounts/doctype/account_type/account_type.json
Normal file
134
erpnext/accounts/doctype/account_type/account_type.json
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:account_type",
|
||||
"beta": 0,
|
||||
"creation": "2018-10-25 15:45:45.789963",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "account_type",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Account Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-10-25 15:46:51.042604",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account Type",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
9
erpnext/accounts/doctype/account_type/account_type.py
Normal file
9
erpnext/accounts/doctype/account_type/account_type.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class AccountType(Document):
|
||||
pass
|
||||
23
erpnext/accounts/doctype/account_type/test_account_type.js
Normal file
23
erpnext/accounts/doctype/account_type/test_account_type.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Account Type", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Account Type
|
||||
() => frappe.tests.make('Account Type', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
class TestAccountType(unittest.TestCase):
|
||||
pass
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,29 @@
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Bank', {
|
||||
onload: function(frm) {
|
||||
add_fields_to_mapping_table(frm);
|
||||
},
|
||||
refresh: function(frm) {
|
||||
|
||||
add_fields_to_mapping_table(frm);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let add_fields_to_mapping_table = function (frm) {
|
||||
let options = [];
|
||||
|
||||
frappe.model.with_doctype("Bank Transaction", function() {
|
||||
let meta = frappe.get_meta("Bank Transaction");
|
||||
meta.fields.forEach(value => {
|
||||
if (!["Section Break", "Column Break"].includes(value.fieldtype)) {
|
||||
options.push(value.fieldname);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
frappe.meta.get_docfield("Bank Transaction Mapping", "bank_transaction_field",
|
||||
frm.doc.name).options = options;
|
||||
|
||||
frm.fields_dict.bank_transaction_mapping.grid.refresh();
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
@@ -15,6 +16,7 @@
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -42,6 +44,134 @@
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fieldname": "data_import_configuration_section",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Data Import Configuration",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "bank_transaction_mapping",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Bank Transaction Mapping",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Bank Transaction Mapping",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_4",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "plaid_access_token",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Plaid Access Token",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
@@ -55,7 +185,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-04-07 17:00:21.246202",
|
||||
"modified": "2018-11-27 16:12:13.938776",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank",
|
||||
@@ -64,7 +194,6 @@
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
@@ -90,5 +219,6 @@
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Bank Account', {
|
||||
@@ -12,6 +12,11 @@ frappe.ui.form.on('Bank Account', {
|
||||
}
|
||||
};
|
||||
});
|
||||
frm.set_query("party_type", function() {
|
||||
return {
|
||||
query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
|
||||
};
|
||||
});
|
||||
},
|
||||
refresh: function(frm) {
|
||||
frappe.dynamic_link = { doc: frm.doc, fieldname: 'name', doctype: 'Bank Account' }
|
||||
@@ -24,5 +29,13 @@ frappe.ui.form.on('Bank Account', {
|
||||
else {
|
||||
frappe.contacts.render_address_and_contact(frm);
|
||||
}
|
||||
|
||||
if (frm.doc.integration_id) {
|
||||
frm.add_custom_button(__("Unlink external integrations"), function() {
|
||||
frappe.confirm(__("This action will unlink this account from any external service integrating ERPNext with your bank accounts. It cannot be undone. Are you certain ?"), function() {
|
||||
frm.set_value("integration_id", "");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,16 +13,47 @@ class BankAccount(Document):
|
||||
"""Load address and contacts in `__onload`"""
|
||||
load_address_and_contact(self)
|
||||
|
||||
def autoname(self):
|
||||
self.name = self.account_name + " - " + self.bank
|
||||
|
||||
def on_trash(self):
|
||||
delete_contact_and_address('BankAccount', self.name)
|
||||
|
||||
def validate(self):
|
||||
self.validate_company()
|
||||
self.validate_iban()
|
||||
|
||||
def validate_company(self):
|
||||
if self.is_company_account and not self.company:
|
||||
frappe.throw(_("Company is manadatory for company account"))
|
||||
|
||||
def validate_iban(self):
|
||||
'''
|
||||
Algorithm: https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN
|
||||
'''
|
||||
# IBAN field is optional
|
||||
if not self.iban:
|
||||
return
|
||||
|
||||
def encode_char(c):
|
||||
# Position in the alphabet (A=1, B=2, ...) plus nine
|
||||
return str(9 + ord(c) - 64)
|
||||
|
||||
# remove whitespaces, upper case to get the right number from ord()
|
||||
iban = ''.join(self.iban.split(' ')).upper()
|
||||
|
||||
# Move country code and checksum from the start to the end
|
||||
flipped = iban[4:] + iban[:4]
|
||||
|
||||
# Encode characters as numbers
|
||||
encoded = [encode_char(c) if ord(c) >= 65 and ord(c) <= 90 else c for c in flipped]
|
||||
|
||||
to_check = int(''.join(encoded))
|
||||
|
||||
if to_check % 97 != 1:
|
||||
frappe.throw(_('IBAN is not valid'))
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_bank_account(doctype, docname):
|
||||
doc = frappe.new_doc("Bank Account")
|
||||
|
||||
@@ -4,9 +4,46 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe import ValidationError
|
||||
import unittest
|
||||
|
||||
# test_records = frappe.get_test_records('Bank Account')
|
||||
|
||||
class TestBankAccount(unittest.TestCase):
|
||||
pass
|
||||
|
||||
def test_validate_iban(self):
|
||||
valid_ibans = [
|
||||
'GB82 WEST 1234 5698 7654 32',
|
||||
'DE91 1000 0000 0123 4567 89',
|
||||
'FR76 3000 6000 0112 3456 7890 189'
|
||||
]
|
||||
|
||||
invalid_ibans = [
|
||||
# wrong checksum (3rd place)
|
||||
'GB72 WEST 1234 5698 7654 32',
|
||||
'DE81 1000 0000 0123 4567 89',
|
||||
'FR66 3000 6000 0112 3456 7890 189'
|
||||
]
|
||||
|
||||
bank_account = frappe.get_doc({'doctype':'Bank Account'})
|
||||
|
||||
try:
|
||||
bank_account.validate_iban()
|
||||
except AttributeError:
|
||||
msg = _('BankAccount.validate_iban() failed for empty IBAN')
|
||||
self.fail(msg=msg)
|
||||
|
||||
for iban in valid_ibans:
|
||||
bank_account.iban = iban
|
||||
try:
|
||||
bank_account.validate_iban()
|
||||
except ValidationError:
|
||||
msg = _('BankAccount.validate_iban() failed for valid IBAN {}'.format(iban))
|
||||
self.fail(msg=msg)
|
||||
|
||||
for not_iban in invalid_ibans:
|
||||
bank_account.iban = not_iban
|
||||
msg = _('BankAccount.validate_iban() accepted invalid IBAN {}'.format(not_iban))
|
||||
with self.assertRaises(ValidationError, msg=msg):
|
||||
bank_account.validate_iban()
|
||||
|
||||
@@ -22,7 +22,5 @@ class BankGuarantee(Document):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_vouchar_detials(column_list, doctype, docname):
|
||||
print (column_list, doctype, docname)
|
||||
return frappe.db.sql(''' select {columns} from `tab{doctype}` where name=%s'''
|
||||
.format(columns=", ".join(json.loads(column_list)), doctype=doctype), docname, as_dict=1)[0]
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Bank Transaction', {
|
||||
onload(frm) {
|
||||
frm.set_query('payment_document', 'payment_entries', function() {
|
||||
return {
|
||||
"filters": {
|
||||
"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Expense Claim"]]
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.on('Bank Transaction Payments', {
|
||||
payment_entries_remove: function(frm, cdt, cdn) {
|
||||
update_clearance_date(frm, cdt, cdn);
|
||||
}
|
||||
});
|
||||
|
||||
const update_clearance_date = (frm, cdt, cdn) => {
|
||||
if (frm.doc.docstatus === 1) {
|
||||
frappe.xcall('erpnext.accounts.doctype.bank_transaction.bank_transaction.unclear_reference_payment',
|
||||
{doctype: cdt, docname: cdn})
|
||||
.then(e => {
|
||||
if (e == "success") {
|
||||
frappe.show_alert({message:__("Document {0} successfully uncleared", [e]), indicator:'green'});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
833
erpnext/accounts/doctype/bank_transaction/bank_transaction.json
Normal file
833
erpnext/accounts/doctype/bank_transaction/bank_transaction.json
Normal file
@@ -0,0 +1,833 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
"autoname": "naming_series:",
|
||||
"beta": 0,
|
||||
"creation": "2018-10-22 18:19:02.784533",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "ACC-BTN-.YYYY.-",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Series",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "ACC-BTN-.YYYY.-",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 1,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Pending",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "\nPending\nSettled\nUnreconciled\nReconciled",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "bank_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Bank Account",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Bank Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fetch_from": "bank_account.company",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_4",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "debit",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Debit",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "credit",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Credit",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_7",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "currency",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Currency",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_10",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Description",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_14",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "reference_number",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Reference Number",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "transaction_id",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Transaction ID",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "payment_entries",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payment Entries",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Bank Transaction Payments",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_18",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "allocated_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Allocated Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Amended From",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Bank Transaction",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_17",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "unallocated_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Unallocated Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-05-11 05:27:55.244721",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Transaction",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "date",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "bank_account",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
106
erpnext/accounts/doctype/bank_transaction/bank_transaction.py
Normal file
106
erpnext/accounts/doctype/bank_transaction/bank_transaction.py
Normal file
@@ -0,0 +1,106 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from erpnext.controllers.status_updater import StatusUpdater
|
||||
from frappe.utils import flt
|
||||
from six.moves import reduce
|
||||
from frappe import _
|
||||
|
||||
class BankTransaction(StatusUpdater):
|
||||
def after_insert(self):
|
||||
self.unallocated_amount = abs(flt(self.credit) - flt(self.debit))
|
||||
|
||||
def on_submit(self):
|
||||
self.clear_linked_payment_entries()
|
||||
self.set_status()
|
||||
|
||||
def on_update_after_submit(self):
|
||||
self.update_allocations()
|
||||
self.clear_linked_payment_entries()
|
||||
self.set_status(update=True)
|
||||
|
||||
def update_allocations(self):
|
||||
if self.payment_entries:
|
||||
allocated_amount = reduce(lambda x, y: flt(x) + flt(y), [x.allocated_amount for x in self.payment_entries])
|
||||
else:
|
||||
allocated_amount = 0
|
||||
|
||||
if allocated_amount:
|
||||
frappe.db.set_value(self.doctype, self.name, "allocated_amount", flt(allocated_amount))
|
||||
frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit)) - flt(allocated_amount))
|
||||
|
||||
else:
|
||||
frappe.db.set_value(self.doctype, self.name, "allocated_amount", 0)
|
||||
frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit)))
|
||||
|
||||
amount = self.debit or self.credit
|
||||
if amount == self.allocated_amount:
|
||||
frappe.db.set_value(self.doctype, self.name, "status", "Reconciled")
|
||||
|
||||
self.reload()
|
||||
|
||||
def clear_linked_payment_entries(self):
|
||||
for payment_entry in self.payment_entries:
|
||||
allocated_amount = get_total_allocated_amount(payment_entry)
|
||||
paid_amount = get_paid_amount(payment_entry)
|
||||
|
||||
if paid_amount and allocated_amount:
|
||||
if flt(allocated_amount[0]["allocated_amount"]) > flt(paid_amount):
|
||||
frappe.throw(_("The total allocated amount ({0}) is greated than the paid amount ({1}).".format(flt(allocated_amount[0]["allocated_amount"]), flt(paid_amount))))
|
||||
elif flt(allocated_amount[0]["allocated_amount"]) == flt(paid_amount):
|
||||
if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
|
||||
self.clear_simple_entry(payment_entry)
|
||||
|
||||
elif payment_entry.payment_document == "Sales Invoice":
|
||||
self.clear_sales_invoice(payment_entry)
|
||||
|
||||
def clear_simple_entry(self, payment_entry):
|
||||
frappe.db.set_value(payment_entry.payment_document, payment_entry.payment_entry, "clearance_date", self.date)
|
||||
|
||||
def clear_sales_invoice(self, payment_entry):
|
||||
frappe.db.set_value("Sales Invoice Payment", dict(parenttype=payment_entry.payment_document,
|
||||
parent=payment_entry.payment_entry), "clearance_date", self.date)
|
||||
|
||||
def get_total_allocated_amount(payment_entry):
|
||||
return frappe.db.sql("""
|
||||
SELECT
|
||||
SUM(btp.allocated_amount) as allocated_amount,
|
||||
bt.name
|
||||
FROM
|
||||
`tabBank Transaction Payments` as btp
|
||||
LEFT JOIN
|
||||
`tabBank Transaction` bt ON bt.name=btp.parent
|
||||
WHERE
|
||||
btp.payment_document = %s
|
||||
AND
|
||||
btp.payment_entry = %s
|
||||
AND
|
||||
bt.docstatus = 1""", (payment_entry.payment_document, payment_entry.payment_entry), as_dict=True)
|
||||
|
||||
def get_paid_amount(payment_entry):
|
||||
if payment_entry.payment_document in ["Payment Entry", "Sales Invoice", "Purchase Invoice"]:
|
||||
return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "paid_amount")
|
||||
|
||||
elif payment_entry.payment_document == "Journal Entry":
|
||||
return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "total_credit")
|
||||
|
||||
elif payment_entry.payment_document == "Expense Claim":
|
||||
return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "total_amount_reimbursed")
|
||||
|
||||
else:
|
||||
frappe.throw("Please reconcile {0}: {1} manually".format(payment_entry.payment_document, payment_entry.payment_entry))
|
||||
|
||||
@frappe.whitelist()
|
||||
def unclear_reference_payment(doctype, docname):
|
||||
if frappe.db.exists(doctype, docname):
|
||||
doc = frappe.get_doc(doctype, docname)
|
||||
if doctype == "Sales Invoice":
|
||||
frappe.db.set_value("Sales Invoice Payment", dict(parenttype=doc.payment_document,
|
||||
parent=doc.payment_entry), "clearance_date", None)
|
||||
else:
|
||||
frappe.db.set_value(doc.payment_document, doc.payment_entry, "clearance_date", None)
|
||||
|
||||
return doc.payment_entry
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
frappe.listview_settings['Bank Transaction'] = {
|
||||
add_fields: ["unallocated_amount"],
|
||||
get_indicator: function(doc) {
|
||||
if(flt(doc.unallocated_amount)>0) {
|
||||
return [__("Unreconciled"), "orange", "unallocated_amount,>,0"];
|
||||
} else if(flt(doc.unallocated_amount)<=0) {
|
||||
return [__("Reconciled"), "green", "unallocated_amount,=,0"];
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import json
|
||||
from frappe.utils import getdate
|
||||
from frappe.utils.dateutils import parse_date
|
||||
from six import iteritems
|
||||
|
||||
@frappe.whitelist()
|
||||
def upload_bank_statement():
|
||||
if getattr(frappe, "uploaded_file", None):
|
||||
with open(frappe.uploaded_file, "rb") as upfile:
|
||||
fcontent = upfile.read()
|
||||
else:
|
||||
from frappe.utils.file_manager import get_uploaded_content
|
||||
fname, fcontent = get_uploaded_content()
|
||||
|
||||
if frappe.safe_encode(fname).lower().endswith("csv".encode('utf-8')):
|
||||
from frappe.utils.csvutils import read_csv_content
|
||||
rows = read_csv_content(fcontent, False)
|
||||
|
||||
elif frappe.safe_encode(fname).lower().endswith("xlsx".encode('utf-8')):
|
||||
from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file
|
||||
rows = read_xlsx_file_from_attached_file(fcontent=fcontent)
|
||||
|
||||
columns = rows[0]
|
||||
rows.pop(0)
|
||||
data = rows
|
||||
return {"columns": columns, "data": data}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_bank_entries(columns, data, bank_account):
|
||||
header_map = get_header_mapping(columns, bank_account)
|
||||
|
||||
success = 0
|
||||
errors = 0
|
||||
for d in json.loads(data):
|
||||
if all(item is None for item in d) is True:
|
||||
continue
|
||||
fields = {}
|
||||
for key, value in iteritems(header_map):
|
||||
fields.update({key: d[int(value)-1]})
|
||||
|
||||
try:
|
||||
bank_transaction = frappe.get_doc({
|
||||
"doctype": "Bank Transaction"
|
||||
})
|
||||
bank_transaction.update(fields)
|
||||
bank_transaction.date = getdate(parse_date(bank_transaction.date))
|
||||
bank_transaction.bank_account = bank_account
|
||||
bank_transaction.insert()
|
||||
bank_transaction.submit()
|
||||
success += 1
|
||||
except Exception:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
errors += 1
|
||||
|
||||
return {"success": success, "errors": errors}
|
||||
|
||||
def get_header_mapping(columns, bank_account):
|
||||
mapping = get_bank_mapping(bank_account)
|
||||
|
||||
header_map = {}
|
||||
for column in json.loads(columns):
|
||||
if column["content"] in mapping:
|
||||
header_map.update({mapping[column["content"]]: column["colIndex"]})
|
||||
|
||||
return header_map
|
||||
|
||||
def get_bank_mapping(bank_account):
|
||||
bank_name = frappe.db.get_value("Bank Account", bank_account, "bank")
|
||||
bank = frappe.get_doc("Bank", bank_name)
|
||||
|
||||
mapping = {row.file_field:row.bank_transaction_field for row in bank.bank_transaction_mapping}
|
||||
|
||||
return mapping
|
||||
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Bank Transaction", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Bank Transaction
|
||||
() => frappe.tests.make('Bank Transaction', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
||||
@@ -0,0 +1,286 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
|
||||
from erpnext.accounts.page.bank_reconciliation.bank_reconciliation import reconcile, get_linked_payments
|
||||
|
||||
test_dependencies = ["Item", "Cost Center"]
|
||||
|
||||
class TestBankTransaction(unittest.TestCase):
|
||||
def setUp(self):
|
||||
add_transactions()
|
||||
add_payments()
|
||||
|
||||
def tearDown(self):
|
||||
for bt in frappe.get_all("Bank Transaction"):
|
||||
doc = frappe.get_doc("Bank Transaction", bt.name)
|
||||
doc.cancel()
|
||||
doc.delete()
|
||||
|
||||
# Delete directly in DB to avoid validation errors for countries not allowing deletion
|
||||
frappe.db.sql("""delete from `tabPayment Entry Reference`""")
|
||||
frappe.db.sql("""delete from `tabPayment Entry`""")
|
||||
|
||||
frappe.flags.test_bank_transactions_created = False
|
||||
frappe.flags.test_payments_created = False
|
||||
|
||||
# This test checks if ERPNext is able to provide a linked payment for a bank transaction based on the amount of the bank transaction.
|
||||
def test_linked_payments(self):
|
||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic"))
|
||||
linked_payments = get_linked_payments(bank_transaction.name)
|
||||
self.assertTrue(linked_payments[0].party == "Conrad Electronic")
|
||||
|
||||
# This test validates a simple reconciliation leading to the clearance of the bank transaction and the payment
|
||||
def test_reconcile(self):
|
||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
|
||||
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
|
||||
reconcile(bank_transaction.name, "Payment Entry", payment.name)
|
||||
|
||||
unallocated_amount = frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount")
|
||||
self.assertTrue(unallocated_amount == 0)
|
||||
|
||||
clearance_date = frappe.db.get_value("Payment Entry", payment.name, "clearance_date")
|
||||
self.assertTrue(clearance_date is not None)
|
||||
|
||||
# Check if ERPNext can correctly fetch a linked payment based on the party
|
||||
def test_linked_payments_based_on_party(self):
|
||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G"))
|
||||
linked_payments = get_linked_payments(bank_transaction.name)
|
||||
self.assertTrue(len(linked_payments)==1)
|
||||
|
||||
# Check if ERPNext can correctly filter a linked payments based on the debit/credit amount
|
||||
def test_debit_credit_output(self):
|
||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"))
|
||||
linked_payments = get_linked_payments(bank_transaction.name)
|
||||
self.assertTrue(linked_payments[0].payment_type == "Pay")
|
||||
|
||||
# Check error if already reconciled
|
||||
def test_already_reconciled(self):
|
||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
|
||||
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
|
||||
reconcile(bank_transaction.name, "Payment Entry", payment.name)
|
||||
|
||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
|
||||
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
|
||||
self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
|
||||
|
||||
# Raise an error if creditor transaction vs creditor payment
|
||||
def test_invalid_creditor_reconcilation(self):
|
||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio"))
|
||||
payment = frappe.get_doc("Payment Entry", dict(party="Conrad Electronic", paid_amount=690))
|
||||
self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
|
||||
|
||||
# Raise an error if debitor transaction vs debitor payment
|
||||
def test_invalid_debitor_reconcilation(self):
|
||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"))
|
||||
payment = frappe.get_doc("Payment Entry", dict(party="Fayva", paid_amount=109080))
|
||||
self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
|
||||
|
||||
# Raise an error if debitor transaction vs debitor payment
|
||||
def test_clear_sales_invoice(self):
|
||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio"))
|
||||
payment = frappe.get_doc("Sales Invoice", dict(customer="Fayva", status=["=", "Paid"]))
|
||||
reconcile(bank_transaction.name, "Sales Invoice", payment.name)
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount"), 0)
|
||||
self.assertTrue(frappe.db.get_value("Sales Invoice Payment", dict(parent=payment.name), "clearance_date") is not None)
|
||||
|
||||
def add_transactions():
|
||||
if frappe.flags.test_bank_transactions_created:
|
||||
return
|
||||
|
||||
frappe.set_user("Administrator")
|
||||
try:
|
||||
frappe.get_doc({
|
||||
"doctype": "Bank",
|
||||
"bank_name":"Citi Bank",
|
||||
}).insert()
|
||||
except frappe.DuplicateEntryError:
|
||||
pass
|
||||
|
||||
try:
|
||||
frappe.get_doc({
|
||||
"doctype": "Bank Account",
|
||||
"account_name":"Checking Account",
|
||||
"bank": "Citi Bank",
|
||||
"account": "_Test Bank - _TC"
|
||||
}).insert()
|
||||
except frappe.DuplicateEntryError:
|
||||
pass
|
||||
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "Bank Transaction",
|
||||
"description":"1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G",
|
||||
"date": "2018-10-23",
|
||||
"debit": 1200,
|
||||
"currency": "INR",
|
||||
"bank_account": "Checking Account - Citi Bank"
|
||||
}).insert()
|
||||
doc.submit()
|
||||
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "Bank Transaction",
|
||||
"description":"1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G",
|
||||
"date": "2018-10-23",
|
||||
"debit": 1700,
|
||||
"currency": "INR",
|
||||
"bank_account": "Checking Account - Citi Bank"
|
||||
}).insert()
|
||||
doc.submit()
|
||||
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "Bank Transaction",
|
||||
"description":"Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic",
|
||||
"date": "2018-10-26",
|
||||
"debit": 690,
|
||||
"currency": "INR",
|
||||
"bank_account": "Checking Account - Citi Bank"
|
||||
}).insert()
|
||||
doc.submit()
|
||||
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "Bank Transaction",
|
||||
"description":"Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07",
|
||||
"date": "2018-10-27",
|
||||
"debit": 3900,
|
||||
"currency": "INR",
|
||||
"bank_account": "Checking Account - Citi Bank"
|
||||
}).insert()
|
||||
doc.submit()
|
||||
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "Bank Transaction",
|
||||
"description":"I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio",
|
||||
"date": "2018-10-27",
|
||||
"credit": 109080,
|
||||
"currency": "INR",
|
||||
"bank_account": "Checking Account - Citi Bank"
|
||||
}).insert()
|
||||
doc.submit()
|
||||
|
||||
frappe.flags.test_bank_transactions_created = True
|
||||
|
||||
def add_payments():
|
||||
if frappe.flags.test_payments_created:
|
||||
return
|
||||
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
try:
|
||||
frappe.get_doc({
|
||||
"doctype": "Supplier",
|
||||
"supplier_group":"All Supplier Groups",
|
||||
"supplier_type": "Company",
|
||||
"supplier_name": "Conrad Electronic"
|
||||
}).insert()
|
||||
|
||||
except frappe.DuplicateEntryError:
|
||||
pass
|
||||
|
||||
pi = make_purchase_invoice(supplier="Conrad Electronic", qty=1, rate=690)
|
||||
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
|
||||
pe.reference_no = "Conrad Oct 18"
|
||||
pe.reference_date = "2018-10-24"
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
try:
|
||||
frappe.get_doc({
|
||||
"doctype": "Supplier",
|
||||
"supplier_group":"All Supplier Groups",
|
||||
"supplier_type": "Company",
|
||||
"supplier_name": "Mr G"
|
||||
}).insert()
|
||||
except frappe.DuplicateEntryError:
|
||||
pass
|
||||
|
||||
pi = make_purchase_invoice(supplier="Mr G", qty=1, rate=1200)
|
||||
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
|
||||
pe.reference_no = "Herr G Oct 18"
|
||||
pe.reference_date = "2018-10-24"
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
pi = make_purchase_invoice(supplier="Mr G", qty=1, rate=1700)
|
||||
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
|
||||
pe.reference_no = "Herr G Nov 18"
|
||||
pe.reference_date = "2018-11-01"
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
try:
|
||||
frappe.get_doc({
|
||||
"doctype": "Supplier",
|
||||
"supplier_group":"All Supplier Groups",
|
||||
"supplier_type": "Company",
|
||||
"supplier_name": "Poore Simon's"
|
||||
}).insert()
|
||||
except frappe.DuplicateEntryError:
|
||||
pass
|
||||
|
||||
try:
|
||||
frappe.get_doc({
|
||||
"doctype": "Customer",
|
||||
"customer_group":"All Customer Groups",
|
||||
"customer_type": "Company",
|
||||
"customer_name": "Poore Simon's"
|
||||
}).insert()
|
||||
except frappe.DuplicateEntryError:
|
||||
pass
|
||||
|
||||
pi = make_purchase_invoice(supplier="Poore Simon's", qty=1, rate=3900)
|
||||
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
|
||||
pe.reference_no = "Poore Simon's Oct 18"
|
||||
pe.reference_date = "2018-10-28"
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
si = create_sales_invoice(customer="Poore Simon's", qty=1, rate=3900)
|
||||
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC")
|
||||
pe.reference_no = "Poore Simon's Oct 18"
|
||||
pe.reference_date = "2018-10-28"
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
try:
|
||||
frappe.get_doc({
|
||||
"doctype": "Customer",
|
||||
"customer_group":"All Customer Groups",
|
||||
"customer_type": "Company",
|
||||
"customer_name": "Fayva"
|
||||
}).insert()
|
||||
except frappe.DuplicateEntryError:
|
||||
pass
|
||||
|
||||
si = create_sales_invoice(customer="Fayva", qty=1, rate=109080)
|
||||
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC")
|
||||
pe.reference_no = "Fayva Oct 18"
|
||||
pe.reference_date = "2018-10-29"
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
company = frappe.db.get_single_value('Global Defaults', 'default_company')
|
||||
frappe.get_doc({
|
||||
"doctype": "Mode of Payment",
|
||||
"name": "Cash"
|
||||
}).append("accounts", {
|
||||
"company": company,
|
||||
"default_account": "_Test Bank - _TC"
|
||||
}).save()
|
||||
si = create_sales_invoice(customer="Fayva", qty=1, rate=109080, do_not_submit=1)
|
||||
si.is_pos = 1
|
||||
si.append("payments", {
|
||||
"mode_of_payment": "Cash",
|
||||
"account": "_Test Bank - _TC",
|
||||
"amount": 109080
|
||||
})
|
||||
si.save()
|
||||
si.submit()
|
||||
|
||||
frappe.flags.test_payments_created = True
|
||||
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2018-10-24 15:24:56.713277",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "bank_transaction_field",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Field in Bank Transaction",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "file_field",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Column in Bank File",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-10-24 15:24:56.713277",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Transaction Mapping",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class BankTransactionMapping(Document):
|
||||
pass
|
||||
@@ -0,0 +1,141 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2018-11-28 08:55:40.815355",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "payment_document",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payment Document",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "DocType",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "payment_entry",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payment Entry",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "payment_document",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "allocated_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Allocated Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-12-06 10:57:02.635141",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Transaction Payments",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class BankTransactionPayments(Document):
|
||||
pass
|
||||
@@ -160,7 +160,7 @@ class PaymentEntry(AccountsController):
|
||||
d.reference_name, self.party_account_currency)
|
||||
|
||||
for field, value in iteritems(ref_details):
|
||||
if not d.get(field) or force:
|
||||
if field == 'exchange_rate' or not d.get(field) or force:
|
||||
d.set(field, value)
|
||||
|
||||
def validate_payment_type(self):
|
||||
@@ -536,9 +536,13 @@ class PaymentEntry(AccountsController):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_outstanding_reference_documents(args):
|
||||
|
||||
if isinstance(args, string_types):
|
||||
args = json.loads(args)
|
||||
|
||||
if args.get('party_type') == 'Member':
|
||||
return
|
||||
|
||||
# confirm that Supplier is not blocked
|
||||
if args.get('party_type') == 'Supplier':
|
||||
supplier_status = get_supplier_block_status(args['party'])
|
||||
|
||||
@@ -13,20 +13,20 @@ class PaymentReconciliation(Document):
|
||||
def get_unreconciled_entries(self):
|
||||
self.get_nonreconciled_payment_entries()
|
||||
self.get_invoice_entries()
|
||||
|
||||
|
||||
def get_nonreconciled_payment_entries(self):
|
||||
self.check_mandatory_to_fetch()
|
||||
|
||||
|
||||
payment_entries = self.get_payment_entries()
|
||||
journal_entries = self.get_jv_entries()
|
||||
|
||||
|
||||
self.add_payment_entries(payment_entries + journal_entries)
|
||||
|
||||
|
||||
def get_payment_entries(self):
|
||||
order_doctype = "Sales Order" if self.party_type=="Customer" else "Purchase Order"
|
||||
payment_entries = get_advance_payment_entries(self.party_type, self.party,
|
||||
payment_entries = get_advance_payment_entries(self.party_type, self.party,
|
||||
self.receivable_payable_account, order_doctype, against_all_orders=True, limit=self.limit)
|
||||
|
||||
|
||||
return payment_entries
|
||||
|
||||
def get_jv_entries(self):
|
||||
@@ -36,12 +36,12 @@ class PaymentReconciliation(Document):
|
||||
bank_account_condition = "t2.against_account like %(bank_cash_account)s" \
|
||||
if self.bank_cash_account else "1=1"
|
||||
|
||||
limit_cond = "limit %s" % (self.limit or 1000)
|
||||
limit_cond = "limit %s" % self.limit if self.limit else ""
|
||||
|
||||
journal_entries = frappe.db.sql("""
|
||||
select
|
||||
"Journal Entry" as reference_type, t1.name as reference_name,
|
||||
t1.posting_date, t1.remark as remarks, t2.name as reference_row,
|
||||
"Journal Entry" as reference_type, t1.name as reference_name,
|
||||
t1.posting_date, t1.remark as remarks, t2.name as reference_row,
|
||||
{dr_or_cr} as amount, t2.is_advance
|
||||
from
|
||||
`tabJournal Entry` t1, `tabJournal Entry Account` t2
|
||||
@@ -49,8 +49,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 (t2.reference_type is null or t2.reference_type = '' or
|
||||
(t2.reference_type in ('Sales Order', 'Purchase Order')
|
||||
and (t2.reference_type is null or t2.reference_type = '' or
|
||||
(t2.reference_type in ('Sales Order', 'Purchase Order')
|
||||
and t2.reference_name is not null and t2.reference_name != ''))
|
||||
and (CASE
|
||||
WHEN t1.voucher_type in ('Debit Note', 'Credit Note')
|
||||
@@ -83,7 +83,10 @@ class PaymentReconciliation(Document):
|
||||
condition = self.check_condition()
|
||||
|
||||
non_reconciled_invoices = get_outstanding_invoices(self.party_type, self.party,
|
||||
self.receivable_payable_account, condition=condition, limit=self.limit)
|
||||
self.receivable_payable_account, condition=condition)
|
||||
|
||||
if self.limit:
|
||||
non_reconciled_invoices = non_reconciled_invoices[:self.limit]
|
||||
|
||||
self.add_invoice_entries(non_reconciled_invoices)
|
||||
|
||||
@@ -109,7 +112,7 @@ class PaymentReconciliation(Document):
|
||||
self.validate_invoice()
|
||||
dr_or_cr = ("credit_in_account_currency"
|
||||
if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit_in_account_currency")
|
||||
|
||||
|
||||
lst = []
|
||||
for e in self.get('payments'):
|
||||
if e.invoice_number and e.allocated_amount:
|
||||
@@ -127,11 +130,11 @@ class PaymentReconciliation(Document):
|
||||
'unadjusted_amount' : flt(e.amount),
|
||||
'allocated_amount' : flt(e.allocated_amount)
|
||||
}))
|
||||
|
||||
|
||||
if lst:
|
||||
from erpnext.accounts.utils import reconcile_against_document
|
||||
reconcile_against_document(lst)
|
||||
|
||||
|
||||
msgprint(_("Successfully Reconciled"))
|
||||
self.get_unreconciled_entries()
|
||||
|
||||
|
||||
@@ -167,7 +167,12 @@ def get_pricing_rule_for_item(args):
|
||||
|
||||
if args.transaction_type=="selling":
|
||||
if args.customer and not (args.customer_group and args.territory):
|
||||
customer = frappe.get_cached_value("Customer", args.customer, ["customer_group", "territory"])
|
||||
|
||||
if args.quotation_to and args.quotation_to != 'Customer':
|
||||
customer = frappe._dict()
|
||||
else:
|
||||
customer = frappe.get_cached_value("Customer", args.customer, ["customer_group", "territory"])
|
||||
|
||||
if customer:
|
||||
args.customer_group, args.territory = customer
|
||||
|
||||
|
||||
@@ -285,6 +285,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
is_paid: function() {
|
||||
hide_fields(this.frm.doc);
|
||||
if(cint(this.frm.doc.is_paid)) {
|
||||
this.frm.set_value("allocate_advances_automatically", 0);
|
||||
if(!this.frm.doc.company) {
|
||||
this.frm.set_value("is_paid", 0)
|
||||
frappe.msgprint(__("Please specify Company to proceed"));
|
||||
@@ -522,8 +523,13 @@ frappe.ui.form.on("Purchase Invoice", {
|
||||
},
|
||||
|
||||
onload: function(frm) {
|
||||
if(frm.doc.__onload && !frm.doc.__onload.supplier_tds) {
|
||||
me.frm.set_df_property("apply_tds", "read_only", 1);
|
||||
if(frm.doc.__onload) {
|
||||
if(frm.doc.supplier) {
|
||||
frm.doc.apply_tds = frm.doc.__onload.supplier_tds ? 1 : 0;
|
||||
}
|
||||
if(!frm.doc.__onload.supplier_tds) {
|
||||
frm.set_df_property("apply_tds", "read_only", 1);
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -100,6 +100,7 @@ class PurchaseInvoice(BuyingController):
|
||||
self.validate_fixed_asset()
|
||||
self.create_remarks()
|
||||
self.set_status()
|
||||
self.validate_purchase_receipt_if_update_stock()
|
||||
validate_inter_company_party(self.doctype, self.supplier, self.company, self.inter_company_invoice_reference)
|
||||
|
||||
def validate_release_date(self):
|
||||
@@ -284,7 +285,7 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
def update_status_updater_args(self):
|
||||
if cint(self.update_stock):
|
||||
self.status_updater.extend([{
|
||||
self.status_updater.append({
|
||||
'source_dt': 'Purchase Invoice Item',
|
||||
'target_dt': 'Purchase Order Item',
|
||||
'join_field': 'po_detail',
|
||||
@@ -292,28 +293,29 @@ class PurchaseInvoice(BuyingController):
|
||||
'target_parent_dt': 'Purchase Order',
|
||||
'target_parent_field': 'per_received',
|
||||
'target_ref_field': 'qty',
|
||||
'source_field': 'qty',
|
||||
'source_field': 'received_qty',
|
||||
'second_source_dt': 'Purchase Receipt Item',
|
||||
'second_source_field': 'received_qty',
|
||||
'second_join_field': 'purchase_order_item',
|
||||
'percent_join_field':'purchase_order',
|
||||
# 'percent_join_field': 'prevdoc_docname',
|
||||
'overflow_type': 'receipt',
|
||||
'extra_cond': """ and exists(select name from `tabPurchase Invoice`
|
||||
where name=`tabPurchase Invoice Item`.parent and update_stock = 1)"""
|
||||
},
|
||||
{
|
||||
'source_dt': 'Purchase Invoice Item',
|
||||
'target_dt': 'Purchase Order Item',
|
||||
'join_field': 'po_detail',
|
||||
'target_field': 'returned_qty',
|
||||
'target_parent_dt': 'Purchase Order',
|
||||
# 'target_parent_field': 'per_received',
|
||||
# 'target_ref_field': 'qty',
|
||||
'source_field': '-1 * qty',
|
||||
# 'percent_join_field': 'prevdoc_docname',
|
||||
# 'overflow_type': 'receipt',
|
||||
'extra_cond': """ and exists (select name from `tabPurchase Invoice`
|
||||
where name=`tabPurchase Invoice Item`.parent and update_stock=1 and is_return=1)"""
|
||||
}
|
||||
])
|
||||
})
|
||||
if cint(self.is_return):
|
||||
self.status_updater.append({
|
||||
'source_dt': 'Purchase Invoice Item',
|
||||
'target_dt': 'Purchase Order Item',
|
||||
'join_field': 'po_detail',
|
||||
'target_field': 'returned_qty',
|
||||
'source_field': '-1 * qty',
|
||||
'second_source_dt': 'Purchase Receipt Item',
|
||||
'second_source_field': '-1 * qty',
|
||||
'second_join_field': 'purchase_order_item',
|
||||
'overflow_type': 'receipt',
|
||||
'extra_cond': """ and exists (select name from `tabPurchase Invoice`
|
||||
where name=`tabPurchase Invoice Item`.parent and update_stock=1 and is_return=1)"""
|
||||
})
|
||||
|
||||
def validate_purchase_receipt_if_update_stock(self):
|
||||
if self.update_stock:
|
||||
@@ -327,13 +329,13 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
self.check_prev_docstatus()
|
||||
self.update_status_updater_args()
|
||||
self.update_prevdoc_status()
|
||||
|
||||
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
||||
self.company, self.base_grand_total)
|
||||
|
||||
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_billing_status_in_pr()
|
||||
|
||||
@@ -763,13 +765,13 @@ class PurchaseInvoice(BuyingController):
|
||||
self.check_for_closed_status()
|
||||
|
||||
self.update_status_updater_args()
|
||||
self.update_prevdoc_status()
|
||||
|
||||
if not self.is_return:
|
||||
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
|
||||
if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
|
||||
unlink_ref_doc_from_payment_entries(self)
|
||||
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
self.update_billing_status_in_pr()
|
||||
|
||||
@@ -789,9 +791,8 @@ class PurchaseInvoice(BuyingController):
|
||||
for d in self.items:
|
||||
if d.project and d.project not in project_list:
|
||||
project = frappe.get_doc("Project", d.project)
|
||||
project.flags.dont_sync_tasks = True
|
||||
project.update_purchase_costing()
|
||||
project.save()
|
||||
project.db_update()
|
||||
project_list.append(d.project)
|
||||
|
||||
def validate_supplier_invoice(self):
|
||||
|
||||
@@ -6,8 +6,8 @@ frappe.listview_settings['Purchase Invoice'] = {
|
||||
add_fields: ["supplier", "supplier_name", "base_grand_total", "outstanding_amount", "due_date", "company",
|
||||
"currency", "is_return", "release_date", "on_hold"],
|
||||
get_indicator: function(doc) {
|
||||
if(cint(doc.is_return)==1) {
|
||||
return [__("Return"), "darkgrey", "is_return,=,Yes"];
|
||||
if(flt(doc.outstanding_amount) < 0 && doc.docstatus == 1) {
|
||||
return [__("Debit Note Issued"), "darkgrey", "outstanding_amount,<,0"]
|
||||
} else if(flt(doc.outstanding_amount) > 0 && doc.docstatus==1) {
|
||||
if(cint(doc.on_hold) && !doc.release_date) {
|
||||
return [__("On Hold"), "darkgrey"];
|
||||
@@ -18,9 +18,9 @@ frappe.listview_settings['Purchase Invoice'] = {
|
||||
} else {
|
||||
return [__("Unpaid"), "orange", "outstanding_amount,>,0|due,>=,Today"];
|
||||
}
|
||||
} else if(flt(doc.outstanding_amount) < 0 && doc.docstatus == 1) {
|
||||
return [__("Debit Note Issued"), "darkgrey", "outstanding_amount,<,0"]
|
||||
}else if(flt(doc.outstanding_amount)==0 && doc.docstatus==1) {
|
||||
} else if(cint(doc.is_return)) {
|
||||
return [__("Return"), "darkgrey", "is_return,=,Yes"];
|
||||
} else if(flt(doc.outstanding_amount)==0 && doc.docstatus==1) {
|
||||
return [__("Paid"), "green", "outstanding_amount,=,0"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,9 +402,9 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
|
||||
pi.save()
|
||||
pi.submit()
|
||||
self.assertEqual(pi.payment_schedule[0].payment_amount, 756.15)
|
||||
self.assertEqual(pi.payment_schedule[0].payment_amount, 606.15)
|
||||
self.assertEqual(pi.payment_schedule[0].due_date, pi.posting_date)
|
||||
self.assertEqual(pi.payment_schedule[1].payment_amount, 756.15)
|
||||
self.assertEqual(pi.payment_schedule[1].payment_amount, 606.15)
|
||||
self.assertEqual(pi.payment_schedule[1].due_date, add_days(pi.posting_date, 30))
|
||||
|
||||
pi.load_from_db()
|
||||
|
||||
38
erpnext/accounts/doctype/sales_invoice/regional/india.js
Normal file
38
erpnext/accounts/doctype/sales_invoice/regional/india.js
Normal file
@@ -0,0 +1,38 @@
|
||||
frappe.ui.form.on("Sales Invoice", {
|
||||
setup: function(frm) {
|
||||
frm.set_query('transporter', function() {
|
||||
return {
|
||||
filters: {
|
||||
'is_transporter': 1
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query('driver', function(doc) {
|
||||
return {
|
||||
filters: {
|
||||
'transporter': doc.transporter
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
if(frm.doc.docstatus == 1 && !frm.is_dirty()
|
||||
&& !frm.doc.is_return && !frm.doc.ewaybill) {
|
||||
|
||||
frm.add_custom_button('Generate e-Way Bill JSON', () => {
|
||||
var w = window.open(
|
||||
frappe.urllib.get_full_url(
|
||||
"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
|
||||
+ "dt=" + encodeURIComponent(frm.doc.doctype)
|
||||
+ "&dn=" + encodeURIComponent(frm.doc.name)
|
||||
)
|
||||
);
|
||||
if (!w) {
|
||||
frappe.msgprint(__("Please enable pop-ups")); return;
|
||||
}
|
||||
}, __("Make"));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
var globalOnload = frappe.listview_settings['Sales Invoice'].onload;
|
||||
frappe.listview_settings['Sales Invoice'].onload = function (doclist) {
|
||||
|
||||
// Provision in case onload event is added to sales_invoice.js in future
|
||||
if (globalOnload) {
|
||||
globalOnload(doclist);
|
||||
}
|
||||
|
||||
const action = () => {
|
||||
const selected_docs = doclist.get_checked_items();
|
||||
const docnames = doclist.get_checked_items(true);
|
||||
|
||||
for (let doc of selected_docs) {
|
||||
if (doc.docstatus !== 1) {
|
||||
frappe.throw(__("e-Way Bill JSON can only be generated from a submitted document"));
|
||||
}
|
||||
}
|
||||
|
||||
var w = window.open(
|
||||
frappe.urllib.get_full_url(
|
||||
"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
|
||||
+ "dt=" + encodeURIComponent(doclist.doctype)
|
||||
+ "&dn=" + encodeURIComponent(docnames)
|
||||
)
|
||||
);
|
||||
if (!w) {
|
||||
frappe.msgprint(__("Please enable pop-ups")); return;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
doclist.page.add_actions_menu_item(__('Generate e-Way Bill JSON'), action, false);
|
||||
};
|
||||
@@ -356,6 +356,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
|
||||
set_pos_data: function() {
|
||||
if(this.frm.doc.is_pos) {
|
||||
this.frm.set_value("allocate_advances_automatically", 0);
|
||||
if(!this.frm.doc.company) {
|
||||
this.frm.set_value("is_pos", 0);
|
||||
frappe.msgprint(__("Please specify Company to proceed"));
|
||||
|
||||
@@ -3630,7 +3630,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "1",
|
||||
"default": "",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "allocate_advances_automatically",
|
||||
"fieldtype": "Check",
|
||||
@@ -5816,7 +5816,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2019-04-10 16:10:34.266458",
|
||||
"modified": "2019-04-22 12:45:41.109345",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
||||
@@ -54,8 +54,8 @@ class SalesInvoice(SellingController):
|
||||
|
||||
def set_indicator(self):
|
||||
"""Set indicator for portal"""
|
||||
if cint(self.is_return) == 1:
|
||||
self.indicator_title = _("Return")
|
||||
if self.outstanding_amount < 0:
|
||||
self.indicator_title = _("Credit Note Issued")
|
||||
self.indicator_color = "darkgrey"
|
||||
elif self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()):
|
||||
self.indicator_color = "orange"
|
||||
@@ -63,8 +63,8 @@ class SalesInvoice(SellingController):
|
||||
elif self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()):
|
||||
self.indicator_color = "red"
|
||||
self.indicator_title = _("Overdue")
|
||||
elif self.outstanding_amount < 0:
|
||||
self.indicator_title = _("Credit Note Issued")
|
||||
elif cint(self.is_return) == 1:
|
||||
self.indicator_title = _("Return")
|
||||
self.indicator_color = "darkgrey"
|
||||
else:
|
||||
self.indicator_color = "green"
|
||||
@@ -256,7 +256,7 @@ class SalesInvoice(SellingController):
|
||||
|
||||
def update_status_updater_args(self):
|
||||
if cint(self.update_stock):
|
||||
self.status_updater.extend([{
|
||||
self.status_updater.append({
|
||||
'source_dt':'Sales Invoice Item',
|
||||
'target_dt':'Sales Order Item',
|
||||
'target_parent_dt':'Sales Order',
|
||||
@@ -274,21 +274,20 @@ class SalesInvoice(SellingController):
|
||||
'overflow_type': 'delivery',
|
||||
'extra_cond': """ and exists(select name from `tabSales Invoice`
|
||||
where name=`tabSales Invoice Item`.parent and update_stock = 1)"""
|
||||
},
|
||||
{
|
||||
'source_dt': 'Sales Invoice Item',
|
||||
'target_dt': 'Sales Order Item',
|
||||
'join_field': 'so_detail',
|
||||
'target_field': 'returned_qty',
|
||||
'target_parent_dt': 'Sales Order',
|
||||
# 'target_parent_field': 'per_delivered',
|
||||
# 'target_ref_field': 'qty',
|
||||
'source_field': '-1 * qty',
|
||||
# 'percent_join_field': 'sales_order',
|
||||
# 'overflow_type': 'delivery',
|
||||
'extra_cond': """ and exists (select name from `tabSales Invoice` where name=`tabSales Invoice Item`.parent and update_stock=1 and is_return=1)"""
|
||||
}
|
||||
])
|
||||
})
|
||||
if cint(self.is_return):
|
||||
self.status_updater.append({
|
||||
'source_dt': 'Sales Invoice Item',
|
||||
'target_dt': 'Sales Order Item',
|
||||
'join_field': 'so_detail',
|
||||
'target_field': 'returned_qty',
|
||||
'target_parent_dt': 'Sales Order',
|
||||
'source_field': '-1 * qty',
|
||||
'second_source_dt': 'Delivery Note Item',
|
||||
'second_source_field': '-1 * qty',
|
||||
'second_join_field': 'so_detail',
|
||||
'extra_cond': """ and exists (select name from `tabSales Invoice` where name=`tabSales Invoice Item`.parent and update_stock=1 and is_return=1)"""
|
||||
})
|
||||
|
||||
def check_credit_limit(self):
|
||||
from erpnext.selling.doctype.customer.customer import check_credit_limit
|
||||
@@ -504,12 +503,15 @@ 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', 'is_pos'],'Delivery Note':['dn_required', 'update_stock']}
|
||||
for i in dic:
|
||||
if frappe.db.get_single_value('Selling Settings', dic[i][0]) == 'Yes':
|
||||
for d in self.get('items'):
|
||||
if frappe.get_cached_value('Item', d.item_code, 'is_stock_item') == 1 \
|
||||
and not d.get(i.lower().replace(' ','_')) and not self.get(dic[i][1]):
|
||||
is_stock_item = frappe.get_cached_value('Item', d.item_code, 'is_stock_item')
|
||||
if (d.item_code and is_stock_item == 1\
|
||||
and not d.get(i.lower().replace(' ','_')) and not self.get(dic[i][1])):
|
||||
msgprint(_("{0} is mandatory for Item {1}").format(i,d.item_code), raise_exception=1)
|
||||
|
||||
|
||||
@@ -1022,9 +1024,8 @@ class SalesInvoice(SellingController):
|
||||
def update_project(self):
|
||||
if self.project:
|
||||
project = frappe.get_doc("Project", self.project)
|
||||
project.flags.dont_sync_tasks = True
|
||||
project.update_billed_amount()
|
||||
project.save()
|
||||
project.db_update()
|
||||
|
||||
|
||||
def verify_payment_amount_is_positive(self):
|
||||
@@ -1168,6 +1169,8 @@ class SalesInvoice(SellingController):
|
||||
self.set_missing_values(for_validate = True)
|
||||
|
||||
def validate_inter_company_party(doctype, party, company, inter_company_invoice_reference):
|
||||
if not party:
|
||||
return
|
||||
if doctype == "Sales Invoice":
|
||||
partytype, ref_partytype, internal = "Customer", "Supplier", "is_internal_customer"
|
||||
ref_doc = "Purchase Invoice"
|
||||
|
||||
@@ -6,16 +6,16 @@ frappe.listview_settings['Sales Invoice'] = {
|
||||
add_fields: ["customer", "customer_name", "base_grand_total", "outstanding_amount", "due_date", "company",
|
||||
"currency", "is_return"],
|
||||
get_indicator: function(doc) {
|
||||
if(cint(doc.is_return)==1) {
|
||||
return [__("Return"), "darkgrey", "is_return,=,Yes"];
|
||||
} else if(flt(doc.outstanding_amount)==0) {
|
||||
return [__("Paid"), "green", "outstanding_amount,=,0"]
|
||||
} else if(flt(doc.outstanding_amount) < 0) {
|
||||
if(flt(doc.outstanding_amount) < 0) {
|
||||
return [__("Credit Note Issued"), "darkgrey", "outstanding_amount,<,0"]
|
||||
}else if (flt(doc.outstanding_amount) > 0 && doc.due_date >= frappe.datetime.get_today()) {
|
||||
} else if (flt(doc.outstanding_amount) > 0 && doc.due_date >= frappe.datetime.get_today()) {
|
||||
return [__("Unpaid"), "orange", "outstanding_amount,>,0|due_date,>,Today"]
|
||||
} else if (flt(doc.outstanding_amount) > 0 && doc.due_date < frappe.datetime.get_today()) {
|
||||
return [__("Overdue"), "red", "outstanding_amount,>,0|due_date,<=,Today"]
|
||||
} else if(cint(doc.is_return)) {
|
||||
return [__("Return"), "darkgrey", "is_return,=,Yes"];
|
||||
} else if(flt(doc.outstanding_amount)==0) {
|
||||
return [__("Paid"), "green", "outstanding_amount,=,0"]
|
||||
}
|
||||
},
|
||||
right_column: "grand_total"
|
||||
|
||||
@@ -18,6 +18,8 @@ from erpnext.accounts.doctype.account.test_account import get_inventory_account,
|
||||
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
|
||||
from erpnext.stock.doctype.item.test_item import create_item
|
||||
from six import iteritems
|
||||
from erpnext.regional.india.utils import get_ewb_data
|
||||
|
||||
class TestSalesInvoice(unittest.TestCase):
|
||||
def make(self):
|
||||
w = frappe.copy_doc(test_records[0])
|
||||
@@ -1362,7 +1364,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"included_in_print_rate": 1
|
||||
})
|
||||
si.save()
|
||||
|
||||
si.submit()
|
||||
self.assertEqual(si.net_total, 19453.13)
|
||||
self.assertEqual(si.grand_total, 24900)
|
||||
self.assertEqual(si.total_taxes_and_charges, 5446.88)
|
||||
@@ -1384,6 +1386,50 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
self.assertEqual(expected_values[gle.account][1], gle.debit)
|
||||
self.assertEqual(expected_values[gle.account][2], gle.credit)
|
||||
|
||||
def test_rounding_adjustment_2(self):
|
||||
si = create_sales_invoice(rate=400, do_not_save=True)
|
||||
for rate in [400, 600, 100]:
|
||||
si.append("items", {
|
||||
"item_code": "_Test Item",
|
||||
"gst_hsn_code": "999800",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"qty": 1,
|
||||
"rate": rate,
|
||||
"income_account": "Sales - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC"
|
||||
})
|
||||
for tax_account in ["_Test Account VAT - _TC", "_Test Account Service Tax - _TC"]:
|
||||
si.append("taxes", {
|
||||
"charge_type": "On Net Total",
|
||||
"account_head": tax_account,
|
||||
"description": tax_account,
|
||||
"rate": 9,
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"included_in_print_rate": 1
|
||||
})
|
||||
si.save()
|
||||
si.submit()
|
||||
self.assertEqual(si.net_total, 1271.19)
|
||||
self.assertEqual(si.grand_total, 1500)
|
||||
self.assertEqual(si.total_taxes_and_charges, 228.82)
|
||||
self.assertEqual(si.rounding_adjustment, -0.01)
|
||||
|
||||
expected_values = dict((d[0], d) for d in [
|
||||
[si.debit_to, 1500, 0.0],
|
||||
["_Test Account Service Tax - _TC", 0.0, 114.41],
|
||||
["_Test Account VAT - _TC", 0.0, 114.41],
|
||||
["Sales - _TC", 0.0, 1271.18]
|
||||
])
|
||||
|
||||
gl_entries = frappe.db.sql("""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
order by account asc""", si.name, as_dict=1)
|
||||
|
||||
for gle in gl_entries:
|
||||
self.assertEqual(expected_values[gle.account][0], gle.account)
|
||||
self.assertEqual(expected_values[gle.account][1], gle.debit)
|
||||
self.assertEqual(expected_values[gle.account][2], gle.credit)
|
||||
|
||||
def test_sales_invoice_with_shipping_rule(self):
|
||||
from erpnext.accounts.doctype.shipping_rule.test_shipping_rule \
|
||||
import create_shipping_rule
|
||||
@@ -1567,6 +1613,110 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
self.assertEqual(expected_gle[i][2], gle.credit)
|
||||
self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
|
||||
|
||||
def test_eway_bill_json(self):
|
||||
if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'):
|
||||
address = frappe.get_doc({
|
||||
"address_line1": "_Test Address Line 1",
|
||||
"address_title": "_Test Address for Eway bill",
|
||||
"address_type": "Billing",
|
||||
"city": "_Test City",
|
||||
"state": "Test State",
|
||||
"country": "India",
|
||||
"doctype": "Address",
|
||||
"is_primary_address": 1,
|
||||
"phone": "+91 0000000000",
|
||||
"gstin": "27AAECE4835E1ZR",
|
||||
"gst_state": "Maharashtra",
|
||||
"gst_state_number": "27",
|
||||
"pincode": "401108"
|
||||
}).insert()
|
||||
|
||||
address.append("links", {
|
||||
"link_doctype": "Company",
|
||||
"link_name": "_Test Company"
|
||||
})
|
||||
|
||||
address.save()
|
||||
|
||||
if not frappe.db.exists('Address', '_Test Customer-Address for Eway bill-Shipping'):
|
||||
address = frappe.get_doc({
|
||||
"address_line1": "_Test Address Line 1",
|
||||
"address_title": "_Test Customer-Address for Eway bill",
|
||||
"address_type": "Shipping",
|
||||
"city": "_Test City",
|
||||
"state": "Test State",
|
||||
"country": "India",
|
||||
"doctype": "Address",
|
||||
"is_primary_address": 1,
|
||||
"phone": "+91 0000000000",
|
||||
"gst_state": "Maharashtra",
|
||||
"gst_state_number": "27",
|
||||
"pincode": "410038"
|
||||
}).insert()
|
||||
|
||||
address.append("links", {
|
||||
"link_doctype": "Customer",
|
||||
"link_name": "_Test Customer"
|
||||
})
|
||||
|
||||
address.save()
|
||||
|
||||
gst_settings = frappe.get_doc("GST Settings")
|
||||
|
||||
gst_account = frappe.get_all(
|
||||
"GST Account",
|
||||
fields=["cgst_account", "sgst_account", "igst_account"],
|
||||
filters = {"company": "_Test Company"})
|
||||
|
||||
if not gst_account:
|
||||
gst_settings.append("gst_accounts", {
|
||||
"company": "_Test Company",
|
||||
"cgst_account": "CGST - _TC",
|
||||
"sgst_account": "SGST - _TC",
|
||||
"igst_account": "IGST - _TC",
|
||||
})
|
||||
|
||||
gst_settings.save()
|
||||
|
||||
si = create_sales_invoice(do_not_save =1, rate = '60000')
|
||||
|
||||
si.distance = 2000
|
||||
si.company_address = "_Test Address for Eway bill-Billing"
|
||||
si.customer_address = "_Test Customer-Address for Eway bill-Shipping"
|
||||
si.vehicle_no = "KA12KA1234"
|
||||
|
||||
si.append("taxes", {
|
||||
"charge_type": "On Net Total",
|
||||
"account_head": "CGST - _TC",
|
||||
"cost_center": "Main - _TC",
|
||||
"description": "CGST @ 9.0",
|
||||
"rate": 9
|
||||
})
|
||||
|
||||
si.append("taxes", {
|
||||
"charge_type": "On Net Total",
|
||||
"account_head": "SGST - _TC",
|
||||
"cost_center": "Main - _TC",
|
||||
"description": "SGST @ 9.0",
|
||||
"rate": 9
|
||||
})
|
||||
|
||||
si.submit()
|
||||
|
||||
data = get_ewb_data("Sales Invoice", si.name)
|
||||
|
||||
self.assertEqual(data['version'], '1.0.1118')
|
||||
self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR')
|
||||
self.assertEqual(data['billLists'][0]['fromTrdName'], '_Test Company')
|
||||
self.assertEqual(data['billLists'][0]['toTrdName'], '_Test Customer')
|
||||
self.assertEqual(data['billLists'][0]['vehicleType'], 'R')
|
||||
self.assertEqual(data['billLists'][0]['totalValue'], 60000)
|
||||
self.assertEqual(data['billLists'][0]['cgstValue'], 5400)
|
||||
self.assertEqual(data['billLists'][0]['sgstValue'], 5400)
|
||||
self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234')
|
||||
self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000)
|
||||
|
||||
|
||||
def create_sales_invoice(**args):
|
||||
si = frappe.new_doc("Sales Invoice")
|
||||
args = frappe._dict(args)
|
||||
|
||||
@@ -295,7 +295,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-03-06 15:58:37.839241",
|
||||
"modified": "2019-03-19 14:54:56.524556",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Payment",
|
||||
|
||||
@@ -314,13 +314,11 @@ class Subscription(Document):
|
||||
|
||||
self.save()
|
||||
|
||||
@property
|
||||
def is_postpaid_to_invoice(self):
|
||||
return getdate(nowdate()) > getdate(self.current_invoice_end) or \
|
||||
(getdate(nowdate()) >= getdate(self.current_invoice_end) and getdate(self.current_invoice_end) == getdate(self.current_invoice_start)) and \
|
||||
not self.has_outstanding_invoice()
|
||||
|
||||
@property
|
||||
def is_prepaid_to_invoice(self):
|
||||
if not self.generate_invoice_at_period_start:
|
||||
return False
|
||||
@@ -340,7 +338,7 @@ class Subscription(Document):
|
||||
2. Change the `Subscription` status to 'Past Due Date'
|
||||
3. Change the `Subscription` status to 'Cancelled'
|
||||
"""
|
||||
if self.is_postpaid_to_invoice or self.is_prepaid_to_invoice:
|
||||
if self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice():
|
||||
self.generate_invoice()
|
||||
if self.current_invoice_is_past_due():
|
||||
self.status = 'Past Due Date'
|
||||
|
||||
@@ -135,9 +135,9 @@ def round_off_debit_credit(gl_map):
|
||||
.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)
|
||||
make_round_off_gle(gl_map, debit_credit_diff, precision)
|
||||
|
||||
def make_round_off_gle(gl_map, debit_credit_diff):
|
||||
def make_round_off_gle(gl_map, debit_credit_diff, precision):
|
||||
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(gl_map[0].company)
|
||||
round_off_account_exists = False
|
||||
round_off_gle = frappe._dict()
|
||||
@@ -150,6 +150,10 @@ def make_round_off_gle(gl_map, debit_credit_diff):
|
||||
debit_credit_diff += flt(d.credit_in_account_currency)
|
||||
round_off_account_exists = True
|
||||
|
||||
if round_off_account_exists and abs(debit_credit_diff) <= (1.0 / (10**precision)):
|
||||
gl_map.remove(round_off_gle)
|
||||
return
|
||||
|
||||
if not round_off_gle:
|
||||
for k in ["voucher_type", "voucher_no", "company",
|
||||
"posting_date", "remarks", "is_opening"]:
|
||||
|
||||
578
erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
Normal file
578
erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
Normal file
@@ -0,0 +1,578 @@
|
||||
frappe.provide("erpnext.accounts");
|
||||
|
||||
frappe.pages['bank-reconciliation'].on_page_load = function(wrapper) {
|
||||
new erpnext.accounts.bankReconciliation(wrapper);
|
||||
}
|
||||
|
||||
erpnext.accounts.bankReconciliation = class BankReconciliation {
|
||||
constructor(wrapper) {
|
||||
this.page = frappe.ui.make_app_page({
|
||||
parent: wrapper,
|
||||
title: __("Bank Reconciliation"),
|
||||
single_column: true
|
||||
});
|
||||
this.parent = wrapper;
|
||||
this.page = this.parent.page;
|
||||
|
||||
this.check_plaid_status();
|
||||
this.make();
|
||||
}
|
||||
|
||||
make() {
|
||||
const me = this;
|
||||
|
||||
me.$main_section = $(`<div class="reconciliation page-main-content"></div>`).appendTo(me.page.main);
|
||||
const empty_state = __("Upload a bank statement, link or reconcile a bank account")
|
||||
me.$main_section.append(`<div class="flex justify-center align-center text-muted"
|
||||
style="height: 50vh; display: flex;"><h5 class="text-muted">${empty_state}</h5></div>`)
|
||||
|
||||
me.page.add_field({
|
||||
fieldtype: 'Link',
|
||||
label: __('Company'),
|
||||
fieldname: 'company',
|
||||
options: "Company",
|
||||
onchange: function() {
|
||||
if (this.value) {
|
||||
me.company = this.value;
|
||||
} else {
|
||||
me.company = null;
|
||||
me.bank_account = null;
|
||||
}
|
||||
}
|
||||
})
|
||||
me.page.add_field({
|
||||
fieldtype: 'Link',
|
||||
label: __('Bank Account'),
|
||||
fieldname: 'bank_account',
|
||||
options: "Bank Account",
|
||||
get_query: function() {
|
||||
if(!me.company) {
|
||||
frappe.throw(__("Please select company first"));
|
||||
return
|
||||
}
|
||||
|
||||
return {
|
||||
filters: {
|
||||
"company": me.company
|
||||
}
|
||||
}
|
||||
},
|
||||
onchange: function() {
|
||||
if (this.value) {
|
||||
me.bank_account = this.value;
|
||||
me.add_actions();
|
||||
} else {
|
||||
me.bank_account = null;
|
||||
me.page.hide_actions_menu();
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
check_plaid_status() {
|
||||
const me = this;
|
||||
frappe.db.get_value("Plaid Settings", "Plaid Settings", "enabled", (r) => {
|
||||
if (r && r.enabled == "1") {
|
||||
me.plaid_status = "active"
|
||||
} else {
|
||||
me.plaid_status = "inactive"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
add_actions() {
|
||||
const me = this;
|
||||
|
||||
me.page.show_menu()
|
||||
|
||||
me.page.add_menu_item(__("Upload a statement"), function() {
|
||||
me.clear_page_content();
|
||||
new erpnext.accounts.bankTransactionUpload(me);
|
||||
}, true)
|
||||
|
||||
if (me.plaid_status==="active") {
|
||||
me.page.add_menu_item(__("Synchronize this account"), function() {
|
||||
me.clear_page_content();
|
||||
new erpnext.accounts.bankTransactionSync(me);
|
||||
}, true)
|
||||
}
|
||||
|
||||
me.page.add_menu_item(__("Reconcile this account"), function() {
|
||||
me.clear_page_content();
|
||||
me.make_reconciliation_tool();
|
||||
}, true)
|
||||
}
|
||||
|
||||
clear_page_content() {
|
||||
const me = this;
|
||||
$(me.page.body).find('.frappe-list').remove();
|
||||
me.$main_section.empty();
|
||||
}
|
||||
|
||||
make_reconciliation_tool() {
|
||||
const me = this;
|
||||
frappe.model.with_doctype("Bank Transaction", () => {
|
||||
erpnext.accounts.ReconciliationList = new erpnext.accounts.ReconciliationTool({
|
||||
parent: me.parent,
|
||||
doctype: "Bank Transaction"
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
erpnext.accounts.bankTransactionUpload = class bankTransactionUpload {
|
||||
constructor(parent) {
|
||||
this.parent = parent;
|
||||
this.data = [];
|
||||
|
||||
const assets = [
|
||||
"/assets/frappe/css/frappe-datatable.css",
|
||||
"/assets/frappe/js/lib/clusterize.min.js",
|
||||
"/assets/frappe/js/lib/Sortable.min.js",
|
||||
"/assets/frappe/js/lib/frappe-datatable.js"
|
||||
];
|
||||
|
||||
frappe.require(assets, () => {
|
||||
this.make();
|
||||
});
|
||||
}
|
||||
|
||||
make() {
|
||||
const me = this;
|
||||
frappe.upload.make({
|
||||
args: {
|
||||
method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement',
|
||||
allow_multiple: 0
|
||||
},
|
||||
no_socketio: true,
|
||||
sample_url: "e.g. http://example.com/somefile.csv",
|
||||
callback: function(attachment, r) {
|
||||
if (!r.exc && r.message) {
|
||||
me.data = r.message;
|
||||
me.setup_transactions_dom();
|
||||
me.create_datatable();
|
||||
me.add_primary_action();
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
setup_transactions_dom() {
|
||||
const me = this;
|
||||
me.parent.$main_section.append(`<div class="transactions-table"></div>`)
|
||||
}
|
||||
|
||||
create_datatable() {
|
||||
try {
|
||||
this.datatable = new DataTable('.transactions-table', {
|
||||
columns: this.data.columns,
|
||||
data: this.data.data
|
||||
})
|
||||
}
|
||||
catch(err) {
|
||||
let msg = __(`Your file could not be processed by ERPNext.
|
||||
<br>It should be a standard CSV or XLSX file.
|
||||
<br>The headers should be in the first row.`)
|
||||
frappe.throw(msg)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
add_primary_action() {
|
||||
const me = this;
|
||||
me.parent.page.set_primary_action(__("Submit"), function() {
|
||||
me.add_bank_entries()
|
||||
}, null, __("Creating bank entries..."))
|
||||
}
|
||||
|
||||
add_bank_entries() {
|
||||
const me = this;
|
||||
frappe.xcall('erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.create_bank_entries',
|
||||
{columns: this.datatable.datamanager.columns, data: this.datatable.datamanager.data, bank_account: me.parent.bank_account}
|
||||
).then((result) => {
|
||||
let result_title = result.errors == 0 ? __("{0} bank transaction(s) created", [result.success]) : __("{0} bank transaction(s) created and {1} errors", [result.success, result.errors])
|
||||
let result_msg = `
|
||||
<div class="flex justify-center align-center text-muted" style="height: 50vh; display: flex;">
|
||||
<h5 class="text-muted">${result_title}</h5>
|
||||
</div>`
|
||||
me.parent.page.clear_primary_action();
|
||||
me.parent.$main_section.empty();
|
||||
me.parent.$main_section.append(result_msg);
|
||||
if (result.errors == 0) {
|
||||
frappe.show_alert({message:__("All bank transactions have been created"), indicator:'green'});
|
||||
} else {
|
||||
frappe.show_alert({message:__("Please check the error log for details about the import errors"), indicator:'red'});
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.accounts.bankTransactionSync = class bankTransactionSync {
|
||||
constructor(parent) {
|
||||
this.parent = parent;
|
||||
this.data = [];
|
||||
|
||||
this.init_config()
|
||||
}
|
||||
|
||||
init_config() {
|
||||
const me = this;
|
||||
frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.plaid_configuration')
|
||||
.then(result => {
|
||||
me.plaid_env = result.plaid_env;
|
||||
me.plaid_public_key = result.plaid_public_key;
|
||||
me.client_name = result.client_name;
|
||||
me.sync_transactions()
|
||||
})
|
||||
}
|
||||
|
||||
sync_transactions() {
|
||||
const me = this;
|
||||
frappe.db.get_value("Bank Account", me.parent.bank_account, "bank", (v) => {
|
||||
frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions', {
|
||||
bank: v['bank'],
|
||||
bank_account: me.parent.bank_account,
|
||||
freeze: true
|
||||
})
|
||||
.then((result) => {
|
||||
let result_title = (result.length > 0) ? __("{0} bank transaction(s) created", [result.length]) : __("This bank account is already synchronized")
|
||||
let result_msg = `
|
||||
<div class="flex justify-center align-center text-muted" style="height: 50vh; display: flex;">
|
||||
<h5 class="text-muted">${result_title}</h5>
|
||||
</div>`
|
||||
this.parent.$main_section.append(result_msg)
|
||||
frappe.show_alert({message:__("Bank account '{0}' has been synchronized", [me.parent.bank_account]), indicator:'green'});
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
erpnext.accounts.ReconciliationTool = class ReconciliationTool extends frappe.views.BaseList {
|
||||
constructor(opts) {
|
||||
super(opts);
|
||||
this.show();
|
||||
}
|
||||
|
||||
setup_defaults() {
|
||||
super.setup_defaults();
|
||||
|
||||
this.page_title = __("Bank Reconciliation");
|
||||
this.doctype = 'Bank Transaction';
|
||||
this.fields = ['date', 'description', 'debit', 'credit', 'currency']
|
||||
|
||||
}
|
||||
|
||||
setup_view() {
|
||||
this.render_header();
|
||||
}
|
||||
|
||||
setup_side_bar() {
|
||||
//
|
||||
}
|
||||
|
||||
make_standard_filters() {
|
||||
//
|
||||
}
|
||||
|
||||
freeze() {
|
||||
this.$result.find('.list-count').html(`<span>${__('Refreshing')}...</span>`);
|
||||
}
|
||||
|
||||
get_args() {
|
||||
const args = super.get_args();
|
||||
|
||||
return Object.assign({}, args, {
|
||||
...args.filters.push(["Bank Transaction", "docstatus", "=", 1],
|
||||
["Bank Transaction", "unallocated_amount", ">", 0])
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
update_data(r) {
|
||||
let data = r.message || [];
|
||||
|
||||
if (this.start === 0) {
|
||||
this.data = data;
|
||||
} else {
|
||||
this.data = this.data.concat(data);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const me = this;
|
||||
this.$result.find('.list-row-container').remove();
|
||||
$('[data-fieldname="name"]').remove();
|
||||
me.data.map((value) => {
|
||||
const row = $('<div class="list-row-container">').data("data", value).appendTo(me.$result).get(0);
|
||||
new erpnext.accounts.ReconciliationRow(row, value);
|
||||
})
|
||||
}
|
||||
|
||||
render_header() {
|
||||
const me = this;
|
||||
if ($(this.wrapper).find('.transaction-header').length === 0) {
|
||||
me.$result.append(frappe.render_template("bank_transaction_header"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
||||
constructor(row, data) {
|
||||
this.data = data;
|
||||
this.row = row;
|
||||
this.make();
|
||||
this.bind_events();
|
||||
}
|
||||
|
||||
make() {
|
||||
$(this.row).append(frappe.render_template("bank_transaction_row", this.data))
|
||||
}
|
||||
|
||||
bind_events() {
|
||||
const me = this;
|
||||
$(me.row).on('click', '.clickable-section', function() {
|
||||
me.bank_entry = $(this).attr("data-name");
|
||||
me.show_dialog($(this).attr("data-name"));
|
||||
})
|
||||
|
||||
$(me.row).on('click', '.new-reconciliation', function() {
|
||||
me.bank_entry = $(this).attr("data-name");
|
||||
me.show_dialog($(this).attr("data-name"));
|
||||
})
|
||||
|
||||
$(me.row).on('click', '.new-payment', function() {
|
||||
me.bank_entry = $(this).attr("data-name");
|
||||
me.new_payment();
|
||||
})
|
||||
|
||||
$(me.row).on('click', '.new-invoice', function() {
|
||||
me.bank_entry = $(this).attr("data-name");
|
||||
me.new_invoice();
|
||||
})
|
||||
|
||||
$(me.row).on('click', '.new-expense', function() {
|
||||
me.bank_entry = $(this).attr("data-name");
|
||||
me.new_expense();
|
||||
})
|
||||
}
|
||||
|
||||
new_payment() {
|
||||
const me = this;
|
||||
const paid_amount = me.data.credit > 0 ? me.data.credit : me.data.debit;
|
||||
const payment_type = me.data.credit > 0 ? "Receive": "Pay";
|
||||
const party_type = me.data.credit > 0 ? "Customer": "Supplier";
|
||||
|
||||
frappe.new_doc("Payment Entry", {"payment_type": payment_type, "paid_amount": paid_amount,
|
||||
"party_type": party_type, "paid_from": me.data.bank_account})
|
||||
}
|
||||
|
||||
new_invoice() {
|
||||
const me = this;
|
||||
const invoice_type = me.data.credit > 0 ? "Sales Invoice" : "Purchase Invoice";
|
||||
|
||||
frappe.new_doc(invoice_type)
|
||||
}
|
||||
|
||||
new_expense() {
|
||||
frappe.new_doc("Expense Claim")
|
||||
}
|
||||
|
||||
|
||||
show_dialog(data) {
|
||||
const me = this;
|
||||
|
||||
frappe.db.get_value("Bank Account", me.data.bank_account, "account", (r) => {
|
||||
me.gl_account = r.account;
|
||||
})
|
||||
|
||||
frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.get_linked_payments',
|
||||
{bank_transaction: data, freeze:true, freeze_message:__("Finding linked payments")}
|
||||
).then((result) => {
|
||||
me.make_dialog(result)
|
||||
})
|
||||
}
|
||||
|
||||
make_dialog(data) {
|
||||
const me = this;
|
||||
me.selected_payment = null;
|
||||
|
||||
const fields = [
|
||||
{
|
||||
fieldtype: 'Section Break',
|
||||
fieldname: 'section_break_1',
|
||||
label: __('Automatic Reconciliation')
|
||||
},
|
||||
{
|
||||
fieldtype: 'HTML',
|
||||
fieldname: 'payment_proposals'
|
||||
},
|
||||
{
|
||||
fieldtype: 'Section Break',
|
||||
fieldname: 'section_break_2',
|
||||
label: __('Search for a payment')
|
||||
},
|
||||
{
|
||||
fieldtype: 'Link',
|
||||
fieldname: 'payment_doctype',
|
||||
options: 'DocType',
|
||||
label: 'Payment DocType',
|
||||
get_query: () => {
|
||||
return {
|
||||
filters : {
|
||||
"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Expense Claim"]]
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldtype: 'Column Break',
|
||||
fieldname: 'column_break_1',
|
||||
},
|
||||
{
|
||||
fieldtype: 'Dynamic Link',
|
||||
fieldname: 'payment_entry',
|
||||
options: 'payment_doctype',
|
||||
label: 'Payment Document',
|
||||
get_query: () => {
|
||||
let dt = this.dialog.fields_dict.payment_doctype.value;
|
||||
if (dt === "Payment Entry") {
|
||||
return {
|
||||
query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.payment_entry_query",
|
||||
filters : {
|
||||
"bank_account": this.data.bank_account,
|
||||
"company": this.data.company
|
||||
}
|
||||
}
|
||||
} else if (dt === "Journal Entry") {
|
||||
return {
|
||||
query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.journal_entry_query",
|
||||
filters : {
|
||||
"bank_account": this.data.bank_account,
|
||||
"company": this.data.company
|
||||
}
|
||||
}
|
||||
} else if (dt === "Sales Invoice") {
|
||||
return {
|
||||
query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.sales_invoices_query"
|
||||
}
|
||||
} else if (dt === "Purchase Invoice") {
|
||||
return {
|
||||
filters : [
|
||||
["Purchase Invoice", "ifnull(clearance_date, '')", "=", ""],
|
||||
["Purchase Invoice", "docstatus", "=", 1],
|
||||
["Purchase Invoice", "company", "=", this.data.company]
|
||||
]
|
||||
}
|
||||
} else if (dt === "Expense Claim") {
|
||||
return {
|
||||
filters : [
|
||||
["Expense Claim", "ifnull(clearance_date, '')", "=", ""],
|
||||
["Expense Claim", "docstatus", "=", 1],
|
||||
["Expense Claim", "company", "=", this.data.company]
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
onchange: function() {
|
||||
if (me.selected_payment !== this.value) {
|
||||
me.selected_payment = this.value;
|
||||
me.display_payment_details(this);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldtype: 'Section Break',
|
||||
fieldname: 'section_break_3'
|
||||
},
|
||||
{
|
||||
fieldtype: 'HTML',
|
||||
fieldname: 'payment_details'
|
||||
},
|
||||
];
|
||||
|
||||
me.dialog = new frappe.ui.Dialog({
|
||||
title: __("Choose a corresponding payment"),
|
||||
fields: fields,
|
||||
size: "large"
|
||||
});
|
||||
|
||||
const proposals_wrapper = me.dialog.fields_dict.payment_proposals.$wrapper;
|
||||
if (data && data.length > 0) {
|
||||
proposals_wrapper.append(frappe.render_template("linked_payment_header"));
|
||||
data.map(value => {
|
||||
proposals_wrapper.append(frappe.render_template("linked_payment_row", value))
|
||||
})
|
||||
} else {
|
||||
const empty_data_msg = __("ERPNext could not find any matching payment entry")
|
||||
proposals_wrapper.append(`<div class="text-center"><h5 class="text-muted">${empty_data_msg}</h5></div>`)
|
||||
}
|
||||
|
||||
$(me.dialog.body).on('click', '.reconciliation-btn', (e) => {
|
||||
const payment_entry = $(e.target).attr('data-name');
|
||||
const payment_doctype = $(e.target).attr('data-doctype');
|
||||
frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.reconcile',
|
||||
{bank_transaction: me.bank_entry, payment_doctype: payment_doctype, payment_name: payment_entry})
|
||||
.then((result) => {
|
||||
setTimeout(function(){
|
||||
erpnext.accounts.ReconciliationList.refresh();
|
||||
}, 2000);
|
||||
me.dialog.hide();
|
||||
})
|
||||
})
|
||||
|
||||
me.dialog.show();
|
||||
}
|
||||
|
||||
display_payment_details(event) {
|
||||
const me = this;
|
||||
if (event.value) {
|
||||
let dt = me.dialog.fields_dict.payment_doctype.value;
|
||||
me.dialog.fields_dict['payment_details'].$wrapper.empty();
|
||||
frappe.db.get_doc(dt, event.value)
|
||||
.then(doc => {
|
||||
let displayed_docs = []
|
||||
if (dt === "Payment Entry") {
|
||||
payment.currency = doc.payment_type == "Receive" ? doc.paid_to_account_currency : doc.paid_from_account_currency;
|
||||
payment.doctype = dt
|
||||
displayed_docs.push(payment);
|
||||
} else if (dt === "Journal Entry") {
|
||||
doc.accounts.forEach(payment => {
|
||||
if (payment.account === me.gl_account) {
|
||||
payment.doctype = dt;
|
||||
payment.posting_date = doc.posting_date;
|
||||
payment.party = doc.pay_to_recd_from;
|
||||
payment.reference_no = doc.cheque_no;
|
||||
payment.reference_date = doc.cheque_date;
|
||||
payment.currency = payment.account_currency;
|
||||
payment.paid_amount = payment.credit > 0 ? payment.credit : payment.debit;
|
||||
payment.name = doc.name;
|
||||
displayed_docs.push(payment);
|
||||
}
|
||||
})
|
||||
} else if (dt === "Sales Invoice") {
|
||||
doc.payments.forEach(payment => {
|
||||
if (payment.clearance_date === null || payment.clearance_date === "") {
|
||||
payment.doctype = dt;
|
||||
payment.posting_date = doc.posting_date;
|
||||
payment.party = doc.customer;
|
||||
payment.reference_no = doc.remarks;
|
||||
payment.currency = doc.currency;
|
||||
payment.paid_amount = payment.amount;
|
||||
payment.name = doc.name;
|
||||
displayed_docs.push(payment);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const details_wrapper = me.dialog.fields_dict.payment_details.$wrapper;
|
||||
details_wrapper.append(frappe.render_template("linked_payment_header"));
|
||||
displayed_docs.forEach(values => {
|
||||
details_wrapper.append(frappe.render_template("linked_payment_row", values));
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"content": null,
|
||||
"creation": "2018-11-24 12:03:14.646669",
|
||||
"docstatus": 0,
|
||||
"doctype": "Page",
|
||||
"idx": 0,
|
||||
"modified": "2018-11-24 12:03:14.646669",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "bank-reconciliation",
|
||||
"owner": "Administrator",
|
||||
"page_name": "bank-reconciliation",
|
||||
"roles": [
|
||||
{
|
||||
"role": "System Manager"
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager"
|
||||
},
|
||||
{
|
||||
"role": "Accounts User"
|
||||
}
|
||||
],
|
||||
"script": null,
|
||||
"standard": "Yes",
|
||||
"style": null,
|
||||
"system_page": 0,
|
||||
"title": "Bank Reconciliation"
|
||||
}
|
||||
378
erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
Normal file
378
erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
Normal file
@@ -0,0 +1,378 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
import difflib
|
||||
from frappe.utils import flt
|
||||
from six import iteritems
|
||||
from erpnext import get_company_currency
|
||||
|
||||
@frappe.whitelist()
|
||||
def reconcile(bank_transaction, payment_doctype, payment_name):
|
||||
transaction = frappe.get_doc("Bank Transaction", bank_transaction)
|
||||
payment_entry = frappe.get_doc(payment_doctype, payment_name)
|
||||
|
||||
account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
|
||||
gl_entry = frappe.get_doc("GL Entry", dict(account=account, voucher_type=payment_doctype, voucher_no=payment_name))
|
||||
|
||||
if transaction.unallocated_amount == 0:
|
||||
frappe.throw(_("This bank transaction is already fully reconciled"))
|
||||
|
||||
if transaction.credit > 0 and gl_entry.credit > 0:
|
||||
frappe.throw(_("The selected payment entry should be linked with a debtor bank transaction"))
|
||||
|
||||
if transaction.debit > 0 and gl_entry.debit > 0:
|
||||
frappe.throw(_("The selected payment entry should be linked with a creditor bank transaction"))
|
||||
|
||||
add_payment_to_transaction(transaction, payment_entry, gl_entry)
|
||||
|
||||
return 'reconciled'
|
||||
|
||||
def add_payment_to_transaction(transaction, payment_entry, gl_entry):
|
||||
gl_amount, transaction_amount = (gl_entry.credit, transaction.debit) if gl_entry.credit > 0 else (gl_entry.debit, transaction.credit)
|
||||
allocated_amount = gl_amount if gl_amount <= transaction_amount else transaction_amount
|
||||
transaction.append("payment_entries", {
|
||||
"payment_document": payment_entry.doctype,
|
||||
"payment_entry": payment_entry.name,
|
||||
"allocated_amount": allocated_amount
|
||||
})
|
||||
|
||||
transaction.save()
|
||||
transaction.update_allocations()
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_linked_payments(bank_transaction):
|
||||
transaction = frappe.get_doc("Bank Transaction", bank_transaction)
|
||||
bank_account = frappe.db.get_values("Bank Account", transaction.bank_account, ["account", "company"], as_dict=True)
|
||||
|
||||
# Get all payment entries with a matching amount
|
||||
amount_matching = check_matching_amount(bank_account[0].account, bank_account[0].company, transaction)
|
||||
|
||||
# Get some data from payment entries linked to a corresponding bank transaction
|
||||
description_matching = get_matching_descriptions_data(bank_account[0].company, transaction)
|
||||
|
||||
if amount_matching:
|
||||
return check_amount_vs_description(amount_matching, description_matching)
|
||||
|
||||
elif description_matching:
|
||||
description_matching = filter(lambda x: not x.get('clearance_date'), description_matching)
|
||||
if not description_matching:
|
||||
return []
|
||||
|
||||
return sorted(list(description_matching), key = lambda x: x["posting_date"], reverse=True)
|
||||
|
||||
else:
|
||||
return []
|
||||
|
||||
def check_matching_amount(bank_account, company, transaction):
|
||||
payments = []
|
||||
amount = transaction.credit if transaction.credit > 0 else transaction.debit
|
||||
|
||||
payment_type = "Receive" if transaction.credit > 0 else "Pay"
|
||||
account_from_to = "paid_to" if transaction.credit > 0 else "paid_from"
|
||||
currency_field = "paid_to_account_currency as currency" if transaction.credit > 0 else "paid_from_account_currency as currency"
|
||||
|
||||
payment_entries = frappe.get_all("Payment Entry", fields=["'Payment Entry' as doctype", "name", "paid_amount", "payment_type", "reference_no", "reference_date",
|
||||
"party", "party_type", "posting_date", "{0}".format(currency_field)], filters=[["paid_amount", "like", "{0}%".format(amount)],
|
||||
["docstatus", "=", "1"], ["payment_type", "=", [payment_type, "Internal Transfer"]], ["ifnull(clearance_date, '')", "=", ""], ["{0}".format(account_from_to), "=", "{0}".format(bank_account)]])
|
||||
|
||||
if transaction.credit > 0:
|
||||
journal_entries = frappe.db.sql("""
|
||||
SELECT
|
||||
'Journal Entry' as doctype, je.name, je.posting_date, je.cheque_no as reference_no,
|
||||
je.pay_to_recd_from as party, je.cheque_date as reference_date, jea.debit_in_account_currency as paid_amount
|
||||
FROM
|
||||
`tabJournal Entry Account` as jea
|
||||
JOIN
|
||||
`tabJournal Entry` as je
|
||||
ON
|
||||
jea.parent = je.name
|
||||
WHERE
|
||||
(je.clearance_date is null or je.clearance_date='0000-00-00')
|
||||
AND
|
||||
jea.account = %s
|
||||
AND
|
||||
jea.debit_in_account_currency like %s
|
||||
AND
|
||||
je.docstatus = 1
|
||||
""", (bank_account, amount), as_dict=True)
|
||||
else:
|
||||
journal_entries = frappe.db.sql("""
|
||||
SELECT
|
||||
'Journal Entry' as doctype, je.name, je.posting_date, je.cheque_no as reference_no,
|
||||
jea.account_currency as currency, je.pay_to_recd_from as party, je.cheque_date as reference_date,
|
||||
jea.credit_in_account_currency as paid_amount
|
||||
FROM
|
||||
`tabJournal Entry Account` as jea
|
||||
JOIN
|
||||
`tabJournal Entry` as je
|
||||
ON
|
||||
jea.parent = je.name
|
||||
WHERE
|
||||
(je.clearance_date is null or je.clearance_date='0000-00-00')
|
||||
AND
|
||||
jea.account = %(bank_account)s
|
||||
AND
|
||||
jea.credit_in_account_currency like %(txt)s
|
||||
AND
|
||||
je.docstatus = 1
|
||||
""", {
|
||||
'bank_account': bank_account,
|
||||
'txt': '%%%s%%' % amount
|
||||
}, as_dict=True)
|
||||
|
||||
frappe.errprint(journal_entries)
|
||||
|
||||
if transaction.credit > 0:
|
||||
sales_invoices = frappe.db.sql("""
|
||||
SELECT
|
||||
'Sales Invoice' as doctype, si.name, si.customer as party,
|
||||
si.posting_date, sip.amount as paid_amount
|
||||
FROM
|
||||
`tabSales Invoice Payment` as sip
|
||||
JOIN
|
||||
`tabSales Invoice` as si
|
||||
ON
|
||||
sip.parent = si.name
|
||||
WHERE
|
||||
(sip.clearance_date is null or sip.clearance_date='0000-00-00')
|
||||
AND
|
||||
sip.account = %s
|
||||
AND
|
||||
sip.amount like %s
|
||||
AND
|
||||
si.docstatus = 1
|
||||
""", (bank_account, amount), as_dict=True)
|
||||
else:
|
||||
sales_invoices = []
|
||||
|
||||
if transaction.debit > 0:
|
||||
purchase_invoices = frappe.get_all("Purchase Invoice",
|
||||
fields = ["'Purchase Invoice' as doctype", "name", "paid_amount", "supplier as party", "posting_date", "currency"],
|
||||
filters=[
|
||||
["paid_amount", "like", "{0}%".format(amount)],
|
||||
["docstatus", "=", "1"],
|
||||
["is_paid", "=", "1"],
|
||||
["ifnull(clearance_date, '')", "=", ""],
|
||||
["cash_bank_account", "=", "{0}".format(bank_account)]
|
||||
]
|
||||
)
|
||||
|
||||
mode_of_payments = [x["parent"] for x in frappe.db.get_list("Mode of Payment Account",
|
||||
filters={"default_account": bank_account}, fields=["parent"])]
|
||||
|
||||
company_currency = get_company_currency(company)
|
||||
|
||||
expense_claims = frappe.get_all("Expense Claim",
|
||||
fields=["'Expense Claim' as doctype", "name", "total_sanctioned_amount as paid_amount",
|
||||
"employee as party", "posting_date", "'{0}' as currency".format(company_currency)],
|
||||
filters=[
|
||||
["total_sanctioned_amount", "like", "{0}%".format(amount)],
|
||||
["docstatus", "=", "1"],
|
||||
["is_paid", "=", "1"],
|
||||
["ifnull(clearance_date, '')", "=", ""],
|
||||
["mode_of_payment", "in", "{0}".format(tuple(mode_of_payments))]
|
||||
]
|
||||
)
|
||||
else:
|
||||
purchase_invoices = expense_claims = []
|
||||
|
||||
for data in [payment_entries, journal_entries, sales_invoices, purchase_invoices, expense_claims]:
|
||||
if data:
|
||||
payments.extend(data)
|
||||
|
||||
return payments
|
||||
|
||||
def get_matching_descriptions_data(company, transaction):
|
||||
if not transaction.description :
|
||||
return []
|
||||
|
||||
bank_transactions = frappe.db.sql("""
|
||||
SELECT
|
||||
bt.name, bt.description, bt.date, btp.payment_document, btp.payment_entry
|
||||
FROM
|
||||
`tabBank Transaction` as bt
|
||||
LEFT JOIN
|
||||
`tabBank Transaction Payments` as btp
|
||||
ON
|
||||
bt.name = btp.parent
|
||||
WHERE
|
||||
bt.allocated_amount > 0
|
||||
AND
|
||||
bt.docstatus = 1
|
||||
""", as_dict=True)
|
||||
|
||||
selection = []
|
||||
for bank_transaction in bank_transactions:
|
||||
if bank_transaction.description:
|
||||
seq=difflib.SequenceMatcher(lambda x: x == " ", transaction.description, bank_transaction.description)
|
||||
|
||||
if seq.ratio() > 0.6:
|
||||
bank_transaction["ratio"] = seq.ratio()
|
||||
selection.append(bank_transaction)
|
||||
|
||||
document_types = set([x["payment_document"] for x in selection])
|
||||
|
||||
links = {}
|
||||
for document_type in document_types:
|
||||
links[document_type] = [x["payment_entry"] for x in selection if x["payment_document"]==document_type]
|
||||
|
||||
|
||||
data = []
|
||||
company_currency = get_company_currency(company)
|
||||
for key, value in iteritems(links):
|
||||
if key == "Payment Entry":
|
||||
data.extend(frappe.get_all("Payment Entry", filters=[["name", "in", value]],
|
||||
fields=["'Payment Entry' as doctype", "posting_date", "party", "reference_no",
|
||||
"reference_date", "paid_amount", "paid_to_account_currency as currency", "clearance_date"]))
|
||||
if key == "Journal Entry":
|
||||
journal_entries = frappe.get_all("Journal Entry", filters=[["name", "in", value]],
|
||||
fields=["name", "'Journal Entry' as doctype", "posting_date",
|
||||
"pay_to_recd_from as party", "cheque_no as reference_no", "cheque_date as reference_date",
|
||||
"total_credit as paid_amount", "clearance_date"])
|
||||
for journal_entry in journal_entries:
|
||||
journal_entry_accounts = frappe.get_all("Journal Entry Account", filters={"parenttype": journal_entry["doctype"], "parent": journal_entry["name"]}, fields=["account_currency"])
|
||||
journal_entry["currency"] = journal_entry_accounts[0]["account_currency"] if journal_entry_accounts else company_currency
|
||||
data.extend(journal_entries)
|
||||
if key == "Sales Invoice":
|
||||
data.extend(frappe.get_all("Sales Invoice", filters=[["name", "in", value]], fields=["'Sales Invoice' as doctype", "posting_date", "customer_name as party", "paid_amount", "currency"]))
|
||||
if key == "Purchase Invoice":
|
||||
data.extend(frappe.get_all("Purchase Invoice", filters=[["name", "in", value]], fields=["'Purchase Invoice' as doctype", "posting_date", "supplier_name as party", "paid_amount", "currency"]))
|
||||
if key == "Expense Claim":
|
||||
expense_claims = frappe.get_all("Expense Claim", filters=[["name", "in", value]], fields=["'Expense Claim' as doctype", "posting_date", "employee_name as party", "total_amount_reimbursed as paid_amount"])
|
||||
data.extend([dict(x,**{"currency": company_currency}) for x in expense_claims])
|
||||
|
||||
return data
|
||||
|
||||
def check_amount_vs_description(amount_matching, description_matching):
|
||||
result = []
|
||||
|
||||
if description_matching:
|
||||
for am_match in amount_matching:
|
||||
for des_match in description_matching:
|
||||
if des_match.get("clearance_date"):
|
||||
continue
|
||||
|
||||
if am_match["party"] == des_match["party"]:
|
||||
if am_match not in result:
|
||||
result.append(am_match)
|
||||
continue
|
||||
|
||||
if "reference_no" in am_match and "reference_no" in des_match:
|
||||
if difflib.SequenceMatcher(lambda x: x == " ", am_match["reference_no"], des_match["reference_no"]).ratio() > 70:
|
||||
if am_match not in result:
|
||||
result.append(am_match)
|
||||
if result:
|
||||
return sorted(result, key = lambda x: x["posting_date"], reverse=True)
|
||||
else:
|
||||
return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True)
|
||||
|
||||
else:
|
||||
return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True)
|
||||
|
||||
def get_matching_transactions_payments(description_matching):
|
||||
payments = [x["payment_entry"] for x in description_matching]
|
||||
|
||||
payment_by_ratio = {x["payment_entry"]: x["ratio"] for x in description_matching}
|
||||
|
||||
if payments:
|
||||
reference_payment_list = frappe.get_all("Payment Entry", fields=["name", "paid_amount", "payment_type", "reference_no", "reference_date",
|
||||
"party", "party_type", "posting_date", "paid_to_account_currency"], filters=[["name", "in", payments]])
|
||||
|
||||
return sorted(reference_payment_list, key=lambda x: payment_by_ratio[x["name"]])
|
||||
|
||||
else:
|
||||
return []
|
||||
|
||||
def payment_entry_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account")
|
||||
if not account:
|
||||
return
|
||||
|
||||
return frappe.db.sql("""
|
||||
SELECT
|
||||
name, party, paid_amount, received_amount, reference_no
|
||||
FROM
|
||||
`tabPayment Entry`
|
||||
WHERE
|
||||
(clearance_date is null or clearance_date='0000-00-00')
|
||||
AND (paid_from = %(account)s or paid_to = %(account)s)
|
||||
AND (name like %(txt)s or party like %(txt)s)
|
||||
AND docstatus = 1
|
||||
ORDER BY
|
||||
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), name
|
||||
LIMIT
|
||||
%(start)s, %(page_len)s""",
|
||||
{
|
||||
'txt': "%%%s%%" % txt,
|
||||
'_txt': txt.replace("%", ""),
|
||||
'start': start,
|
||||
'page_len': page_len,
|
||||
'account': account
|
||||
}
|
||||
)
|
||||
|
||||
def journal_entry_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account")
|
||||
|
||||
return frappe.db.sql("""
|
||||
SELECT
|
||||
jea.parent, je.pay_to_recd_from,
|
||||
if(jea.debit_in_account_currency > 0, jea.debit_in_account_currency, jea.credit_in_account_currency)
|
||||
FROM
|
||||
`tabJournal Entry Account` as jea
|
||||
LEFT JOIN
|
||||
`tabJournal Entry` as je
|
||||
ON
|
||||
jea.parent = je.name
|
||||
WHERE
|
||||
(je.clearance_date is null or je.clearance_date='0000-00-00')
|
||||
AND
|
||||
jea.account = %(account)s
|
||||
AND
|
||||
(jea.parent like %(txt)s or je.pay_to_recd_from like %(txt)s)
|
||||
AND
|
||||
je.docstatus = 1
|
||||
ORDER BY
|
||||
if(locate(%(_txt)s, jea.parent), locate(%(_txt)s, jea.parent), 99999),
|
||||
jea.parent
|
||||
LIMIT
|
||||
%(start)s, %(page_len)s""",
|
||||
{
|
||||
'txt': "%%%s%%" % txt,
|
||||
'_txt': txt.replace("%", ""),
|
||||
'start': start,
|
||||
'page_len': page_len,
|
||||
'account': account
|
||||
}
|
||||
)
|
||||
|
||||
def sales_invoices_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
return frappe.db.sql("""
|
||||
SELECT
|
||||
sip.parent, si.customer, sip.amount, sip.mode_of_payment
|
||||
FROM
|
||||
`tabSales Invoice Payment` as sip
|
||||
LEFT JOIN
|
||||
`tabSales Invoice` as si
|
||||
ON
|
||||
sip.parent = si.name
|
||||
WHERE
|
||||
(sip.clearance_date is null or sip.clearance_date='0000-00-00')
|
||||
AND
|
||||
(sip.parent like %(txt)s or si.customer like %(txt)s)
|
||||
ORDER BY
|
||||
if(locate(%(_txt)s, sip.parent), locate(%(_txt)s, sip.parent), 99999),
|
||||
sip.parent
|
||||
LIMIT
|
||||
%(start)s, %(page_len)s""",
|
||||
{
|
||||
'txt': "%%%s%%" % txt,
|
||||
'_txt': txt.replace("%", ""),
|
||||
'start': start,
|
||||
'page_len': page_len
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="transaction-header">
|
||||
<div class="level list-row list-row-head text-muted small">
|
||||
<div class="col-sm-2 ellipsis hidden-xs">
|
||||
{{ __("Date") }}
|
||||
</div>
|
||||
<div class="col-xs-11 col-sm-4 ellipsis list-subject">
|
||||
{{ __("Description") }}
|
||||
</div>
|
||||
<div class="col-sm-2 ellipsis hidden-xs">
|
||||
{{ __("Debit") }}
|
||||
</div>
|
||||
<div class="col-sm-2 ellipsis hidden-xs">
|
||||
{{ __("Credit") }}
|
||||
</div>
|
||||
<div class="col-sm-1 ellipsis hidden-xs">
|
||||
{{ __("Currency") }}
|
||||
</div>
|
||||
<div class="col-sm-1 ellipsis">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
<div class="list-row transaction-item">
|
||||
<div>
|
||||
<div class="clickable-section" data-name={{ name }}>
|
||||
<div class="col-sm-2 ellipsis hidden-xs">
|
||||
{%= frappe.datetime.str_to_user(date) %}
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-4 ellipsis list-subject">
|
||||
{{ description }}
|
||||
</div>
|
||||
<div class="col-sm-2 ellipsis hidden-xs">
|
||||
{%= format_currency(debit, currency) %}
|
||||
</div>
|
||||
<div class="col-sm-2 ellipsis hidden-xs">
|
||||
{%= format_currency(credit, currency) %}
|
||||
</div>
|
||||
<div class="col-sm-1 ellipsis hidden-xs">
|
||||
{{ currency }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-3 col-sm-1">
|
||||
<div class="btn-group">
|
||||
<a class="dropdown-toggle btn btn-default btn-xs" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span>Actions </span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu reports-dropdown" style="max-height: 300px; overflow-y: auto; right: 0px; left: auto;">
|
||||
<li><a class="new-reconciliation" data-name={{ name }}>{{ __("Reconcile") }}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a class="new-payment" data-name={{ name }}>{{ __("New Payment") }}</a></li>
|
||||
<li><a class="new-invoice" data-name={{ name }}>{{ __("New Invoice") }}</a></li>
|
||||
<li><a class="new-expense" data-name={{ name }}>{{ __("New Expense") }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="transaction-header">
|
||||
<div class="level list-row list-row-head text-muted small">
|
||||
<div class="col-xs-3 col-sm-2 ellipsis">
|
||||
{{ __("Payment Name") }}
|
||||
</div>
|
||||
<div class="col-xs-3 col-sm-2 ellipsis">
|
||||
{{ __("Reference Date") }}
|
||||
</div>
|
||||
<div class="col-sm-2 ellipsis hidden-xs">
|
||||
{{ __("Amount") }}
|
||||
</div>
|
||||
<div class="col-sm-2 ellipsis hidden-xs">
|
||||
{{ __("Party") }}
|
||||
</div>
|
||||
<div class="col-xs-3 col-sm-2 ellipsis">
|
||||
{{ __("Reference Number") }}
|
||||
</div>
|
||||
<div class="col-xs-2 col-sm-2">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
<div class="list-row">
|
||||
<div>
|
||||
<div class="col-xs-3 col-sm-2 ellipsis">
|
||||
{{ name }}
|
||||
</div>
|
||||
<div class="col-xs-3 col-sm-2 ellipsis">
|
||||
{% if (typeof reference_date !== "undefined") %}
|
||||
{%= frappe.datetime.str_to_user(reference_date) %}
|
||||
{% else %}
|
||||
{% if (typeof posting_date !== "undefined") %}
|
||||
{%= frappe.datetime.str_to_user(posting_date) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-sm-2 ellipsis hidden-xs">
|
||||
{{ format_currency(paid_amount, currency) }}
|
||||
</div>
|
||||
<div class="col-sm-2 ellipsis hidden-xs">
|
||||
{% if (typeof party !== "undefined") %}
|
||||
{{ party }}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-xs-3 col-sm-2 ellipsis">
|
||||
{% if (typeof reference_no !== "undefined") %}
|
||||
{{ reference_no }}
|
||||
{% else %}
|
||||
{{ "" }}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-xs-2 col-sm-2">
|
||||
<div class="text-right margin-bottom">
|
||||
<button class="btn btn-primary btn-xs reconciliation-btn" data-doctype="{{ doctype }}" data-name="{{ name }}">{{ __("Reconcile") }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1957,6 +1957,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
}],
|
||||
function(values){
|
||||
me.item_batch_no[me.items[0].item_code] = values.batch;
|
||||
const item = me.frm.doc.items.find(
|
||||
({ item_code }) => item_code === me.items[0].item_code
|
||||
);
|
||||
if (item) {
|
||||
item.batch_no = values.batch;
|
||||
}
|
||||
},
|
||||
__('Select Batch No'))
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
|
||||
frappe.throw(_("Not permitted for {0}").format(party), frappe.PermissionError)
|
||||
|
||||
party = frappe.get_doc(party_type, party)
|
||||
currency = party.default_currency if party.default_currency else get_company_currency(company)
|
||||
currency = party.default_currency if party.get("default_currency") else get_company_currency(company)
|
||||
|
||||
out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_group)
|
||||
out["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
|
||||
@@ -140,7 +140,7 @@ def set_other_values(out, party, party_type):
|
||||
|
||||
def get_default_price_list(party):
|
||||
"""Return default price list for party (Document object)"""
|
||||
if party.default_price_list:
|
||||
if party.get("default_price_list"):
|
||||
return party.default_price_list
|
||||
|
||||
if party.doctype == "Customer":
|
||||
|
||||
@@ -6,17 +6,18 @@
|
||||
|
||||
|
||||
</style>
|
||||
<div class="page-break">
|
||||
<div>
|
||||
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
|
||||
{%- if not doc.get("print_heading") and not doc.get("select_print_heading")
|
||||
and doc.set("select_print_heading", _("Payment Entry")) -%}{%- endif -%}
|
||||
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
|
||||
<div class="row margin-bottom">
|
||||
<div class="col-sm-6">
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
|
||||
</table>
|
||||
@@ -30,53 +31,46 @@
|
||||
<th>Party</th>
|
||||
<th>Amount</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
|
||||
</tr>
|
||||
{% for entries in gl %}
|
||||
{% if entries.credit == 0.0 %}
|
||||
<tr>
|
||||
<td class="right top-bottom">{{ entries.account }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party_type }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party }}</td>
|
||||
<td class="left top-bottom">{{ entries.debit }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom"colspan="4"><strong> Narration </strong><br>{{ entries.remarks }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
|
||||
<td class="left" >{{ gl | sum(attribute='debit') }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="5"><strong>Credit</strong></td>
|
||||
</tr>
|
||||
{% set total_credit = 0 -%}
|
||||
{% for entries in doc.gl_entries %}
|
||||
{% for entries in gl %}
|
||||
{% if entries.debit == 0.0 %}
|
||||
<tr>
|
||||
<td class="right top-bottom">{{ entries.account }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party_type }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party }}</td>
|
||||
<td class="left top-bottom">{{ entries.credit }}</td>
|
||||
{% set total_credit = total_credit + entries.credit -%}
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="4"><strong> Narration </strong><br>{{ entries.remarks }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
|
||||
<td class="left" >{{total_credit}}</td>
|
||||
<td class="left" >{{ gl | sum(attribute='credit') }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="4"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
|
||||
</tr>
|
||||
{% set total_debit = 0 -%}
|
||||
{% for entries in doc.gl_entries %}
|
||||
{% if entries.credit == 0.0 %}
|
||||
<tr>
|
||||
<td class="right top-bottom">{{ entries.account }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party_type }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party }}</td>
|
||||
{% set total_debit = total_debit + entries.debit -%}
|
||||
<td class="left top-bottom">{{ entries.debit }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom"colspan="4"><strong> Narration </strong><br>{{ entries.remarks }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
|
||||
<td class="left" >{{total_debit}}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
<div>
|
||||
</div>
|
||||
@@ -1,19 +1,23 @@
|
||||
{
|
||||
"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",
|
||||
"align_labels_right": 0,
|
||||
"creation": "2014-08-28 11:11:39.796473",
|
||||
"custom_format": 0,
|
||||
"disabled": 0,
|
||||
"doc_type": "Journal Entry",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format",
|
||||
"format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"<div class=\\\"print-heading\\\">\\t\\t\\t\\t<h2>Journal Entry<br><small>{{ doc.name }}</small>\\t\\t\\t\\t</h2></div>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"voucher_type\", \"print_hide\": 0, \"label\": \"Entry Type\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"posting_date\", \"print_hide\": 0, \"label\": \"Posting Date\"}, {\"fieldname\": \"finance_book\", \"print_hide\": 0, \"label\": \"Finance Book\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"accounts\", \"print_hide\": 0, \"label\": \"Accounting Entries\", \"visible_columns\": [{\"fieldname\": \"account\", \"print_width\": \"250px\", \"print_hide\": 0}, {\"fieldname\": \"bank_account_no\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"party_type\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"party\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"debit_in_account_currency\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"credit_in_account_currency\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"reference_type\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"reference_name\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"reference_due_date\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"project\", \"print_width\": \"\", \"print_hide\": 0}]}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"cheque_no\", \"print_hide\": 0, \"label\": \"Reference Number\"}, {\"fieldname\": \"cheque_date\", \"print_hide\": 0, \"label\": \"Reference Date\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"get_balance\", \"print_hide\": 0, \"label\": \"Make Difference Entry\"}, {\"fieldname\": \"total_amount\", \"print_hide\": 0, \"label\": \"Total Amount\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Reference\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"clearance_date\", \"print_hide\": 0, \"label\": \"Clearance Date\"}, {\"fieldname\": \"remark\", \"print_hide\": 0, \"label\": \"Remark\"}, {\"fieldname\": \"inter_company_journal_entry_reference\", \"print_hide\": 0, \"label\": \"Inter Company Journal Entry Reference\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"due_date\", \"print_hide\": 0, \"label\": \"Due Date\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Printing Settings\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"pay_to_recd_from\", \"print_hide\": 0, \"label\": \"Pay To / Recd From\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"letter_head\", \"print_hide\": 0, \"label\": \"Letter Head\"}, {\"fieldtype\": \"Section Break\", \"label\": \"More Information\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"mode_of_payment\", \"print_hide\": 0, \"label\": \"Mode of Payment\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"stock_entry\", \"print_hide\": 0, \"label\": \"Stock Entry\"}]",
|
||||
"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,
|
||||
"line_breaks": 0,
|
||||
"modified": "2019-04-18 12:10:14.732269",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Credit Note",
|
||||
"owner": "Administrator",
|
||||
"parentfield": "__print_formats",
|
||||
"print_format_builder": 0,
|
||||
"print_format_type": "Server",
|
||||
"show_section_headings": 0,
|
||||
"standard": "Yes"
|
||||
}
|
||||
@@ -3,26 +3,25 @@
|
||||
.table-bordered td.top-bottom {border-top: none !important;border-bottom: none !important;}
|
||||
.table-bordered td.right{border-right: none !important;}
|
||||
.table-bordered td.left{border-left: none !important;}
|
||||
|
||||
|
||||
</style>
|
||||
<div class="page-break">
|
||||
<div>
|
||||
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
|
||||
{%- if not doc.get("print_heading") and not doc.get("select_print_heading")
|
||||
and doc.set("select_print_heading", _("Journal Entry")) -%}{%- endif -%}
|
||||
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
|
||||
<div class="row margin-bottom">
|
||||
<div class="col-sm-6">
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
||||
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="margin-top">
|
||||
<div>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<tr>
|
||||
<th>Account</th>
|
||||
@@ -30,47 +29,43 @@
|
||||
<th>Party</th>
|
||||
<th>Amount</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
|
||||
</tr>
|
||||
{% for entries in gl %}
|
||||
{% if entries.credit == 0.0 %}
|
||||
<tr>
|
||||
<td class="right top-bottom">{{ entries.account }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party_type }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party }}</td>
|
||||
<td class="left top-bottom">{{ entries.debit }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
|
||||
<td class="left" >{{ gl | sum(attribute='debit') }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="5"><strong>Credit</strong></td>
|
||||
</tr>
|
||||
{% set total_credit = 0 -%}
|
||||
{% for entries in doc.gl_entries %}
|
||||
{% for entries in gl %}
|
||||
{% if entries.debit == 0.0 %}
|
||||
<tr>
|
||||
<td class="right top-bottom">{{ entries.account }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party_type }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party }}</td>
|
||||
<td class="left top-bottom">{{ entries.credit }}</td>
|
||||
{% set total_credit = total_credit + entries.credit -%}
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
|
||||
<td class="left" >{{total_credit}}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="4"> </td>
|
||||
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
|
||||
<td class="left" >{{ gl | sum(attribute='credit') }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
|
||||
<td class="top-bottom" colspan="5"><b>Narration: </b>{{ gl[0].remarks }}</td>
|
||||
</tr>
|
||||
{% set total_debit = 0 -%}
|
||||
{% for entries in doc.gl_entries %}
|
||||
{% if entries.credit == 0.0 %}
|
||||
<tr>
|
||||
<td class="right top-bottom">{{ entries.account }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party_type }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party }}</td>
|
||||
{% set total_debit = total_debit + entries.debit -%}
|
||||
<td class="left top-bottom">{{ entries.debit }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
|
||||
<td class="left" >{{total_debit}}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
<div>
|
||||
</div>
|
||||
@@ -1,10 +1,11 @@
|
||||
{%- from "templates/print_formats/standard_macros.html" import add_header -%}
|
||||
<div class="page-break">
|
||||
<div>
|
||||
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
|
||||
{%- if not doc.get("print_heading") and not doc.get("select_print_heading")
|
||||
and doc.set("select_print_heading", _("Purchase Invoice")) -%}{%- endif -%}
|
||||
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
|
||||
<div class="row margin-bottom">
|
||||
<div class="col-sm-6">
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Supplier Name: </strong></td><td>{{ doc.supplier }}</td></tr>
|
||||
<tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr>
|
||||
@@ -13,7 +14,7 @@
|
||||
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
||||
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
|
||||
@@ -49,21 +50,27 @@
|
||||
</table>
|
||||
</div>
|
||||
<div class="row margin-bottom">
|
||||
<div class="col-sm-6">
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Total Quantity: </strong></td><td>{{ doc.total_qty }}</td></tr>
|
||||
<tr><td><strong>Total: </strong></td><td>{{doc.total}}</td></tr>
|
||||
<tr><td><strong>Net Weight: </strong></td><td>{{ doc.total_net_weight }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Tax and Charges: </strong></td><td>{{doc.taxes_and_charges}}</td></tr>
|
||||
{% for tax in doc.taxes %}
|
||||
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
|
||||
{% if tax.tax_amount_after_discount_amount!= 0 %}
|
||||
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if doc.taxes_and_charges_added!= 0 %}
|
||||
<tr><td><strong> Taxes and Charges Added: </strong></td><td>{{ doc.taxes_and_charges_added }}</td></tr>
|
||||
{% endif %}
|
||||
{% if doc.taxes_and_charges_deducted!= 0 %}
|
||||
<tr><td><strong> Taxes and Charges Deducted: </strong></td><td>{{ doc.taxes_and_charges_deducted }}</td></tr>
|
||||
{% endif %}
|
||||
<tr><td><strong> Total Taxes and Charges: </strong></td><td>{{ doc.total_taxes_and_charges }}</td></tr>
|
||||
<tr><td><strong> Net Payable: </strong></td><td>{{ doc.grand_total }}</td></tr>
|
||||
</table>
|
||||
@@ -76,17 +83,17 @@
|
||||
<th>Account</th>
|
||||
<th>Party Type</th>
|
||||
<th>Party</th>
|
||||
<th>Credit Amount</th>
|
||||
<th>Debit Amount</th>
|
||||
<th>Credit Amount</th>
|
||||
</tr>
|
||||
{% for entries in doc.gl_entries %}
|
||||
{% for entries in gl %}
|
||||
<tr>
|
||||
<td>{{ loop.index }}</td>
|
||||
<td>{{ entries.account }}</td>
|
||||
<td>{{ entries.party_type }}</td>
|
||||
<td>{{ entries.party }}</td>
|
||||
<td>{{ entries.credit }}</td>
|
||||
<td>{{ entries.debit }}</td>
|
||||
<td>{{ entries.credit }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
{%- from "templates/print_formats/standard_macros.html" import add_header -%}
|
||||
<div class="page-break">
|
||||
<div>
|
||||
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
|
||||
{%- if not doc.get("print_heading") and not doc.get("select_print_heading")
|
||||
and doc.set("select_print_heading", _("Sales Invoice")) -%}{%- endif -%}
|
||||
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
|
||||
<div class="row margin-bottom">
|
||||
<div class="col-sm-6">
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Customer Name: </strong></td><td>{{ doc.customer }}</td></tr>
|
||||
<tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr>
|
||||
@@ -13,7 +14,7 @@
|
||||
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
||||
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
|
||||
@@ -45,18 +46,20 @@
|
||||
</table>
|
||||
</div>
|
||||
<div class="row margin-bottom">
|
||||
<div class="col-sm-6">
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Total Quantity: </strong></td><td>{{ doc.total_qty }}</td></tr>
|
||||
<tr><td><strong>Total: </strong></td><td>{{doc.total}}</td></tr>
|
||||
<tr><td><strong>Net Weight: </strong></td><td>{{ doc.total_net_weight }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Tax and Charges: </strong></td><td>{{doc.taxes_and_charges}}</td></tr>
|
||||
{% for tax in doc.taxes %}
|
||||
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
|
||||
{% if tax.tax_amount_after_discount_amount!= 0 %}
|
||||
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr><td><strong> Total Taxes and Charges: </strong></td><td>{{ doc.total_taxes_and_charges }}</td></tr>
|
||||
<tr><td><strong> Net Payable: </strong></td><td>{{ doc.grand_total }}</td></tr>
|
||||
@@ -70,17 +73,17 @@
|
||||
<th>Account</th>
|
||||
<th>Party Type</th>
|
||||
<th>Party</th>
|
||||
<th>Credit Amount</th>
|
||||
<th>Debit Amount</th>
|
||||
<th>Credit Amount</th>
|
||||
</tr>
|
||||
{% for entries in doc.gl_entries %}
|
||||
{% for entries in gl %}
|
||||
<tr>
|
||||
<td>{{ loop.index }}</td>
|
||||
<td>{{ entries.account }}</td>
|
||||
<td>{{ entries.party_type }}</td>
|
||||
<td>{{ entries.party }}</td>
|
||||
<td>{{ entries.credit }}</td>
|
||||
<td>{{ entries.debit }}</td>
|
||||
<td>{{ entries.credit }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
|
||||
@@ -44,6 +44,13 @@ frappe.query_reports["Accounts Payable"] = {
|
||||
"default": "90",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"range4",
|
||||
"label": __("Ageing Range 4"),
|
||||
"fieldtype": "Int",
|
||||
"default": "120",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"finance_book",
|
||||
"label": __("Finance Book"),
|
||||
|
||||
@@ -44,6 +44,13 @@ frappe.query_reports["Accounts Payable Summary"] = {
|
||||
"default": "90",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"range4",
|
||||
"label": __("Ageing Range 4"),
|
||||
"fieldtype": "Int",
|
||||
"default": "120",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"finance_book",
|
||||
"label": __("Finance Book"),
|
||||
|
||||
@@ -107,14 +107,14 @@
|
||||
<thead>
|
||||
<tr>
|
||||
{% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
|
||||
<th style="width: 9%">{%= __("Date") %}</th>
|
||||
<th style="width: 5%">{%= __("Age (Days)") %}</th>
|
||||
<th style="width: 10%">{%= __("Date") %}</th>
|
||||
<th style="width: 4%">{%= __("Age (Days)") %}</th>
|
||||
|
||||
{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
|
||||
<th style="width: 16%">{%= __("Reference") %}</th>
|
||||
<th style="width: 14%">{%= __("Reference") %}</th>
|
||||
<th style="width: 10%">{%= __("Sales Person") %}</th>
|
||||
{% } else { %}
|
||||
<th style="width: 26%">{%= __("Reference") %}</th>
|
||||
<th style="width: 24%">{%= __("Reference") %}</th>
|
||||
{% } %}
|
||||
{% if(!filters.show_pdc_in_print) { %}
|
||||
<th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
|
||||
@@ -127,7 +127,7 @@
|
||||
<th style="width: 10%; text-align: right">{%= __("Outstanding Amount") %}</th>
|
||||
{% if(filters.show_pdc_in_print) { %}
|
||||
{% if(report.report_name === "Accounts Receivable") { %}
|
||||
<th style="width: 10%">{%= __("Customer LPO No.") %}</th>
|
||||
<th style="width: 12%">{%= __("Customer LPO No.") %}</th>
|
||||
{% } %}
|
||||
<th style="width: 10%">{%= __("PDC/LC Ref") %}</th>
|
||||
<th style="width: 10%">{%= __("PDC/LC Amount") %}</th>
|
||||
@@ -206,7 +206,7 @@
|
||||
{% if(!filters.show_pdc_in_print) { %}
|
||||
<td></td>
|
||||
{% } %}
|
||||
{% if(report.report_name === "Accounts Receivable") { %}
|
||||
{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
|
||||
<td></td>
|
||||
{% } %}
|
||||
<td></td>
|
||||
|
||||
@@ -44,6 +44,13 @@ frappe.query_reports["Accounts Receivable"] = {
|
||||
"default": "90",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"range4",
|
||||
"label": __("Ageing Range 4"),
|
||||
"fieldtype": "Int",
|
||||
"default": "120",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"finance_book",
|
||||
"label": __("Finance Book"),
|
||||
|
||||
@@ -100,11 +100,14 @@ class ReceivablePayableReport(object):
|
||||
self.filters["range2"] = "60"
|
||||
if not "range3" in self.filters:
|
||||
self.filters["range3"] = "90"
|
||||
if not "range4" in self.filters:
|
||||
self.filters["range4"] = "120"
|
||||
|
||||
for label in ("0-{range1}".format(range1=self.filters["range1"]),
|
||||
"{range1}-{range2}".format(range1=cint(self.filters["range1"])+ 1, range2=self.filters["range2"]),
|
||||
"{range2}-{range3}".format(range2=cint(self.filters["range2"])+ 1, range3=self.filters["range3"]),
|
||||
"{range3}-{above}".format(range3=cint(self.filters["range3"])+ 1, above=_("Above"))):
|
||||
"{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
|
||||
"{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))):
|
||||
columns.append({
|
||||
"label": label,
|
||||
"fieldname":label,
|
||||
@@ -194,10 +197,9 @@ class ReceivablePayableReport(object):
|
||||
self.payment_term_map = self.get_payment_term_detail(voucher_nos)
|
||||
|
||||
for gle in gl_entries_data:
|
||||
if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers):
|
||||
if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers, return_entries):
|
||||
outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount(
|
||||
gle,self.filters.report_date, self.dr_or_cr, return_entries)
|
||||
|
||||
temp_outstanding_amt = outstanding_amount
|
||||
temp_credit_note_amt = credit_note_amount
|
||||
|
||||
@@ -329,18 +331,17 @@ class ReceivablePayableReport(object):
|
||||
entry_date = gle.posting_date
|
||||
|
||||
row += get_ageing_data(cint(self.filters.range1), cint(self.filters.range2),
|
||||
cint(self.filters.range3), self.age_as_on, entry_date, outstanding_amount)
|
||||
|
||||
cint(self.filters.range3), cint(self.filters.range4), self.age_as_on, entry_date, outstanding_amount)
|
||||
|
||||
# issue 6371-Ageing buckets should not have amounts if due date is not reached
|
||||
if self.filters.ageing_based_on == "Due Date" \
|
||||
and getdate(due_date) > getdate(self.filters.report_date):
|
||||
row[-1]=row[-2]=row[-3]=row[-4]=0
|
||||
row[-1]=row[-2]=row[-3]=row[-4]=row[-5]=0
|
||||
|
||||
if self.filters.ageing_based_on == "Supplier Invoice Date" \
|
||||
and getdate(bill_date) > getdate(self.filters.report_date):
|
||||
|
||||
row[-1]=row[-2]=row[-3]=row[-4]=0
|
||||
row[-1]=row[-2]=row[-3]=row[-4]=row[-5]=0
|
||||
|
||||
if self.filters.get(scrub(args.get("party_type"))):
|
||||
row.append(gle.account_currency)
|
||||
@@ -377,7 +378,7 @@ class ReceivablePayableReport(object):
|
||||
# returns a generator
|
||||
return self.get_gl_entries(party_type, report_date)
|
||||
|
||||
def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers):
|
||||
def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers, return_entries):
|
||||
return (
|
||||
# advance
|
||||
(not gle.against_voucher) or
|
||||
@@ -388,30 +389,37 @@ class ReceivablePayableReport(object):
|
||||
# sales invoice/purchase invoice
|
||||
(gle.against_voucher==gle.voucher_no and gle.get(dr_or_cr) > 0) or
|
||||
|
||||
# standalone credit notes
|
||||
(gle.against_voucher==gle.voucher_no and gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no)) or
|
||||
|
||||
# entries adjusted with future vouchers
|
||||
((gle.against_voucher_type, gle.against_voucher) in future_vouchers)
|
||||
)
|
||||
|
||||
def get_return_entries(self, party_type):
|
||||
doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
|
||||
return [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1})]
|
||||
return_entries = frappe._dict(frappe.get_all(doctype,
|
||||
filters={"is_return": 1, "docstatus": 1}, fields=["name", "return_against"], as_list=1))
|
||||
return return_entries
|
||||
|
||||
def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries):
|
||||
payment_amount, credit_note_amount = 0.0, 0.0
|
||||
reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit"
|
||||
|
||||
for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no):
|
||||
if getdate(e.posting_date) <= report_date and e.name!=gle.name:
|
||||
if getdate(e.posting_date) <= report_date \
|
||||
and (e.name!=gle.name or (e.voucher_no in return_entries and not return_entries.get(e.voucher_no))):
|
||||
|
||||
amount = flt(e.get(reverse_dr_or_cr), self.currency_precision) - flt(e.get(dr_or_cr), self.currency_precision)
|
||||
if e.voucher_no not in return_entries:
|
||||
payment_amount += amount
|
||||
else:
|
||||
credit_note_amount += amount
|
||||
|
||||
outstanding_amount = (flt((flt(gle.get(dr_or_cr), self.currency_precision)
|
||||
- flt(gle.get(reverse_dr_or_cr), self.currency_precision)
|
||||
- payment_amount - credit_note_amount), self.currency_precision))
|
||||
voucher_amount = flt(gle.get(dr_or_cr), self.currency_precision) - flt(gle.get(reverse_dr_or_cr), self.currency_precision)
|
||||
if gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no):
|
||||
voucher_amount = 0
|
||||
|
||||
outstanding_amount = flt((voucher_amount - payment_amount - credit_note_amount), self.currency_precision)
|
||||
credit_note_amount = flt(credit_note_amount, self.currency_precision)
|
||||
|
||||
return outstanding_amount, credit_note_amount, payment_amount
|
||||
@@ -481,13 +489,8 @@ class ReceivablePayableReport(object):
|
||||
conditions.append("company=%s")
|
||||
values.append(self.filters.company)
|
||||
|
||||
company_finance_book = erpnext.get_default_finance_book(self.filters.company)
|
||||
|
||||
if not self.filters.finance_book or (self.filters.finance_book == company_finance_book):
|
||||
if self.filters.finance_book:
|
||||
conditions.append("ifnull(finance_book,'') in (%s, '')")
|
||||
values.append(company_finance_book)
|
||||
elif self.filters.finance_book:
|
||||
conditions.append("ifnull(finance_book,'') = %s")
|
||||
values.append(self.filters.finance_book)
|
||||
|
||||
if self.filters.get(party_type_field):
|
||||
@@ -584,13 +587,13 @@ class ReceivablePayableReport(object):
|
||||
return payment_term_map
|
||||
|
||||
def get_chart_data(self, columns, data):
|
||||
ageing_columns = columns[self.ageing_col_idx_start : self.ageing_col_idx_start+4]
|
||||
ageing_columns = columns[self.ageing_col_idx_start : self.ageing_col_idx_start+5]
|
||||
|
||||
rows = []
|
||||
for d in data:
|
||||
rows.append(
|
||||
{
|
||||
'values': d[self.ageing_col_idx_start : self.ageing_col_idx_start+4]
|
||||
'values': d[self.ageing_col_idx_start : self.ageing_col_idx_start+5]
|
||||
}
|
||||
)
|
||||
|
||||
@@ -609,21 +612,22 @@ def execute(filters=None):
|
||||
}
|
||||
return ReceivablePayableReport(filters).run(args)
|
||||
|
||||
def get_ageing_data(first_range, second_range, third_range, age_as_on, entry_date, outstanding_amount):
|
||||
# [0-30, 30-60, 60-90, 90-above]
|
||||
outstanding_range = [0.0, 0.0, 0.0, 0.0]
|
||||
def get_ageing_data(first_range, second_range, third_range,
|
||||
fourth_range, age_as_on, entry_date, outstanding_amount):
|
||||
# [0-30, 30-60, 60-90, 90-120, 120-above]
|
||||
outstanding_range = [0.0, 0.0, 0.0, 0.0, 0.0]
|
||||
|
||||
if not (age_as_on and entry_date):
|
||||
return [0] + outstanding_range
|
||||
|
||||
age = (getdate(age_as_on) - getdate(entry_date)).days or 0
|
||||
index = None
|
||||
for i, days in enumerate([first_range, second_range, third_range]):
|
||||
for i, days in enumerate([first_range, second_range, third_range, fourth_range]):
|
||||
if age <= days:
|
||||
index = i
|
||||
break
|
||||
|
||||
if index is None: index = 3
|
||||
if index is None: index = 4
|
||||
outstanding_range[index] = outstanding_amount
|
||||
|
||||
return [age] + outstanding_range
|
||||
|
||||
@@ -44,6 +44,13 @@ frappe.query_reports["Accounts Receivable Summary"] = {
|
||||
"default": "90",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"range4",
|
||||
"label": __("Ageing Range 4"),
|
||||
"fieldtype": "Int",
|
||||
"default": "120",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"finance_book",
|
||||
"label": __("Finance Book"),
|
||||
|
||||
@@ -82,8 +82,15 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
"width": 160
|
||||
},
|
||||
{
|
||||
"label": _(str(self.filters.range3) + _("-Above")),
|
||||
"fieldname": scrub(str(self.filters.range3) + _("-Above")),
|
||||
"label": _(str(self.filters.range3) + "-" + str(self.filters.range4)),
|
||||
"fieldname": scrub(str(self.filters.range3) + "-" + str(self.filters.range4)),
|
||||
"fieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"width": 160
|
||||
},
|
||||
{
|
||||
"label": _(str(self.filters.range4) + _("-Above")),
|
||||
"fieldname": scrub(str(self.filters.range4) + _("-Above")),
|
||||
"fieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"width": 160
|
||||
@@ -152,7 +159,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
|
||||
row += [
|
||||
party_dict.invoiced_amt, paid_amt, party_dict.credit_amt, party_dict.outstanding_amt,
|
||||
party_dict.range1, party_dict.range2, party_dict.range3, party_dict.range4,
|
||||
party_dict.range1, party_dict.range2, party_dict.range3, party_dict.range4, party_dict.range5
|
||||
]
|
||||
|
||||
if args.get("party_type") == "Customer":
|
||||
@@ -178,6 +185,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
"range2": 0,
|
||||
"range3": 0,
|
||||
"range4": 0,
|
||||
"range5": 0,
|
||||
"sales_person": []
|
||||
})
|
||||
)
|
||||
@@ -209,7 +217,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
cols += ["bill_no", "bill_date"]
|
||||
|
||||
cols += ["invoiced_amt", "paid_amt", "credit_amt",
|
||||
"outstanding_amt", "age", "range1", "range2", "range3", "range4", "currency", "pdc/lc_date", "pdc/lc_ref",
|
||||
"outstanding_amt", "age", "range1", "range2", "range3", "range4", "range5", "currency", "pdc/lc_date", "pdc/lc_ref",
|
||||
"pdc/lc_amount"]
|
||||
|
||||
if args.get("party_type") == "Supplier":
|
||||
|
||||
@@ -31,11 +31,8 @@ def get_data(filters):
|
||||
|
||||
filters_data.append(["against_voucher", "in", assets])
|
||||
|
||||
company_finance_book = erpnext.get_default_finance_book(filters.get("company"))
|
||||
if (not filters.get('finance_book') or (filters.get('finance_book') == company_finance_book)):
|
||||
if filters.get("finance_book"):
|
||||
filters_data.append(["finance_book", "in", ['', filters.get('finance_book')]])
|
||||
elif filters.get("finance_book"):
|
||||
filters_data.append(["finance_book", "=", filters.get('finance_book')])
|
||||
|
||||
gl_entries = frappe.get_all('GL Entry',
|
||||
filters= filters_data,
|
||||
|
||||
@@ -101,7 +101,7 @@ def get_income_expense_data(companies, fiscal_year, filters):
|
||||
net_profit_loss = get_net_profit_loss(income, expense, companies, filters.company, company_currency, True)
|
||||
|
||||
return income, expense, net_profit_loss
|
||||
|
||||
|
||||
def get_cash_flow_data(fiscal_year, companies, filters):
|
||||
cash_flow_accounts = get_cash_flow_accounts()
|
||||
|
||||
@@ -123,7 +123,7 @@ def get_cash_flow_data(fiscal_year, companies, filters):
|
||||
# add first net income in operations section
|
||||
if net_profit_loss:
|
||||
net_profit_loss.update({
|
||||
"indent": 1,
|
||||
"indent": 1,
|
||||
"parent_account": cash_flow_accounts[0]['section_header']
|
||||
})
|
||||
data.append(net_profit_loss)
|
||||
@@ -327,7 +327,7 @@ def set_gl_entries_by_account(from_date, to_date, root_lft, root_rgt, filters, g
|
||||
accounts_by_name, ignore_closing_entries=False):
|
||||
"""Returns a dict like { "account": [gl entries], ... }"""
|
||||
|
||||
company_lft, company_rgt = frappe.get_cached_value('Company',
|
||||
company_lft, company_rgt = frappe.get_cached_value('Company',
|
||||
filters.get('company'), ["lft", "rgt"])
|
||||
|
||||
additional_conditions = get_additional_conditions(from_date, ignore_closing_entries, filters)
|
||||
@@ -354,7 +354,8 @@ def set_gl_entries_by_account(from_date, to_date, root_lft, root_rgt, filters, g
|
||||
"to_date": to_date,
|
||||
"lft": root_lft,
|
||||
"rgt": root_rgt,
|
||||
"company": d.name
|
||||
"company": d.name,
|
||||
"finance_book": filters.get("finance_book")
|
||||
},
|
||||
as_dict=True)
|
||||
|
||||
@@ -384,14 +385,8 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
||||
if from_date:
|
||||
additional_conditions.append("gl.posting_date >= %(from_date)s")
|
||||
|
||||
company_finance_book = erpnext.get_default_finance_book(filters.get("company"))
|
||||
|
||||
if not filters.get('finance_book') or (filters.get('finance_book') == company_finance_book):
|
||||
additional_conditions.append("ifnull(finance_book, '') in ('%s', '')" %
|
||||
frappe.db.escape(company_finance_book))
|
||||
elif filters.get("finance_book"):
|
||||
additional_conditions.append("ifnull(finance_book, '') = '%s' " %
|
||||
frappe.db.escape(filters.get("finance_book")))
|
||||
if filters.get("finance_book"):
|
||||
additional_conditions.append("ifnull(finance_book, '') in (%(finance_book)s, '')")
|
||||
|
||||
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
|
||||
|
||||
|
||||
@@ -184,12 +184,8 @@ class PartyLedgerSummaryReport(object):
|
||||
if self.filters.company:
|
||||
conditions.append("gle.company=%(company)s")
|
||||
|
||||
self.filters.company_finance_book = erpnext.get_default_finance_book(self.filters.company)
|
||||
|
||||
if not self.filters.finance_book or (self.filters.finance_book == self.filters.company_finance_book):
|
||||
conditions.append("ifnull(finance_book,'') in (%(company_finance_book)s, '')")
|
||||
elif self.filters.finance_book:
|
||||
conditions.append("ifnull(finance_book,'') = %(finance_book)s")
|
||||
if self.filters.finance_book:
|
||||
conditions.append("ifnull(finance_book,'') in (%(finance_book)s, '')")
|
||||
|
||||
if self.filters.get("party"):
|
||||
conditions.append("party=%(party)s")
|
||||
|
||||
@@ -321,7 +321,10 @@ def sort_accounts(accounts, is_root=False, key="name"):
|
||||
"""Sort root types as Asset, Liability, Equity, Income, Expense"""
|
||||
|
||||
def compare_accounts(a, b):
|
||||
if is_root:
|
||||
if re.split('\W+', a[key])[0].isdigit():
|
||||
# if chart of accounts is numbered, then sort by number
|
||||
return cmp(a[key], b[key])
|
||||
elif is_root:
|
||||
if a.report_type != b.report_type and a.report_type == "Balance Sheet":
|
||||
return -1
|
||||
if a.root_type != b.root_type and a.root_type == "Asset":
|
||||
@@ -330,10 +333,6 @@ def sort_accounts(accounts, is_root=False, key="name"):
|
||||
return -1
|
||||
if a.root_type == "Income" and b.root_type == "Expense":
|
||||
return -1
|
||||
else:
|
||||
if re.split('\W+', a[key])[0].isdigit():
|
||||
# if chart of accounts is numbered, then sort by number
|
||||
return cmp(a[key], b[key])
|
||||
return 1
|
||||
|
||||
accounts.sort(key = functools.cmp_to_key(compare_accounts))
|
||||
@@ -359,7 +358,8 @@ def set_gl_entries_by_account(
|
||||
"from_date": from_date,
|
||||
"to_date": to_date,
|
||||
"cost_center": filters.cost_center,
|
||||
"project": filters.project
|
||||
"project": filters.project,
|
||||
"finance_book": filters.get("finance_book")
|
||||
},
|
||||
as_dict=True)
|
||||
|
||||
@@ -392,14 +392,8 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
||||
filters.cost_center = get_cost_centers_with_children(filters.cost_center)
|
||||
additional_conditions.append("cost_center in %(cost_center)s")
|
||||
|
||||
company_finance_book = erpnext.get_default_finance_book(filters.get("company"))
|
||||
|
||||
if not filters.get('finance_book') or (filters.get('finance_book') == company_finance_book):
|
||||
additional_conditions.append("ifnull(finance_book, '') in ('%s', '')" %
|
||||
frappe.db.escape(company_finance_book))
|
||||
elif filters.get("finance_book"):
|
||||
additional_conditions.append("ifnull(finance_book, '') = '%s' " %
|
||||
frappe.db.escape(filters.get("finance_book")))
|
||||
if filters.get("finance_book"):
|
||||
additional_conditions.append("ifnull(finance_book, '') in (%(finance_book)s, '')")
|
||||
|
||||
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
|
||||
|
||||
|
||||
@@ -211,6 +211,11 @@ frappe.query_reports["General Ledger"] = {
|
||||
"label": __("Currency"),
|
||||
"fieldtype": "Select",
|
||||
"options": erpnext.get_presentation_currency_list()
|
||||
},
|
||||
{
|
||||
"fieldname": "show_opening_entries",
|
||||
"label": __("Show Opening Entries"),
|
||||
"fieldtype": "Check"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -186,12 +186,8 @@ def get_conditions(filters):
|
||||
if filters.get("project"):
|
||||
conditions.append("project in %(project)s")
|
||||
|
||||
company_finance_book = erpnext.get_default_finance_book(filters.get("company"))
|
||||
if not filters.get("finance_book") or (filters.get("finance_book") == company_finance_book):
|
||||
filters['finance_book'] = company_finance_book
|
||||
if filters.get("finance_book"):
|
||||
conditions.append("ifnull(finance_book, '') in (%(finance_book)s, '')")
|
||||
elif filters.get("finance_book"):
|
||||
conditions.append("ifnull(finance_book, '') = %(finance_book)s")
|
||||
|
||||
from frappe.desk.reportview import build_match_conditions
|
||||
match_conditions = build_match_conditions("GL Entry")
|
||||
@@ -287,7 +283,8 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
|
||||
|
||||
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
|
||||
for gle in gl_entries:
|
||||
if gle.posting_date < from_date or cstr(gle.is_opening) == "Yes":
|
||||
if (gle.posting_date < from_date or
|
||||
(cstr(gle.is_opening) == "Yes" and not filters.get("show_opening_entries"))):
|
||||
update_value_in_dict(gle_map[gle.get(group_by)].totals, 'opening', gle)
|
||||
update_value_in_dict(totals, 'opening', gle)
|
||||
|
||||
|
||||
@@ -23,6 +23,12 @@ frappe.query_reports["Gross Profit"] = {
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.defaults.get_user_default("year_end_date")
|
||||
},
|
||||
{
|
||||
"fieldname":"sales_invoice",
|
||||
"label": __("Sales Invoice"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Sales Invoice"
|
||||
},
|
||||
{
|
||||
"fieldname":"group_by",
|
||||
"label": __("Group By"),
|
||||
|
||||
@@ -65,7 +65,7 @@ def get_columns(group_wise_columns, filters):
|
||||
"warehouse": _("Warehouse") + ":Link/Warehouse",
|
||||
"qty": _("Qty") + ":Float",
|
||||
"base_rate": _("Avg. Selling Rate") + ":Currency/currency",
|
||||
"buying_rate": _("Avg. Buying Rate") + ":Currency/currency",
|
||||
"buying_rate": _("Valuation Rate") + ":Currency/currency",
|
||||
"base_amount": _("Selling Amount") + ":Currency/currency",
|
||||
"buying_amount": _("Buying Amount") + ":Currency/currency",
|
||||
"gross_profit": _("Gross Profit") + ":Currency/currency",
|
||||
@@ -302,6 +302,12 @@ class GrossProfitGenerator(object):
|
||||
sales_person_cols = ""
|
||||
sales_team_table = ""
|
||||
|
||||
if self.filters.get("sales_invoice"):
|
||||
conditions += " and `tabSales Invoice`.name = %(sales_invoice)s"
|
||||
|
||||
if self.filters.get("item_code"):
|
||||
conditions += " and `tabSales Invoice Item`.item_code = %(item_code)s"
|
||||
|
||||
self.si_list = frappe.db.sql("""
|
||||
select
|
||||
`tabSales Invoice Item`.parenttype, `tabSales Invoice Item`.parent,
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Inactive Sales Items"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname: "territory",
|
||||
label: __("Territory"),
|
||||
fieldtype: "Link",
|
||||
options: "Territory",
|
||||
reqd: 1,
|
||||
},
|
||||
{
|
||||
fieldname: "item",
|
||||
label: __("Item"),
|
||||
fieldtype: "Link",
|
||||
options: "Item"
|
||||
},
|
||||
{
|
||||
fieldname: "item_group",
|
||||
label: __("Item Group"),
|
||||
fieldtype: "Link",
|
||||
options: "Item Group"
|
||||
},
|
||||
{
|
||||
fieldname: "based_on",
|
||||
label: __("Based On"),
|
||||
fieldtype: "Select",
|
||||
options: "Sales Order\nSales Invoice",
|
||||
default: "Sales Order"
|
||||
},
|
||||
{
|
||||
fieldname: "days",
|
||||
label: __("Days Since Last order"),
|
||||
fieldtype: "Select",
|
||||
options: [30, 60, 90],
|
||||
default: 30
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"creation": "2019-05-01 12:59:52.018850",
|
||||
"disable_prepared_report": 0,
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2019-05-01 13:00:26.545278",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Inactive Sales Items",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Sales Invoice",
|
||||
"report_name": "Inactive Sales Items",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Accounts User"
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager"
|
||||
},
|
||||
{
|
||||
"role": "Auditor"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import getdate, add_days, today, cint
|
||||
from frappe import _
|
||||
|
||||
def execute(filters=None):
|
||||
columns = get_columns()
|
||||
data = get_data(filters)
|
||||
return columns, data
|
||||
|
||||
def get_columns():
|
||||
columns = [
|
||||
{
|
||||
"fieldname": "territory",
|
||||
"fieldtype": "Link",
|
||||
"label": _("Territory"),
|
||||
"options": "Territory",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"fieldname": "item_group",
|
||||
"fieldtype": "Link",
|
||||
"label": _("Item Group"),
|
||||
"options": "Item Group",
|
||||
"width": 150
|
||||
},
|
||||
{
|
||||
"fieldname": "item",
|
||||
"fieldtype": "Link",
|
||||
"options": "Item",
|
||||
"label": "Item",
|
||||
"width": 150
|
||||
},
|
||||
{
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Data",
|
||||
"label": _("Item Name"),
|
||||
"width": 150
|
||||
},
|
||||
|
||||
{
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"label": _("Customer"),
|
||||
"options": "Customer",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"fieldname": "last_order_date",
|
||||
"fieldtype": "Date",
|
||||
"label": _("Last Order Date"),
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"fieldname": "qty",
|
||||
"fieldtype": "Float",
|
||||
"label": _("Quantity"),
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"fieldname": "days_since_last_order",
|
||||
"fieldtype": "Int",
|
||||
"label": _("Days Since Last Order"),
|
||||
"width": 100
|
||||
},
|
||||
]
|
||||
|
||||
return columns
|
||||
|
||||
|
||||
def get_data(filters):
|
||||
data = []
|
||||
items = get_items(filters)
|
||||
territories = get_territories(filters)
|
||||
sales_invoice_data = get_sales_details(filters)
|
||||
|
||||
for territory in territories:
|
||||
for item in items:
|
||||
row = {
|
||||
"territory": territory.name,
|
||||
"item_group": item.item_group,
|
||||
"item": item.item_code,
|
||||
"item_name": item.item_name
|
||||
}
|
||||
|
||||
if sales_invoice_data.get((territory.name,item.item_code)):
|
||||
item_obj = sales_invoice_data[(territory.name,item.item_code)]
|
||||
if item_obj.days_since_last_order > cint(filters['days']):
|
||||
row.update({
|
||||
"territory": item_obj.territory,
|
||||
"customer": item_obj.customer,
|
||||
"last_order_date": item_obj.last_order_date,
|
||||
"qty": item_obj.qty,
|
||||
"days_since_last_order": item_obj.days_since_last_order
|
||||
})
|
||||
else:
|
||||
continue
|
||||
|
||||
data.append(row)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_sales_details(filters):
|
||||
data = []
|
||||
item_details_map = {}
|
||||
|
||||
date_field = "s.transaction_date" if filters["based_on"] == "Sales Order" else "s.posting_date"
|
||||
|
||||
sales_data = frappe.db.sql("""
|
||||
select s.territory, s.customer, si.item_group, si.item_code, si.qty, {date_field} as last_order_date,
|
||||
DATEDIFF(CURDATE(), {date_field}) as days_since_last_order
|
||||
from `tab{doctype}` s, `tab{doctype} Item` si
|
||||
where s.name = si.parent and s.docstatus = 1
|
||||
order by days_since_last_order """ #nosec
|
||||
.format(date_field = date_field, doctype = filters['based_on']), as_dict=1)
|
||||
|
||||
for d in sales_data:
|
||||
item_details_map.setdefault((d.territory,d.item_code), d)
|
||||
|
||||
return item_details_map
|
||||
|
||||
def get_territories(filters):
|
||||
|
||||
filter_dict = {}
|
||||
if filters.get("territory"):
|
||||
filter_dict.update({'name': filters['territory']})
|
||||
|
||||
territories = frappe.get_all("Territory", fields=["name"], filters=filter_dict)
|
||||
|
||||
return territories
|
||||
|
||||
def get_items(filters):
|
||||
filters_dict = {
|
||||
"disabled": 0,
|
||||
"is_stock_item": 1
|
||||
}
|
||||
|
||||
if filters.get("item_group"):
|
||||
filters_dict.update({
|
||||
"item_group": filters["item_group"]
|
||||
})
|
||||
|
||||
if filters.get("item"):
|
||||
filters_dict.update({
|
||||
"name": filters["item"]
|
||||
})
|
||||
|
||||
items = frappe.get_all("Item", fields=["name", "item_group", "item_name", "item_code"], filters=filters_dict, order_by="name")
|
||||
|
||||
return items
|
||||
@@ -157,7 +157,7 @@ def get_conditions(filters):
|
||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
||||
where parent=`tabSales Invoice`.name
|
||||
and ifnull(`tabSales Invoice Item`.brand, '') = %(brand)s)"""
|
||||
|
||||
|
||||
if filters.get("item_group"):
|
||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
||||
where parent=`tabSales Invoice`.name
|
||||
@@ -171,7 +171,7 @@ def get_invoices(filters, additional_query_columns):
|
||||
|
||||
conditions = get_conditions(filters)
|
||||
return frappe.db.sql("""
|
||||
select name, posting_date, debit_to, project, customer,
|
||||
select name, posting_date, debit_to, project, customer,
|
||||
customer_name, owner, remarks, territory, tax_id, customer_group,
|
||||
base_net_total, base_grand_total, base_rounded_total, outstanding_amount {0}
|
||||
from `tabSales Invoice`
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"apply_user_permissions": 1,
|
||||
"creation": "2017-12-27 16:15:52.615453",
|
||||
"disable_prepared_report": 0,
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2017-12-27 16:46:54.422356",
|
||||
"modified": "2019-04-19 10:50:36.061588",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Share Ledger",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Share Transfer",
|
||||
"report_name": "Share Ledger",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Administrator"
|
||||
},
|
||||
{
|
||||
"role": "System Manager"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -112,13 +112,15 @@ def convert_to_presentation_currency(gl_entries, currency_info):
|
||||
|
||||
if entry.get('debit'):
|
||||
entry['debit'] = converted_value
|
||||
else:
|
||||
|
||||
if entry.get('credit'):
|
||||
entry['credit'] = converted_value
|
||||
|
||||
elif account_currency == presentation_currency:
|
||||
if entry.get('debit'):
|
||||
entry['debit'] = debit_in_account_currency
|
||||
else:
|
||||
|
||||
if entry.get('credit'):
|
||||
entry['credit'] = credit_in_account_currency
|
||||
|
||||
converted_gl_list.append(entry)
|
||||
@@ -133,3 +135,25 @@ def get_appropriate_company(filters):
|
||||
company = get_default_company()
|
||||
|
||||
return company
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_invoiced_item_gross_margin(sales_invoice=None, item_code=None, company=None, with_item_data=False):
|
||||
from erpnext.accounts.report.gross_profit.gross_profit import GrossProfitGenerator
|
||||
|
||||
sales_invoice = sales_invoice or frappe.form_dict.get('sales_invoice')
|
||||
item_code = item_code or frappe.form_dict.get('item_code')
|
||||
company = company or frappe.get_cached_value("Sales Invoice", sales_invoice, 'company')
|
||||
|
||||
filters = {
|
||||
'sales_invoice': sales_invoice,
|
||||
'item_code': item_code,
|
||||
'company': company,
|
||||
'group_by': 'Invoice'
|
||||
}
|
||||
|
||||
gross_profit_data = GrossProfitGenerator(filters)
|
||||
result = gross_profit_data.grouped_data
|
||||
if not with_item_data:
|
||||
result = sum([d.gross_profit for d in result])
|
||||
|
||||
return result
|
||||
|
||||
@@ -333,6 +333,9 @@ def reconcile_against_document(args):
|
||||
doc = frappe.get_doc(d.voucher_type, d.voucher_no)
|
||||
doc.make_gl_entries(cancel = 0, adv_adj =1)
|
||||
|
||||
if d.voucher_type in ('Payment Entry', 'Journal Entry'):
|
||||
doc.update_expense_claim()
|
||||
|
||||
def check_if_advance_entry_modified(args):
|
||||
"""
|
||||
check if there is already a voucher reference
|
||||
@@ -375,9 +378,9 @@ def check_if_advance_entry_modified(args):
|
||||
|
||||
def validate_allocated_amount(args):
|
||||
if args.get("allocated_amount") < 0:
|
||||
throw(_("Allocated amount can not be negative"))
|
||||
throw(_("Allocated amount cannot be negative"))
|
||||
elif args.get("allocated_amount") > args.get("unadjusted_amount"):
|
||||
throw(_("Allocated amount can not greater than unadjusted amount"))
|
||||
throw(_("Allocated amount cannot be greater than unadjusted amount"))
|
||||
|
||||
def update_reference_in_journal_entry(d, jv_obj):
|
||||
"""
|
||||
@@ -615,7 +618,7 @@ def get_held_invoices(party_type, party):
|
||||
return held_invoices
|
||||
|
||||
|
||||
def get_outstanding_invoices(party_type, party, account, condition=None, limit=None):
|
||||
def get_outstanding_invoices(party_type, party, account, condition=None):
|
||||
outstanding_invoices = []
|
||||
precision = frappe.get_precision("Sales Invoice", "outstanding_amount") or 2
|
||||
|
||||
@@ -628,7 +631,6 @@ def get_outstanding_invoices(party_type, party, account, condition=None, limit=N
|
||||
|
||||
invoice = 'Sales Invoice' if erpnext.get_party_account_type(party_type) == 'Receivable' else 'Purchase Invoice'
|
||||
held_invoices = get_held_invoices(party_type, party)
|
||||
limit_cond = "limit %s" % limit if limit else ""
|
||||
|
||||
invoice_list = frappe.db.sql("""
|
||||
select
|
||||
@@ -643,11 +645,10 @@ def get_outstanding_invoices(party_type, party, account, condition=None, limit=N
|
||||
and (against_voucher = '' or against_voucher is null))
|
||||
or (voucher_type not in ('Journal Entry', 'Payment Entry')))
|
||||
group by voucher_type, voucher_no
|
||||
order by posting_date, name {limit_cond}""".format(
|
||||
order by posting_date, name""".format(
|
||||
dr_or_cr=dr_or_cr,
|
||||
invoice = invoice,
|
||||
condition=condition or "",
|
||||
limit_cond = limit_cond
|
||||
condition=condition or ""
|
||||
), {
|
||||
"party_type": party_type,
|
||||
"party": party,
|
||||
|
||||
@@ -296,6 +296,12 @@ frappe.ui.form.on('Asset', {
|
||||
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
|
||||
},
|
||||
|
||||
gross_purchase_amount: function(frm) {
|
||||
frm.doc.finance_books.forEach(d => {
|
||||
frm.events.set_depreciation_rate(frm, d);
|
||||
})
|
||||
},
|
||||
|
||||
set_depreciation_rate: function(frm, row) {
|
||||
if (row.total_number_of_depreciations && row.frequency_of_depreciation) {
|
||||
frappe.call({
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -101,7 +101,7 @@ class Asset(AccountsController):
|
||||
|
||||
def set_depreciation_rate(self):
|
||||
for d in self.get("finance_books"):
|
||||
d.rate_of_depreciation = self.get_depreciation_rate(d)
|
||||
d.rate_of_depreciation = self.get_depreciation_rate(d, on_validate=True)
|
||||
|
||||
def make_depreciation_schedule(self):
|
||||
depreciation_method = [d.depreciation_method for d in self.finance_books]
|
||||
@@ -125,7 +125,7 @@ class Asset(AccountsController):
|
||||
no_of_depreciations * cint(d.frequency_of_depreciation))
|
||||
|
||||
total_days = date_diff(end_date, self.available_for_use_date)
|
||||
rate_per_day = value_after_depreciation / total_days
|
||||
rate_per_day = (value_after_depreciation - d.get("expected_value_after_useful_life")) / total_days
|
||||
|
||||
number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \
|
||||
cint(self.number_of_depreciations_booked)
|
||||
@@ -291,8 +291,8 @@ class Asset(AccountsController):
|
||||
|
||||
def validate_expected_value_after_useful_life(self):
|
||||
for row in self.get('finance_books'):
|
||||
accumulated_depreciation_after_full_schedule = \
|
||||
max([d.accumulated_depreciation_amount for d in self.get("schedules") if d.finance_book_id == row.idx])
|
||||
accumulated_depreciation_after_full_schedule = max([d.accumulated_depreciation_amount
|
||||
for d in self.get("schedules") if cint(d.finance_book_id) == row.idx])
|
||||
|
||||
asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) -
|
||||
flt(accumulated_depreciation_after_full_schedule),
|
||||
@@ -403,7 +403,7 @@ class Asset(AccountsController):
|
||||
make_gl_entries(gl_entries)
|
||||
self.db_set('booked_fixed_asset', 1)
|
||||
|
||||
def get_depreciation_rate(self, args):
|
||||
def get_depreciation_rate(self, args, on_validate=False):
|
||||
if isinstance(args, string_types):
|
||||
args = json.loads(args)
|
||||
|
||||
@@ -420,7 +420,10 @@ class Asset(AccountsController):
|
||||
if args.get("depreciation_method") == 'Double Declining Balance':
|
||||
return 200.0 / args.get("total_number_of_depreciations")
|
||||
|
||||
if args.get("depreciation_method") == "Written Down Value" and not args.get("rate_of_depreciation"):
|
||||
if args.get("depreciation_method") == "Written Down Value":
|
||||
if args.get("rate_of_depreciation") and on_validate:
|
||||
return args.get("rate_of_depreciation")
|
||||
|
||||
no_of_years = flt(args.get("total_number_of_depreciations") * flt(args.get("frequency_of_depreciation"))) / 12
|
||||
value = flt(args.get("expected_value_after_useful_life")) / flt(self.gross_purchase_amount)
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user