Extracted interfaces for UI model classes Customer, BankAccount and AccountTransaction. So entities can implement these interfaces directly, there's no need for mapping anymore
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 342 B |
After Width: | Height: | Size: 493 B |
After Width: | Height: | Size: 687 B |
After Width: | Height: | Size: 436 B |
After Width: | Height: | Size: 684 B |
After Width: | Height: | Size: 926 B |
After Width: | Height: | Size: 493 B |
After Width: | Height: | Size: 840 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 828 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,21 @@
|
||||||
|
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0)">
|
||||||
|
<rect width="60" height="60" fill="white"/>
|
||||||
|
<rect width="60" height="60" fill="white"/>
|
||||||
|
<circle cx="29.9999" cy="30" r="25.9091" fill="black" fill-opacity="0.09"/>
|
||||||
|
<circle cx="29.9999" cy="30" r="25.6591" stroke="#2869BF" stroke-opacity="0.04" stroke-width="0.5"/>
|
||||||
|
<circle cx="30.0001" cy="30" r="16.3636" fill="black" fill-opacity="0.09"/>
|
||||||
|
<circle cx="30.0001" cy="30" r="16.1136" stroke="#2869BF" stroke-opacity="0.04" stroke-width="0.5"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.25 0H29.75V29.75H0V30.25H29.75V60H30.25V30.25H60V29.75H30.25V0Z" fill="#6277A1" fill-opacity="0.1"/>
|
||||||
|
<path d="M0 0L60 0L60 60L0 60L0 0Z" fill="#003832"/>
|
||||||
|
<path d="M16.2969 18.9254C16.2969 17.9348 17.022 17.0935 18.0018 16.9473L29.5243 15.2286C29.7173 15.1998 29.9135 15.1994 30.1067 15.2275L41.9916 16.953C42.9749 17.0957 43.7043 17.9387 43.7043 18.9322V20.963C43.7043 22.0675 42.8089 22.963 41.7043 22.963L18.2969 22.963C17.1923 22.963 16.2969 22.0675 16.2969 20.963V18.9254Z" fill="#77A83F"/>
|
||||||
|
<rect x="16.2961" y="25.5555" width="7.40741" height="19.2593" rx="2" fill="#079326"/>
|
||||||
|
<rect x="26.2961" y="25.5555" width="7.40741" height="19.2593" rx="2" fill="#68A93D"/>
|
||||||
|
<rect x="36.2961" y="25.5555" width="7.40741" height="19.2593" rx="2" fill="#CCFFB4"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0">
|
||||||
|
<rect width="60" height="60" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 619 B |
After Width: | Height: | Size: 838 B |
After Width: | Height: | Size: 822 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.0 KiB |
|
@ -0,0 +1,22 @@
|
||||||
|
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect width="60" height="60" fill="white"/>
|
||||||
|
<rect width="60" height="60" fill="white"/>
|
||||||
|
<circle cx="29.9999" cy="30" r="25.9091" fill="black" fill-opacity="0.09"/>
|
||||||
|
<circle cx="29.9999" cy="30" r="25.6591" stroke="#2869BF" stroke-opacity="0.04" stroke-width="0.5"/>
|
||||||
|
<circle cx="30.0001" cy="30" r="16.3636" fill="black" fill-opacity="0.09"/>
|
||||||
|
<circle cx="30.0001" cy="30" r="16.1136" stroke="#2869BF" stroke-opacity="0.04" stroke-width="0.5"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.25 0H29.75V29.75H0V30.25H29.75V60H30.25V30.25H60V29.75H30.25V0Z" fill="#6277A1" fill-opacity="0.1"/>
|
||||||
|
<rect width="60" height="60" fill="white"/>
|
||||||
|
<rect width="60" height="60" fill="white"/>
|
||||||
|
<circle cx="29.9999" cy="30" r="25.9091" fill="black" fill-opacity="0.09"/>
|
||||||
|
<circle cx="29.9999" cy="30" r="25.6591" stroke="#2869BF" stroke-opacity="0.04" stroke-width="0.5"/>
|
||||||
|
<circle cx="30.0001" cy="30" r="16.3636" fill="black" fill-opacity="0.09"/>
|
||||||
|
<circle cx="30.0001" cy="30" r="16.1136" stroke="#2869BF" stroke-opacity="0.04" stroke-width="0.5"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.25 0H29.75V29.75H0V30.25H29.75V60H30.25V30.25H60V29.75H30.25V0Z" fill="#6277A1" fill-opacity="0.1"/>
|
||||||
|
<rect width="60" height="60" fill="#003832"/>
|
||||||
|
<path d="M30.0012 22.5524C30.0012 21.8764 30.4961 21.3022 31.1647 21.2025L39.0278 20.0296C39.1595 20.01 39.2934 20.0097 39.4252 20.0289L47.5357 21.2064C48.2067 21.3038 48.7044 21.879 48.7044 22.557V23.9428C48.7044 24.6966 48.0934 25.3077 47.3396 25.3077L31.366 25.3077C30.6123 25.3077 30.0012 24.6966 30.0012 23.9428V22.5524Z" fill="#77A83F"/>
|
||||||
|
<rect x="30" y="27.0769" width="5.05492" height="13.1428" rx="1.36483" fill="#079326"/>
|
||||||
|
<rect x="36.824" y="27.0769" width="5.05492" height="13.1428" rx="1.36483" fill="#68A93D"/>
|
||||||
|
<rect x="43.6482" y="27.0769" width="5.05492" height="13.1428" rx="1.36483" fill="#CCFFB4"/>
|
||||||
|
<path d="M11.317 39V21.5677H17.5787C19.8216 21.5677 21.5258 21.9788 22.6911 22.8009C23.8644 23.623 24.4511 24.8163 24.4511 26.3807C24.4511 27.2827 24.2436 28.0529 23.8285 28.6915C23.4135 29.33 22.8028 29.8009 21.9967 30.1043C22.9066 30.3437 23.605 30.7907 24.0919 31.4452C24.5788 32.0997 24.8222 32.8979 24.8222 33.8398C24.8222 35.5479 24.2795 36.8329 23.194 37.695C22.1164 38.549 20.5161 38.984 18.3929 39H11.317ZM15.5194 31.5889V35.7674H18.2732C19.0314 35.7674 19.6141 35.5958 20.0212 35.2525C20.4283 34.9013 20.6318 34.4105 20.6318 33.7799C20.6318 32.3272 19.9094 31.5969 18.4647 31.5889H15.5194ZM15.5194 28.8351H17.7104C18.6284 28.8272 19.2829 28.6595 19.674 28.3323C20.0651 28.005 20.2606 27.5221 20.2606 26.8836C20.2606 26.1493 20.0491 25.6225 19.6261 25.3032C19.203 24.9759 18.5206 24.8123 17.5787 24.8123H15.5194V28.8351Z" fill="#77A83F"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
|
@ -0,0 +1,362 @@
|
||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 0.000000 12.840942 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
1.279276 25.159058 m
|
||||||
|
0.572751 25.159058 0.000000 24.586306 0.000000 23.879782 c
|
||||||
|
0.000000 17.483404 l
|
||||||
|
0.000000 1.279245 l
|
||||||
|
0.000000 0.572721 0.572751 -0.000031 1.279276 -0.000031 c
|
||||||
|
5.221627 -0.000031 l
|
||||||
|
5.221627 2.558521 l
|
||||||
|
2.558551 2.558521 l
|
||||||
|
2.558551 17.483404 l
|
||||||
|
2.558551 22.600506 l
|
||||||
|
36.028580 22.600506 l
|
||||||
|
36.028580 20.894806 l
|
||||||
|
38.587132 20.894806 l
|
||||||
|
38.587132 23.879782 l
|
||||||
|
38.587132 24.586306 38.014378 25.159058 37.307854 25.159058 c
|
||||||
|
1.279276 25.159058 l
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 3.942383 9.056763 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
1.279276 25.105347 m
|
||||||
|
36.988125 25.105347 l
|
||||||
|
37.327412 25.105347 37.652798 24.970568 37.892708 24.730656 c
|
||||||
|
38.132618 24.490746 38.267403 24.165356 38.267403 23.826071 c
|
||||||
|
38.267403 10.402944 l
|
||||||
|
37.452763 10.640730 36.596001 10.804845 35.708851 10.885599 c
|
||||||
|
35.708851 22.546795 l
|
||||||
|
2.558552 22.546795 l
|
||||||
|
2.558552 2.558540 l
|
||||||
|
23.013508 2.558540 l
|
||||||
|
22.961720 2.192711 22.935091 1.820532 22.935091 1.443214 c
|
||||||
|
22.935091 0.952564 22.980118 0.470600 23.066944 -0.000010 c
|
||||||
|
1.279276 -0.000010 l
|
||||||
|
0.939991 -0.000010 0.614603 0.134769 0.374692 0.374680 c
|
||||||
|
0.134781 0.614590 0.000000 0.939981 0.000000 1.279266 c
|
||||||
|
0.000000 23.826071 l
|
||||||
|
0.000000 24.165356 0.134781 24.490746 0.374692 24.730656 c
|
||||||
|
0.614603 24.970568 0.939991 25.105347 1.279276 25.105347 c
|
||||||
|
h
|
||||||
|
23.255920 6.382050 m
|
||||||
|
22.035740 5.566751 20.601198 5.131590 19.133701 5.131590 c
|
||||||
|
17.166679 5.134298 15.280995 5.916893 13.890100 7.307789 c
|
||||||
|
12.499204 8.698685 11.716607 10.584367 11.713900 12.551389 c
|
||||||
|
11.713900 14.018887 12.149064 15.453429 12.964362 16.673609 c
|
||||||
|
13.779660 17.893787 14.938475 18.844801 16.294266 19.406387 c
|
||||||
|
17.650057 19.967976 19.141930 20.114914 20.581230 19.828619 c
|
||||||
|
22.020531 19.542324 23.342613 18.835655 24.380291 17.797979 c
|
||||||
|
25.417969 16.760302 26.124636 15.438218 26.410931 13.998919 c
|
||||||
|
26.697226 12.559619 26.550285 11.067746 25.988699 9.711955 c
|
||||||
|
25.427113 8.356165 24.476101 7.197348 23.255920 6.382050 c
|
||||||
|
h
|
||||||
|
21.834467 16.593369 m
|
||||||
|
21.035038 17.127529 20.095165 17.412636 19.133701 17.412636 c
|
||||||
|
19.133701 17.414341 l
|
||||||
|
17.844608 17.412762 16.608788 16.899853 15.697420 15.988167 c
|
||||||
|
14.786053 15.076480 14.273580 13.840483 14.272451 12.551389 c
|
||||||
|
14.272451 11.589925 14.557560 10.650051 15.091721 9.850623 c
|
||||||
|
15.625881 9.051195 16.385103 8.428120 17.273380 8.060183 c
|
||||||
|
18.161657 7.692245 19.139093 7.595976 20.082083 7.783548 c
|
||||||
|
21.025072 7.971121 21.891266 8.434109 22.571123 9.113967 c
|
||||||
|
23.250980 9.793824 23.713966 10.660017 23.901539 11.603006 c
|
||||||
|
24.089111 12.545996 23.992846 13.523432 23.624908 14.411709 c
|
||||||
|
23.256971 15.299986 22.633896 16.059208 21.834467 16.593369 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 8.500000 27.750000 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.000000 1.250000 m
|
||||||
|
0.000000 1.940356 0.559644 2.500000 1.250000 2.500000 c
|
||||||
|
5.250000 2.500000 l
|
||||||
|
5.940356 2.500000 6.500000 1.940356 6.500000 1.250000 c
|
||||||
|
6.500000 0.559644 5.940356 0.000000 5.250000 0.000000 c
|
||||||
|
1.250000 0.000000 l
|
||||||
|
0.559644 0.000000 0.000000 0.559644 0.000000 1.250000 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 33.000000 12.000000 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.000000 1.000000 m
|
||||||
|
0.000000 1.552285 0.447715 2.000000 1.000000 2.000000 c
|
||||||
|
8.000000 2.000000 l
|
||||||
|
8.552285 2.000000 9.000000 1.552285 9.000000 1.000000 c
|
||||||
|
9.000000 1.000000 l
|
||||||
|
9.000000 0.447715 8.552285 0.000000 8.000000 0.000000 c
|
||||||
|
1.000000 0.000000 l
|
||||||
|
0.447715 0.000000 0.000000 0.447715 0.000000 1.000000 c
|
||||||
|
0.000000 1.000000 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
q
|
||||||
|
-1.000000 -0.000000 -0.000000 1.000000 43.000000 6.000000 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.000000 1.000000 m
|
||||||
|
0.000000 1.552285 0.447715 2.000000 1.000000 2.000000 c
|
||||||
|
8.000000 2.000000 l
|
||||||
|
8.552285 2.000000 9.000000 1.552285 9.000000 1.000000 c
|
||||||
|
9.000000 1.000000 l
|
||||||
|
9.000000 0.447715 8.552285 0.000000 8.000000 0.000000 c
|
||||||
|
1.000000 0.000000 l
|
||||||
|
0.447715 0.000000 0.000000 0.447715 0.000000 1.000000 c
|
||||||
|
0.000000 1.000000 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
43.000000 7.000000 m
|
||||||
|
43.000000 7.552284 42.552284 8.000000 42.000000 8.000000 c
|
||||||
|
35.000000 8.000000 l
|
||||||
|
34.447716 8.000000 34.000000 7.552284 34.000000 7.000000 c
|
||||||
|
34.000000 7.000000 l
|
||||||
|
34.000000 6.447716 34.447716 6.000000 35.000000 6.000000 c
|
||||||
|
42.000000 6.000000 l
|
||||||
|
42.552284 6.000000 43.000000 6.447716 43.000000 7.000000 c
|
||||||
|
43.000000 7.000000 l
|
||||||
|
h
|
||||||
|
W*
|
||||||
|
n
|
||||||
|
q
|
||||||
|
-1.000000 -0.000000 -0.000000 1.000000 43.000000 6.000000 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
1.000000 1.000000 m
|
||||||
|
8.000000 1.000000 l
|
||||||
|
8.000000 3.000000 l
|
||||||
|
1.000000 3.000000 l
|
||||||
|
1.000000 1.000000 l
|
||||||
|
h
|
||||||
|
8.000000 1.000000 m
|
||||||
|
1.000000 1.000000 l
|
||||||
|
1.000000 -1.000000 l
|
||||||
|
8.000000 -1.000000 l
|
||||||
|
8.000000 1.000000 l
|
||||||
|
h
|
||||||
|
1.000000 1.000000 m
|
||||||
|
1.000000 1.000000 l
|
||||||
|
-1.000000 1.000000 l
|
||||||
|
-1.000000 -0.104569 -0.104570 -1.000000 1.000000 -1.000000 c
|
||||||
|
1.000000 1.000000 l
|
||||||
|
h
|
||||||
|
8.000000 1.000000 m
|
||||||
|
8.000000 1.000000 l
|
||||||
|
8.000000 -1.000000 l
|
||||||
|
9.104569 -1.000000 10.000000 -0.104569 10.000000 1.000000 c
|
||||||
|
8.000000 1.000000 l
|
||||||
|
h
|
||||||
|
8.000000 1.000000 m
|
||||||
|
8.000000 1.000000 l
|
||||||
|
10.000000 1.000000 l
|
||||||
|
10.000000 2.104569 9.104569 3.000000 8.000000 3.000000 c
|
||||||
|
8.000000 1.000000 l
|
||||||
|
h
|
||||||
|
1.000000 3.000000 m
|
||||||
|
-0.104569 3.000000 -1.000000 2.104569 -1.000000 1.000000 c
|
||||||
|
1.000000 1.000000 l
|
||||||
|
1.000000 1.000000 l
|
||||||
|
1.000000 3.000000 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
50.000000 10.000000 m
|
||||||
|
50.000000 4.477154 44.851273 0.000000 38.500000 0.000000 c
|
||||||
|
32.148727 0.000000 27.000000 4.477154 27.000000 10.000000 c
|
||||||
|
27.000000 15.522848 32.148727 20.000000 38.500000 20.000000 c
|
||||||
|
44.851273 20.000000 50.000000 15.522848 50.000000 10.000000 c
|
||||||
|
h
|
||||||
|
W*
|
||||||
|
n
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 27.000000 0.000000 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
22.000000 10.000000 m
|
||||||
|
22.000000 5.156100 17.434797 1.000000 11.500000 1.000000 c
|
||||||
|
11.500000 -1.000000 l
|
||||||
|
18.267752 -1.000000 24.000000 3.798204 24.000000 10.000000 c
|
||||||
|
22.000000 10.000000 l
|
||||||
|
h
|
||||||
|
11.500000 1.000000 m
|
||||||
|
5.565202 1.000000 1.000000 5.156100 1.000000 10.000000 c
|
||||||
|
-1.000000 10.000000 l
|
||||||
|
-1.000000 3.798204 4.732249 -1.000000 11.500000 -1.000000 c
|
||||||
|
11.500000 1.000000 l
|
||||||
|
h
|
||||||
|
1.000000 10.000000 m
|
||||||
|
1.000000 14.843899 5.565202 19.000000 11.500000 19.000000 c
|
||||||
|
11.500000 21.000000 l
|
||||||
|
4.732249 21.000000 -1.000000 16.201796 -1.000000 10.000000 c
|
||||||
|
1.000000 10.000000 l
|
||||||
|
h
|
||||||
|
11.500000 19.000000 m
|
||||||
|
17.434797 19.000000 22.000000 14.843899 22.000000 10.000000 c
|
||||||
|
24.000000 10.000000 l
|
||||||
|
24.000000 16.201796 18.267752 21.000000 11.500000 21.000000 c
|
||||||
|
11.500000 19.000000 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
0.707107 -0.707107 0.707107 0.707107 28.118925 3.187651 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
1.000000 6.949707 m
|
||||||
|
0.447715 6.949707 0.000000 6.501992 0.000000 5.949707 c
|
||||||
|
0.000000 5.397422 0.447715 4.949707 1.000000 4.949707 c
|
||||||
|
1.000000 6.949707 l
|
||||||
|
h
|
||||||
|
4.000000 4.949707 m
|
||||||
|
4.552285 4.949707 5.000000 5.397422 5.000000 5.949707 c
|
||||||
|
5.000000 6.501992 4.552285 6.949707 4.000000 6.949707 c
|
||||||
|
4.000000 4.949707 l
|
||||||
|
h
|
||||||
|
1.000000 4.949707 m
|
||||||
|
4.000000 4.949707 l
|
||||||
|
4.000000 6.949707 l
|
||||||
|
1.000000 6.949707 l
|
||||||
|
1.000000 4.949707 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
0.707107 0.707107 -0.707107 0.707107 36.499969 1.964506 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
1.000000 6.949707 m
|
||||||
|
0.447715 6.949707 0.000000 6.501992 0.000000 5.949707 c
|
||||||
|
0.000000 5.397422 0.447715 4.949707 1.000000 4.949707 c
|
||||||
|
1.000000 6.949707 l
|
||||||
|
h
|
||||||
|
4.000000 4.949707 m
|
||||||
|
4.552285 4.949707 5.000000 5.397422 5.000000 5.949707 c
|
||||||
|
5.000000 6.501992 4.552285 6.949707 4.000000 6.949707 c
|
||||||
|
4.000000 4.949707 l
|
||||||
|
h
|
||||||
|
1.000000 4.949707 m
|
||||||
|
4.000000 4.949707 l
|
||||||
|
4.000000 6.949707 l
|
||||||
|
1.000000 6.949707 l
|
||||||
|
1.000000 4.949707 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
-0.707107 0.707107 -0.707107 -0.707107 47.035614 16.964449 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
1.000000 6.949707 m
|
||||||
|
0.447715 6.949707 0.000000 6.501992 0.000000 5.949707 c
|
||||||
|
0.000000 5.397422 0.447715 4.949707 1.000000 4.949707 c
|
||||||
|
1.000000 6.949707 l
|
||||||
|
h
|
||||||
|
4.000000 4.949707 m
|
||||||
|
4.552285 4.949707 5.000000 5.397422 5.000000 5.949707 c
|
||||||
|
5.000000 6.501992 4.552285 6.949707 4.000000 6.949707 c
|
||||||
|
4.000000 4.949707 l
|
||||||
|
h
|
||||||
|
1.000000 4.949707 m
|
||||||
|
4.000000 4.949707 l
|
||||||
|
4.000000 6.949707 l
|
||||||
|
1.000000 6.949707 l
|
||||||
|
1.000000 4.949707 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
-0.707107 -0.707107 0.707107 -0.707107 39.035675 17.499971 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
1.000000 6.949707 m
|
||||||
|
0.447715 6.949707 0.000000 6.501992 0.000000 5.949707 c
|
||||||
|
0.000000 5.397422 0.447715 4.949707 1.000000 4.949707 c
|
||||||
|
1.000000 6.949707 l
|
||||||
|
h
|
||||||
|
4.000000 4.949707 m
|
||||||
|
4.552285 4.949707 5.000000 5.397422 5.000000 5.949707 c
|
||||||
|
5.000000 6.501992 4.552285 6.949707 4.000000 6.949707 c
|
||||||
|
4.000000 4.949707 l
|
||||||
|
h
|
||||||
|
1.000000 4.949707 m
|
||||||
|
4.000000 4.949707 l
|
||||||
|
4.000000 6.949707 l
|
||||||
|
1.000000 6.949707 l
|
||||||
|
1.000000 4.949707 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
8320
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 50.000000 38.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Type /Catalog
|
||||||
|
/Pages 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000034 00000 n
|
||||||
|
0000008410 00000 n
|
||||||
|
0000008433 00000 n
|
||||||
|
0000008606 00000 n
|
||||||
|
0000008680 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
8739
|
||||||
|
%%EOF
|
|
@ -0,0 +1,170 @@
|
||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||||
|
0.596078 0.592157 0.572549 scn
|
||||||
|
12.000000 0.000000 m
|
||||||
|
18.627417 0.000000 24.000000 5.372583 24.000000 12.000000 c
|
||||||
|
24.000000 18.627417 18.627417 24.000000 12.000000 24.000000 c
|
||||||
|
5.372583 24.000000 0.000000 18.627417 0.000000 12.000000 c
|
||||||
|
0.000000 5.372583 5.372583 0.000000 12.000000 0.000000 c
|
||||||
|
h
|
||||||
|
11.356085 20.726612 m
|
||||||
|
11.080673 20.706541 10.887666 20.454128 10.923384 20.180305 c
|
||||||
|
11.042957 19.263630 l
|
||||||
|
10.397048 19.179354 9.777586 19.010939 9.195930 18.769743 c
|
||||||
|
8.841808 19.623703 l
|
||||||
|
8.736031 19.878782 8.442759 20.001123 8.194168 19.880884 c
|
||||||
|
7.804816 19.692562 7.431699 19.476336 7.077398 19.234867 c
|
||||||
|
6.849212 19.079351 6.808879 18.764158 6.977139 18.545200 c
|
||||||
|
7.540419 17.812202 l
|
||||||
|
7.032850 17.422173 6.577827 16.967148 6.187798 16.459579 c
|
||||||
|
5.454800 17.022860 l
|
||||||
|
5.235841 17.191120 4.920649 17.150787 4.765132 16.922600 c
|
||||||
|
4.523664 16.568302 4.307439 16.195185 4.119116 15.805833 c
|
||||||
|
3.998877 15.557242 4.121218 15.263969 4.376298 15.158192 c
|
||||||
|
5.230257 14.804070 l
|
||||||
|
4.989061 14.222414 4.820646 13.602952 4.736370 12.957043 c
|
||||||
|
3.819693 13.076614 l
|
||||||
|
3.545871 13.112333 3.293459 12.919325 3.273387 12.643913 c
|
||||||
|
3.257878 12.431119 3.250000 12.216384 3.250000 12.000000 c
|
||||||
|
3.250000 11.783616 3.257878 11.568881 3.273387 11.356086 c
|
||||||
|
3.293460 11.080674 3.545871 10.887668 3.819694 10.923385 c
|
||||||
|
4.736370 11.042957 l
|
||||||
|
4.820646 10.397048 4.989061 9.777586 5.230256 9.195931 c
|
||||||
|
4.376297 8.841809 l
|
||||||
|
4.121218 8.736032 3.998877 8.442759 4.119116 8.194168 c
|
||||||
|
4.307439 7.804817 4.523664 7.431700 4.765132 7.077400 c
|
||||||
|
4.920649 6.849213 5.235842 6.808880 5.454801 6.977140 c
|
||||||
|
6.187798 7.540421 l
|
||||||
|
6.577827 7.032852 7.032850 6.577827 7.540419 6.187798 c
|
||||||
|
6.977141 5.454802 l
|
||||||
|
6.808880 5.235844 6.849213 4.920650 7.077399 4.765133 c
|
||||||
|
7.431699 4.523664 7.804815 4.307440 8.194167 4.119116 c
|
||||||
|
8.442758 3.998877 8.736031 4.121218 8.841808 4.376299 c
|
||||||
|
9.195930 5.230255 l
|
||||||
|
9.777586 4.989059 10.397048 4.820644 11.042957 4.736368 c
|
||||||
|
10.923386 3.819695 l
|
||||||
|
10.887667 3.545872 11.080674 3.293459 11.356086 3.273388 c
|
||||||
|
11.568880 3.257879 11.783616 3.250000 12.000000 3.250000 c
|
||||||
|
12.216384 3.250000 12.431120 3.257879 12.643914 3.273388 c
|
||||||
|
12.919326 3.293459 13.112333 3.545872 13.076615 3.819695 c
|
||||||
|
12.957043 4.736368 l
|
||||||
|
13.602952 4.820644 14.222414 4.989059 14.804070 5.230255 c
|
||||||
|
15.158191 4.376299 l
|
||||||
|
15.263968 4.121218 15.557241 3.998877 15.805832 4.119116 c
|
||||||
|
16.195183 4.307440 16.568300 4.523664 16.922600 4.765133 c
|
||||||
|
17.150787 4.920650 17.191120 5.235844 17.022858 5.454802 c
|
||||||
|
16.459581 6.187798 l
|
||||||
|
16.967150 6.577827 17.422173 7.032850 17.812202 7.540419 c
|
||||||
|
18.545198 6.977142 l
|
||||||
|
18.764156 6.808880 19.079350 6.849213 19.234867 7.077400 c
|
||||||
|
19.476336 7.431700 19.692560 7.804817 19.880884 8.194167 c
|
||||||
|
20.001123 8.442758 19.878782 8.736032 19.623701 8.841808 c
|
||||||
|
18.769745 9.195930 l
|
||||||
|
19.010941 9.777586 19.179356 10.397049 19.263632 11.042958 c
|
||||||
|
20.180305 10.923386 l
|
||||||
|
20.454128 10.887668 20.706541 11.080674 20.726612 11.356086 c
|
||||||
|
20.742121 11.568881 20.750000 11.783616 20.750000 12.000000 c
|
||||||
|
20.750000 12.216385 20.742121 12.431121 20.726612 12.643916 c
|
||||||
|
20.706541 12.919327 20.454128 13.112334 20.180305 13.076616 c
|
||||||
|
19.263632 12.957044 l
|
||||||
|
19.179356 13.602953 19.010939 14.222414 18.769745 14.804070 c
|
||||||
|
19.623701 15.158192 l
|
||||||
|
19.878782 15.263969 20.001123 15.557241 19.880884 15.805832 c
|
||||||
|
19.692560 16.195185 19.476336 16.568302 19.234867 16.922602 c
|
||||||
|
19.079350 17.150787 18.764156 17.191120 18.545198 17.022861 c
|
||||||
|
17.812202 16.459581 l
|
||||||
|
17.422173 16.967150 16.967148 17.422173 16.459579 17.812202 c
|
||||||
|
17.022860 18.545200 l
|
||||||
|
17.191120 18.764158 17.150787 19.079351 16.922600 19.234867 c
|
||||||
|
16.568300 19.476336 16.195183 19.692562 15.805832 19.880884 c
|
||||||
|
15.557241 20.001123 15.263968 19.878782 15.158192 19.623703 c
|
||||||
|
14.804069 18.769743 l
|
||||||
|
14.222413 19.010939 13.602951 19.179354 12.957042 19.263630 c
|
||||||
|
13.076614 20.180307 l
|
||||||
|
13.112332 20.454130 12.919325 20.706541 12.643913 20.726612 c
|
||||||
|
12.431118 20.742123 12.216383 20.750000 12.000000 20.750000 c
|
||||||
|
11.783615 20.750000 11.568880 20.742123 11.356085 20.726612 c
|
||||||
|
h
|
||||||
|
12.696518 11.185913 m
|
||||||
|
18.050842 11.185913 l
|
||||||
|
17.652849 8.199290 15.095482 5.895348 12.000000 5.895348 c
|
||||||
|
11.021035 5.895348 10.095892 6.125784 9.275852 6.535372 c
|
||||||
|
11.844859 10.710011 l
|
||||||
|
12.026858 11.005757 12.349257 11.185913 12.696518 11.185913 c
|
||||||
|
h
|
||||||
|
5.895349 12.000000 m
|
||||||
|
5.895349 10.045127 6.814215 8.304866 8.243605 7.187559 c
|
||||||
|
10.807167 11.353347 l
|
||||||
|
10.988450 11.647931 11.004625 12.015280 10.849936 12.324657 c
|
||||||
|
8.508228 17.008072 l
|
||||||
|
6.928618 15.904668 5.895349 14.073000 5.895349 12.000000 c
|
||||||
|
h
|
||||||
|
12.000000 18.104652 m
|
||||||
|
11.138405 18.104652 10.318498 17.926159 9.575241 17.604132 c
|
||||||
|
11.897492 12.959629 l
|
||||||
|
12.066884 12.620845 12.413148 12.406842 12.791920 12.406842 c
|
||||||
|
18.091309 12.406842 l
|
||||||
|
17.881950 15.588663 15.234796 18.104652 12.000000 18.104652 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
4761
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Type /Catalog
|
||||||
|
/Pages 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000034 00000 n
|
||||||
|
0000004851 00000 n
|
||||||
|
0000004874 00000 n
|
||||||
|
0000005047 00000 n
|
||||||
|
0000005121 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
5180
|
||||||
|
%%EOF
|
|
@ -0,0 +1,88 @@
|
||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||||
|
0.596078 0.592157 0.572549 scn
|
||||||
|
12.000000 0.000000 m
|
||||||
|
18.627417 0.000000 24.000000 5.372583 24.000000 12.000000 c
|
||||||
|
24.000000 18.627417 18.627417 24.000000 12.000000 24.000000 c
|
||||||
|
5.372583 24.000000 0.000000 18.627417 0.000000 12.000000 c
|
||||||
|
0.000000 5.372583 5.372583 0.000000 12.000000 0.000000 c
|
||||||
|
h
|
||||||
|
11.272544 19.262787 m
|
||||||
|
11.265584 19.754541 11.632695 20.000000 11.999791 20.000000 c
|
||||||
|
12.366895 20.000000 12.734310 19.754541 12.727037 19.262787 c
|
||||||
|
12.727037 12.727312 l
|
||||||
|
19.262306 12.727312 l
|
||||||
|
20.245783 12.741233 20.245783 11.258884 19.262306 11.272775 c
|
||||||
|
12.727037 11.272775 l
|
||||||
|
12.727037 4.737299 l
|
||||||
|
12.732529 4.336187 12.412436 4.006634 12.006896 4.000090 c
|
||||||
|
11.601364 3.993753 11.266726 4.327286 11.272544 4.737299 c
|
||||||
|
11.272544 11.272775 l
|
||||||
|
4.737278 11.272775 l
|
||||||
|
4.336182 11.267284 4.006634 11.587388 4.000089 11.992941 c
|
||||||
|
3.993754 12.398488 4.327280 12.733130 4.737278 12.727312 c
|
||||||
|
11.272544 12.727312 l
|
||||||
|
11.272544 19.262787 l
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
1007
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Type /Catalog
|
||||||
|
/Pages 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000034 00000 n
|
||||||
|
0000001097 00000 n
|
||||||
|
0000001120 00000 n
|
||||||
|
0000001293 00000 n
|
||||||
|
0000001367 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1426
|
||||||
|
%%EOF
|
|
@ -14,9 +14,7 @@ import net.dankito.banking.LuceneConfig.Companion.OtherPartyAccountIdFieldName
|
||||||
import net.dankito.banking.LuceneConfig.Companion.OtherPartyBankCodeFieldName
|
import net.dankito.banking.LuceneConfig.Companion.OtherPartyBankCodeFieldName
|
||||||
import net.dankito.banking.LuceneConfig.Companion.OtherPartyNameFieldName
|
import net.dankito.banking.LuceneConfig.Companion.OtherPartyNameFieldName
|
||||||
import net.dankito.banking.LuceneConfig.Companion.UsageFieldName
|
import net.dankito.banking.LuceneConfig.Companion.UsageFieldName
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.*
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
|
||||||
import net.dankito.banking.util.ISerializer
|
import net.dankito.banking.util.ISerializer
|
||||||
import net.dankito.banking.util.JacksonJsonSerializer
|
import net.dankito.banking.util.JacksonJsonSerializer
|
||||||
import net.dankito.utils.lucene.index.DocumentsWriter
|
import net.dankito.utils.lucene.index.DocumentsWriter
|
||||||
|
@ -47,7 +45,7 @@ open class LuceneBankingPersistence(
|
||||||
protected val fields = FieldBuilder()
|
protected val fields = FieldBuilder()
|
||||||
|
|
||||||
|
|
||||||
override fun saveOrUpdateAccountTransactions(bankAccount: BankAccount, transactions: List<AccountTransaction>) {
|
override fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List<IAccountTransaction>) {
|
||||||
val writer = getWriter()
|
val writer = getWriter()
|
||||||
|
|
||||||
transactions.forEach { transaction ->
|
transactions.forEach { transaction ->
|
||||||
|
@ -60,7 +58,7 @@ open class LuceneBankingPersistence(
|
||||||
writer.flushChangesToDisk()
|
writer.flushChangesToDisk()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun createFieldsForAccountTransaction(bankAccount: BankAccount, transaction: AccountTransaction): List<IndexableField?> {
|
protected open fun createFieldsForAccountTransaction(bankAccount: TypedBankAccount, transaction: IAccountTransaction): List<IndexableField?> {
|
||||||
return listOf(
|
return listOf(
|
||||||
fields.keywordField(BankAccountIdFieldName, bankAccount.technicalId),
|
fields.keywordField(BankAccountIdFieldName, bankAccount.technicalId),
|
||||||
fields.nullableFullTextSearchField(OtherPartyNameFieldName, transaction.otherPartyName, true),
|
fields.nullableFullTextSearchField(OtherPartyNameFieldName, transaction.otherPartyName, true),
|
||||||
|
@ -79,7 +77,7 @@ open class LuceneBankingPersistence(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun deleteAccount(customer: Customer, allCustomers: List<Customer>) {
|
override fun deleteAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||||
try {
|
try {
|
||||||
deleteAccountTransactions(customer.accounts)
|
deleteAccountTransactions(customer.accounts)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -89,7 +87,7 @@ open class LuceneBankingPersistence(
|
||||||
super.deleteAccount(customer, allCustomers)
|
super.deleteAccount(customer, allCustomers)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun deleteAccountTransactions(bankAccounts: List<BankAccount>) {
|
protected open fun deleteAccountTransactions(bankAccounts: List<TypedBankAccount>) {
|
||||||
val writer = getWriter()
|
val writer = getWriter()
|
||||||
|
|
||||||
val bankAccountIds = bankAccounts.map { it.technicalId }
|
val bankAccountIds = bankAccounts.map { it.technicalId }
|
||||||
|
|
|
@ -5,12 +5,14 @@ import net.dankito.banking.ui.model.Customer
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
import net.dankito.banking.ui.model.AccountTransaction
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
import net.dankito.banking.ui.model.BankAccount
|
||||||
import net.dankito.utils.io.FileUtils
|
import net.dankito.utils.io.FileUtils
|
||||||
|
import net.dankito.utils.multiplatform.File
|
||||||
|
import net.dankito.utils.multiplatform.toBigDecimal
|
||||||
|
import net.dankito.utils.multiplatform.toDate
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.Mockito.mock
|
import org.mockito.Mockito.mock
|
||||||
import java.io.File
|
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -211,7 +213,7 @@ class LuceneRemitteeSearcherTest {
|
||||||
otherPartyName: String = randomString(), otherPartyBankCode: String = randomString(),
|
otherPartyName: String = randomString(), otherPartyBankCode: String = randomString(),
|
||||||
otherPartyAccountId: String = randomString(), usage: String = randomString()): AccountTransaction {
|
otherPartyAccountId: String = randomString(), usage: String = randomString()): AccountTransaction {
|
||||||
|
|
||||||
return AccountTransaction(bankAccount, amount, "EUR", usage, bookingDate, otherPartyName, otherPartyBankCode, otherPartyAccountId, null, bookingDate)
|
return AccountTransaction(bankAccount, amount.toBigDecimal(), "EUR", usage, bookingDate.toDate(), otherPartyName, otherPartyBankCode, otherPartyAccountId, null, bookingDate.toDate())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun randomString(): String {
|
private fun randomString(): String {
|
||||||
|
|
|
@ -17,10 +17,6 @@ compileTestKotlin {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':BankingUiCommon')
|
implementation project(':BankingUiCommon')
|
||||||
|
|
||||||
implementation("org.mapstruct:mapstruct:$mapStructVersion")
|
|
||||||
|
|
||||||
kapt("org.mapstruct:mapstruct-processor:$mapStructVersion")
|
|
||||||
|
|
||||||
|
|
||||||
testImplementation "junit:junit:$junitVersion"
|
testImplementation "junit:junit:$junitVersion"
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
package net.dankito.banking.persistence
|
package net.dankito.banking.persistence
|
||||||
|
|
||||||
import net.dankito.banking.persistence.mapper.CustomerConverter
|
|
||||||
import net.dankito.banking.persistence.model.CustomerEntity
|
import net.dankito.banking.persistence.model.CustomerEntity
|
||||||
|
import net.dankito.banking.ui.model.*
|
||||||
import net.dankito.utils.multiplatform.File
|
import net.dankito.utils.multiplatform.File
|
||||||
import net.dankito.banking.ui.model.Customer
|
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
|
||||||
import net.dankito.banking.util.ISerializer
|
import net.dankito.banking.util.ISerializer
|
||||||
import org.mapstruct.factory.Mappers
|
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
||||||
|
@ -17,39 +13,32 @@ open class BankingPersistenceJson(
|
||||||
protected val serializer: ISerializer
|
protected val serializer: ISerializer
|
||||||
) : IBankingPersistence {
|
) : IBankingPersistence {
|
||||||
|
|
||||||
protected val mapper = Mappers.getMapper(CustomerConverter::class.java)
|
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
jsonFile.absoluteFile.parentFile.mkdirs()
|
jsonFile.absoluteFile.parentFile.mkdirs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun saveOrUpdateAccount(customer: Customer, allCustomers: List<Customer>) {
|
override fun saveOrUpdateAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||||
saveAllCustomers(allCustomers)
|
saveAllCustomers(allCustomers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deleteAccount(customer: Customer, allCustomers: List<Customer>) {
|
override fun deleteAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||||
saveAllCustomers(allCustomers)
|
saveAllCustomers(allCustomers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun readPersistedAccounts(): List<Customer> {
|
override fun readPersistedAccounts(): List<TypedCustomer> {
|
||||||
val deserializedCustomers = serializer.deserializeListOr(jsonFile, CustomerEntity::class)
|
return serializer.deserializeListOr(jsonFile, CustomerEntity::class).map { it as TypedCustomer }
|
||||||
|
|
||||||
return mapper.mapCustomerEntities(deserializedCustomers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun saveOrUpdateAccountTransactions(bankAccount: BankAccount, transactions: List<AccountTransaction>) {
|
override fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List<IAccountTransaction>) {
|
||||||
// done when called saveOrUpdateAccount()
|
// done when called saveOrUpdateAccount()
|
||||||
// TODO: or also call saveAllCustomers()?
|
// TODO: or also call saveAllCustomers()?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected open fun saveAllCustomers(allCustomers: List<Customer>) {
|
protected open fun saveAllCustomers(allCustomers: List<TypedCustomer>) {
|
||||||
val mappedCustomers = mapper.mapCustomers(allCustomers)
|
serializer.serializeObject(allCustomers, jsonFile)
|
||||||
|
|
||||||
serializer.serializeObject(mappedCustomers, jsonFile)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
package net.dankito.banking.persistence.mapper
|
|
||||||
|
|
||||||
import net.dankito.banking.persistence.model.AccountTransactionEntity
|
|
||||||
import net.dankito.banking.persistence.model.BankAccountEntity
|
|
||||||
import net.dankito.banking.persistence.model.CustomerEntity
|
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
|
||||||
import net.dankito.banking.ui.model.Customer
|
|
||||||
import org.mapstruct.*
|
|
||||||
|
|
||||||
|
|
||||||
@Mapper
|
|
||||||
abstract class CustomerConverter {
|
|
||||||
|
|
||||||
// Context is needed to fix cycle dependencies issue
|
|
||||||
|
|
||||||
protected val bankAccountCustomerField = BankAccount::class.java.getDeclaredField(BankAccount::customer.name)
|
|
||||||
|
|
||||||
|
|
||||||
init {
|
|
||||||
bankAccountCustomerField.isAccessible = true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Mapping(source = "technicalId", target = "id")
|
|
||||||
abstract fun mapToEntity(customer: Customer, @Context context: CycleAvoidingMappingContext): CustomerEntity
|
|
||||||
|
|
||||||
@InheritInverseConfiguration
|
|
||||||
abstract fun mapCustomer(customer: CustomerEntity, @Context context: CycleAvoidingMappingContext): Customer
|
|
||||||
|
|
||||||
abstract fun mapCustomers(customers: List<Customer>, @Context context: CycleAvoidingMappingContext): List<CustomerEntity>
|
|
||||||
|
|
||||||
open fun mapCustomers(customers: List<Customer>): List<CustomerEntity> {
|
|
||||||
// create a new context instance each time as otherwise just cached instance would be taken und BankAccounts and AccountTransactions would never get updated
|
|
||||||
return mapCustomers(customers, CycleAvoidingMappingContext())
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun mapCustomerEntities(customers: List<CustomerEntity>, @Context context: CycleAvoidingMappingContext): List<Customer>
|
|
||||||
|
|
||||||
open fun mapCustomerEntities(customers: List<CustomerEntity>): List<Customer> {
|
|
||||||
// create a new context instance each time as otherwise just cached instance would be taken und BankAccounts and AccountTransactions would never get updated
|
|
||||||
return mapCustomerEntities(customers, CycleAvoidingMappingContext())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Mapping(source = "technicalId", target = "id")
|
|
||||||
abstract fun mapBankAccount(account: BankAccount, @Context context: CycleAvoidingMappingContext): BankAccountEntity
|
|
||||||
|
|
||||||
@InheritInverseConfiguration
|
|
||||||
abstract fun mapBankAccount(account: BankAccountEntity, @Context context: CycleAvoidingMappingContext): BankAccount
|
|
||||||
|
|
||||||
abstract fun mapBankAccounts(accounts: List<BankAccount>, @Context context: CycleAvoidingMappingContext): List<BankAccountEntity>
|
|
||||||
|
|
||||||
abstract fun mapBankAccountEntities(accounts: List<BankAccountEntity>, @Context context: CycleAvoidingMappingContext): List<BankAccount>
|
|
||||||
|
|
||||||
@AfterMapping
|
|
||||||
open fun mapBankAccountCustomer(serializedAccount: BankAccountEntity, @MappingTarget account: BankAccount, @Context context: CycleAvoidingMappingContext) {
|
|
||||||
val mappedCustomer = mapCustomer(serializedAccount.customer, context)
|
|
||||||
|
|
||||||
bankAccountCustomerField.set(account, mappedCustomer)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Mapping(source = "technicalId", target = "id")
|
|
||||||
abstract fun mapTransaction(transaction: AccountTransaction, @Context context: CycleAvoidingMappingContext): AccountTransactionEntity
|
|
||||||
|
|
||||||
@InheritInverseConfiguration
|
|
||||||
fun mapTransaction(transaction: AccountTransactionEntity, @Context context: CycleAvoidingMappingContext): AccountTransaction {
|
|
||||||
val account = mapBankAccount(transaction.bankAccount, context)
|
|
||||||
|
|
||||||
val mappedTransaction = AccountTransaction(account, transaction.amount, transaction.currency, transaction.unparsedUsage, transaction.bookingDate,
|
|
||||||
transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId, transaction.bookingText,
|
|
||||||
transaction.valueDate, transaction.statementNumber, transaction.sequenceNumber, transaction.openingBalance, transaction.closingBalance,
|
|
||||||
transaction.endToEndReference, transaction.customerReference, transaction.mandateReference, transaction.creditorIdentifier, transaction.originatorsIdentificationCode,
|
|
||||||
transaction.compensationAmount, transaction.originalAmount, transaction.sepaUsage, transaction.deviantOriginator, transaction.deviantRecipient,
|
|
||||||
transaction.usageWithNoSpecialType, transaction.primaNotaNumber, transaction.textKeySupplement, transaction.currencyType, transaction.bookingKey,
|
|
||||||
transaction.referenceForTheAccountOwner, transaction.referenceOfTheAccountServicingInstitution, transaction.supplementaryDetails,
|
|
||||||
transaction.transactionReferenceNumber, transaction.relatedReferenceNumber)
|
|
||||||
|
|
||||||
mappedTransaction.technicalId = transaction.id
|
|
||||||
|
|
||||||
return mappedTransaction
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun mapTransactions(transactions: List<AccountTransaction>, @Context context: CycleAvoidingMappingContext): List<AccountTransactionEntity>
|
|
||||||
|
|
||||||
abstract fun mapTransactionEntities(transactions: List<AccountTransactionEntity>, @Context context: CycleAvoidingMappingContext): List<AccountTransaction>
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package net.dankito.banking.persistence.mapper
|
|
||||||
|
|
||||||
import org.mapstruct.BeforeMapping
|
|
||||||
import org.mapstruct.MappingTarget
|
|
||||||
import org.mapstruct.TargetType
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
|
||||||
open class CycleAvoidingMappingContext {
|
|
||||||
|
|
||||||
private val knownInstances: MutableMap<Any, Any> = IdentityHashMap()
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an instance out of this context if it is already mapped.
|
|
||||||
*/
|
|
||||||
@BeforeMapping
|
|
||||||
open fun <T> getMappedInstance(source: Any, @TargetType targetType: Class<T>): T {
|
|
||||||
return targetType.cast(knownInstances[source])
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Puts an instance into the cache, so that it can be remembered to avoid endless mapping.
|
|
||||||
*/
|
|
||||||
@BeforeMapping
|
|
||||||
open fun storeMappedInstance(source: Any, @MappingTarget target: Any) {
|
|
||||||
knownInstances[source] = target
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,136 +0,0 @@
|
||||||
package net.dankito.banking.persistence.mapper
|
|
||||||
|
|
||||||
import net.dankito.banking.persistence.model.AccountTransactionEntity
|
|
||||||
import net.dankito.banking.persistence.model.BankAccountEntity
|
|
||||||
import net.dankito.banking.persistence.model.CustomerEntity
|
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
|
||||||
import net.dankito.banking.ui.model.Customer
|
|
||||||
|
|
||||||
|
|
||||||
open class EntitiesMapper {
|
|
||||||
|
|
||||||
open fun mapCustomers(customers: List<Customer>): List<CustomerEntity> {
|
|
||||||
return customers.map { mapCustomer(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun mapCustomer(customer: Customer): CustomerEntity {
|
|
||||||
val mappedCustomer = CustomerEntity(
|
|
||||||
customer.bankCode, customer.customerId, customer.password, customer.finTsServerAddress,
|
|
||||||
customer.bankName, customer.bic, customer.customerName, customer.userId, customer.iconUrl,
|
|
||||||
listOf(), customer.supportedTanProcedures, customer.selectedTanProcedure, customer.tanMedia
|
|
||||||
)
|
|
||||||
|
|
||||||
mappedCustomer.id = customer.technicalId
|
|
||||||
mappedCustomer.userSetDisplayName = customer.userSetDisplayName
|
|
||||||
|
|
||||||
mappedCustomer.accounts = mapBankAccounts(customer.accounts, mappedCustomer)
|
|
||||||
|
|
||||||
return mappedCustomer
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
open fun mapCustomerEntities(customers: List<CustomerEntity>): List<Customer> {
|
|
||||||
return customers.map { mapCustomer(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun mapCustomer(customer: CustomerEntity): Customer {
|
|
||||||
val mappedCustomer = Customer(
|
|
||||||
customer.bankCode, customer.customerId, customer.password, customer.finTsServerAddress,
|
|
||||||
customer.bankName, customer.bic, customer.customerName, customer.userId, customer.iconUrl
|
|
||||||
)
|
|
||||||
|
|
||||||
mappedCustomer.technicalId = customer.id
|
|
||||||
mappedCustomer.userSetDisplayName = customer.userSetDisplayName
|
|
||||||
|
|
||||||
mappedCustomer.accounts = mapBankAccounts(customer.accounts, mappedCustomer)
|
|
||||||
|
|
||||||
|
|
||||||
mappedCustomer.supportedTanProcedures = customer.supportedTanProcedures
|
|
||||||
mappedCustomer.selectedTanProcedure = customer.selectedTanProcedure
|
|
||||||
mappedCustomer.tanMedia = customer.tanMedia
|
|
||||||
|
|
||||||
return mappedCustomer
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
open fun mapBankAccounts(transactions: List<BankAccount>, customer: CustomerEntity): List<BankAccountEntity> {
|
|
||||||
return transactions.map { mapBankAccount(it, customer) }
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun mapBankAccount(account: BankAccount, customer: CustomerEntity): BankAccountEntity {
|
|
||||||
val mappedAccount = BankAccountEntity(
|
|
||||||
customer, account.identifier, account.accountHolderName, account.iban, account.subAccountNumber,
|
|
||||||
account.customerId, account.balance, account.currency, account.type, account.productName,
|
|
||||||
account.accountLimit, account.lastRetrievedTransactionsTimestamp,
|
|
||||||
account.supportsRetrievingAccountTransactions, account.supportsRetrievingBalance,
|
|
||||||
account.supportsTransferringMoney, account.supportsInstantPaymentMoneyTransfer
|
|
||||||
)
|
|
||||||
|
|
||||||
mappedAccount.id = account.technicalId
|
|
||||||
mappedAccount.userSetDisplayName = account.userSetDisplayName
|
|
||||||
|
|
||||||
mappedAccount.bookedTransactions = mapTransactions(account.bookedTransactions, mappedAccount)
|
|
||||||
|
|
||||||
return mappedAccount
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
open fun mapBankAccounts(transactions: List<BankAccountEntity>, customer: Customer): List<BankAccount> {
|
|
||||||
return transactions.map { mapBankAccount(it, customer) }
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun mapBankAccount(account: BankAccountEntity, customer: Customer): BankAccount {
|
|
||||||
val mappedAccount = BankAccount(
|
|
||||||
customer, account.identifier, account.accountHolderName, account.iban, account.subAccountNumber,
|
|
||||||
account.customerId, account.balance, account.currency, account.type, account.productName,
|
|
||||||
account.accountLimit, account.lastRetrievedTransactionsTimestamp,
|
|
||||||
account.supportsRetrievingAccountTransactions, account.supportsRetrievingBalance,
|
|
||||||
account.supportsTransferringMoney, account.supportsInstantPaymentMoneyTransfer
|
|
||||||
)
|
|
||||||
|
|
||||||
mappedAccount.technicalId = account.id
|
|
||||||
mappedAccount.userSetDisplayName = account.userSetDisplayName
|
|
||||||
|
|
||||||
mappedAccount.bookedTransactions = mapTransactions(account.bookedTransactions, mappedAccount)
|
|
||||||
|
|
||||||
return mappedAccount
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
open fun mapTransactions(transactions: List<AccountTransaction>, account: BankAccountEntity): List<AccountTransactionEntity> {
|
|
||||||
return transactions.map { mapTransaction(it, account) }
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun mapTransaction(transaction: AccountTransaction, account: BankAccountEntity): AccountTransactionEntity {
|
|
||||||
return AccountTransactionEntity(account, transaction.amount, transaction.currency, transaction.unparsedUsage, transaction.bookingDate,
|
|
||||||
transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId, transaction.bookingText,
|
|
||||||
transaction.valueDate, transaction.statementNumber, transaction.sequenceNumber, transaction.openingBalance, transaction.closingBalance,
|
|
||||||
transaction.endToEndReference, transaction.customerReference, transaction.mandateReference, transaction.creditorIdentifier, transaction.originatorsIdentificationCode,
|
|
||||||
transaction.compensationAmount, transaction.originalAmount, transaction.sepaUsage, transaction.deviantOriginator, transaction.deviantRecipient,
|
|
||||||
transaction.usageWithNoSpecialType, transaction.primaNotaNumber, transaction.textKeySupplement, transaction.currencyType, transaction.bookingKey,
|
|
||||||
transaction.referenceForTheAccountOwner, transaction.referenceOfTheAccountServicingInstitution, transaction.supplementaryDetails,
|
|
||||||
transaction.transactionReferenceNumber, transaction.relatedReferenceNumber, transaction.technicalId)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
open fun mapTransactions(transactions: List<AccountTransactionEntity>, account: BankAccount): List<AccountTransaction> {
|
|
||||||
return transactions.map { mapTransaction(it, account) }
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun mapTransaction(transaction: AccountTransactionEntity, account: BankAccount): AccountTransaction {
|
|
||||||
val mappedTransaction = AccountTransaction(account, transaction.amount, transaction.currency, transaction.unparsedUsage, transaction.bookingDate,
|
|
||||||
transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId, transaction.bookingText,
|
|
||||||
transaction.valueDate, transaction.statementNumber, transaction.sequenceNumber, transaction.openingBalance, transaction.closingBalance,
|
|
||||||
transaction.endToEndReference, transaction.customerReference, transaction.mandateReference, transaction.creditorIdentifier, transaction.originatorsIdentificationCode,
|
|
||||||
transaction.compensationAmount, transaction.originalAmount, transaction.sepaUsage, transaction.deviantOriginator, transaction.deviantRecipient,
|
|
||||||
transaction.usageWithNoSpecialType, transaction.primaNotaNumber, transaction.textKeySupplement, transaction.currencyType, transaction.bookingKey,
|
|
||||||
transaction.referenceForTheAccountOwner, transaction.referenceOfTheAccountServicingInstitution, transaction.supplementaryDetails,
|
|
||||||
transaction.transactionReferenceNumber, transaction.relatedReferenceNumber)
|
|
||||||
|
|
||||||
mappedTransaction.technicalId = transaction.id
|
|
||||||
|
|
||||||
return mappedTransaction
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package net.dankito.banking.persistence.mapper
|
||||||
|
|
||||||
|
import net.dankito.banking.persistence.model.AccountTransactionEntity
|
||||||
|
import net.dankito.banking.persistence.model.BankAccountEntity
|
||||||
|
import net.dankito.banking.persistence.model.CustomerEntity
|
||||||
|
import net.dankito.banking.ui.model.IAccountTransaction
|
||||||
|
import net.dankito.banking.ui.model.TypedBankAccount
|
||||||
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
|
import net.dankito.banking.ui.model.mapper.IModelCreator
|
||||||
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
|
import net.dankito.utils.multiplatform.Date
|
||||||
|
|
||||||
|
|
||||||
|
open class EntitiesModelCreator : IModelCreator {
|
||||||
|
|
||||||
|
override fun createCustomer(bankCode: String, customerId: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||||
|
customerName: String, userId: String, iconUrl: String?): TypedCustomer {
|
||||||
|
|
||||||
|
return CustomerEntity(bankCode, customerId, password, finTsServerAddress, bankName, bic, customerName, userId, iconUrl) as TypedCustomer
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun createBankAccount(customer: TypedCustomer, productName: String?, identifier: String): TypedBankAccount {
|
||||||
|
return BankAccountEntity(customer as CustomerEntity, identifier, "", null, null, "", productName = productName) as TypedBankAccount
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createTransaction(
|
||||||
|
bankAccount: TypedBankAccount,
|
||||||
|
amount: BigDecimal,
|
||||||
|
currency: String,
|
||||||
|
unparsedUsage: String,
|
||||||
|
bookingDate: Date,
|
||||||
|
otherPartyName: String?,
|
||||||
|
otherPartyBankCode: String?,
|
||||||
|
otherPartyAccountId: String?,
|
||||||
|
bookingText: String?,
|
||||||
|
valueDate: Date,
|
||||||
|
statementNumber: Int,
|
||||||
|
sequenceNumber: Int?,
|
||||||
|
openingBalance: BigDecimal?,
|
||||||
|
closingBalance: BigDecimal?,
|
||||||
|
endToEndReference: String?,
|
||||||
|
customerReference: String?,
|
||||||
|
mandateReference: String?,
|
||||||
|
creditorIdentifier: String?,
|
||||||
|
originatorsIdentificationCode: String?,
|
||||||
|
compensationAmount: String?,
|
||||||
|
originalAmount: String?,
|
||||||
|
sepaUsage: String?,
|
||||||
|
deviantOriginator: String?,
|
||||||
|
deviantRecipient: String?,
|
||||||
|
usageWithNoSpecialType: String?,
|
||||||
|
primaNotaNumber: String?,
|
||||||
|
textKeySupplement: String?,
|
||||||
|
currencyType: String?,
|
||||||
|
bookingKey: String,
|
||||||
|
referenceForTheAccountOwner: String,
|
||||||
|
referenceOfTheAccountServicingInstitution: String?,
|
||||||
|
supplementaryDetails: String?,
|
||||||
|
transactionReferenceNumber: String,
|
||||||
|
relatedReferenceNumber: String?
|
||||||
|
) : IAccountTransaction {
|
||||||
|
|
||||||
|
return AccountTransactionEntity(bankAccount as BankAccountEntity, amount, currency, unparsedUsage, bookingDate,
|
||||||
|
otherPartyName, otherPartyBankCode, otherPartyAccountId, bookingText, valueDate, statementNumber, sequenceNumber,
|
||||||
|
openingBalance, closingBalance, endToEndReference, customerReference, mandateReference, creditorIdentifier,
|
||||||
|
originatorsIdentificationCode, compensationAmount, originalAmount, sepaUsage, deviantOriginator, deviantRecipient,
|
||||||
|
usageWithNoSpecialType, primaNotaNumber, textKeySupplement, currencyType, bookingKey, referenceForTheAccountOwner,
|
||||||
|
referenceOfTheAccountServicingInstitution, supplementaryDetails, transactionReferenceNumber, relatedReferenceNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,57 +2,63 @@ package net.dankito.banking.persistence.model
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
||||||
|
import net.dankito.banking.ui.model.IAccountTransaction
|
||||||
import net.dankito.utils.multiplatform.BigDecimal
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
import net.dankito.utils.multiplatform.Date
|
import net.dankito.utils.multiplatform.Date
|
||||||
import net.dankito.utils.multiplatform.UUID
|
import net.dankito.utils.multiplatform.UUID
|
||||||
|
|
||||||
|
|
||||||
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
@JsonIdentityInfo(property = "technicalId", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
||||||
// had to define all properties as 'var' 'cause MapStruct cannot handle vals
|
// had to define all properties as 'var' 'cause MapStruct cannot handle vals
|
||||||
open class AccountTransactionEntity(
|
open class AccountTransactionEntity(
|
||||||
open var bankAccount: BankAccountEntity,
|
override var bankAccount: BankAccountEntity,
|
||||||
open var amount: BigDecimal,
|
override var amount: BigDecimal,
|
||||||
open var currency: String,
|
override var currency: String,
|
||||||
open var unparsedUsage: String,
|
override var unparsedUsage: String,
|
||||||
open var bookingDate: Date,
|
override var bookingDate: Date,
|
||||||
open var otherPartyName: String?,
|
override var otherPartyName: String?,
|
||||||
open var otherPartyBankCode: String?,
|
override var otherPartyBankCode: String?,
|
||||||
open var otherPartyAccountId: String?,
|
override var otherPartyAccountId: String?,
|
||||||
open var bookingText: String?,
|
override var bookingText: String?,
|
||||||
open var valueDate: Date,
|
override var valueDate: Date,
|
||||||
open var statementNumber: Int,
|
override var statementNumber: Int,
|
||||||
open var sequenceNumber: Int?,
|
override var sequenceNumber: Int?,
|
||||||
open var openingBalance: BigDecimal?,
|
override var openingBalance: BigDecimal?,
|
||||||
open var closingBalance: BigDecimal?,
|
override var closingBalance: BigDecimal?,
|
||||||
|
|
||||||
open var endToEndReference: String?,
|
override var endToEndReference: String?,
|
||||||
open var customerReference: String?,
|
override var customerReference: String?,
|
||||||
open var mandateReference: String?,
|
override var mandateReference: String?,
|
||||||
open var creditorIdentifier: String?,
|
override var creditorIdentifier: String?,
|
||||||
open var originatorsIdentificationCode: String?,
|
override var originatorsIdentificationCode: String?,
|
||||||
open var compensationAmount: String?,
|
override var compensationAmount: String?,
|
||||||
open var originalAmount: String?,
|
override var originalAmount: String?,
|
||||||
open var sepaUsage: String?,
|
override var sepaUsage: String?,
|
||||||
open var deviantOriginator: String?,
|
override var deviantOriginator: String?,
|
||||||
open var deviantRecipient: String?,
|
override var deviantRecipient: String?,
|
||||||
open var usageWithNoSpecialType: String?,
|
override var usageWithNoSpecialType: String?,
|
||||||
open var primaNotaNumber: String?,
|
override var primaNotaNumber: String?,
|
||||||
open var textKeySupplement: String?,
|
override var textKeySupplement: String?,
|
||||||
|
|
||||||
open var currencyType: String?,
|
override var currencyType: String?,
|
||||||
open var bookingKey: String,
|
override var bookingKey: String,
|
||||||
open var referenceForTheAccountOwner: String,
|
override var referenceForTheAccountOwner: String,
|
||||||
open var referenceOfTheAccountServicingInstitution: String?,
|
override var referenceOfTheAccountServicingInstitution: String?,
|
||||||
open var supplementaryDetails: String?,
|
override var supplementaryDetails: String?,
|
||||||
|
|
||||||
open var transactionReferenceNumber: String,
|
override var transactionReferenceNumber: String,
|
||||||
open var relatedReferenceNumber: String?,
|
override var relatedReferenceNumber: String?,
|
||||||
var id: String = UUID.random().toString()
|
override var technicalId: String = UUID.random()
|
||||||
) {
|
) : IAccountTransaction {
|
||||||
|
|
||||||
// for object deserializers
|
// for object deserializers
|
||||||
internal constructor() : this(BankAccountEntity(), BigDecimal.Zero, "", "", Date(), null, null, null, null, Date(),
|
internal constructor() : this(BankAccountEntity(), BigDecimal.Zero, "", "", Date(), null, null, null, null, Date(),
|
||||||
-1, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null,
|
-1, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null,
|
||||||
null, "", null)
|
null, "", null)
|
||||||
|
|
||||||
|
constructor(bankAccount: BankAccountEntity, otherPartyName: String?, unparsedUsage: String, amount: BigDecimal, valueDate: Date, bookingText: String?)
|
||||||
|
: this(bankAccount, amount, "EUR", unparsedUsage, valueDate, otherPartyName, null, null, bookingText, valueDate, 0, null, null, null,
|
||||||
|
null, null, null, null, null, null, null, null, null, null, null, null, null,
|
||||||
|
null, "", "", null, null, "", null)
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,37 +2,39 @@ package net.dankito.banking.persistence.model
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
||||||
import net.dankito.banking.ui.model.BankAccountType
|
import net.dankito.banking.ui.model.*
|
||||||
import net.dankito.utils.multiplatform.BigDecimal
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
import net.dankito.utils.multiplatform.Date
|
import net.dankito.utils.multiplatform.Date
|
||||||
import net.dankito.utils.multiplatform.UUID
|
import net.dankito.utils.multiplatform.UUID
|
||||||
|
|
||||||
|
|
||||||
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
@JsonIdentityInfo(property = "technicalId", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
||||||
// had to define all properties as 'var' 'cause MapStruct cannot handle vals (and cannot use Pozo's mapstruct-kotlin as SerializableBankAccountBuilder would fail with @Context)
|
// had to define all properties as 'var' 'cause MapStruct cannot handle vals (and cannot use Pozo's mapstruct-kotlin as SerializableBankAccountBuilder would fail with @Context)
|
||||||
open class BankAccountEntity(
|
open class BankAccountEntity(
|
||||||
open var customer: CustomerEntity,
|
override var customer: CustomerEntity,
|
||||||
open var identifier: String,
|
override var identifier: String,
|
||||||
open var accountHolderName: String,
|
override var accountHolderName: String,
|
||||||
open var iban: String?,
|
override var iban: String?,
|
||||||
open var subAccountNumber: String?,
|
override var subAccountNumber: String?,
|
||||||
open var customerId: String,
|
override var customerId: String,
|
||||||
open var balance: BigDecimal = BigDecimal.Zero,
|
override var balance: BigDecimal = BigDecimal.Zero,
|
||||||
open var currency: String = "EUR",
|
override var currency: String = "EUR",
|
||||||
open var type: BankAccountType = BankAccountType.Girokonto,
|
override var type: BankAccountType = BankAccountType.Girokonto,
|
||||||
open var productName: String? = null,
|
override var productName: String? = null,
|
||||||
open var accountLimit: String? = null,
|
override var accountLimit: String? = null,
|
||||||
open var lastRetrievedTransactionsTimestamp: Date? = null,
|
override var lastRetrievedTransactionsTimestamp: Date? = null,
|
||||||
open var supportsRetrievingAccountTransactions: Boolean = false,
|
override var supportsRetrievingAccountTransactions: Boolean = false,
|
||||||
open var supportsRetrievingBalance: Boolean = false,
|
override var supportsRetrievingBalance: Boolean = false,
|
||||||
open var supportsTransferringMoney: Boolean = false,
|
override var supportsTransferringMoney: Boolean = false,
|
||||||
open var supportsInstantPaymentMoneyTransfer: Boolean = false,
|
override var supportsInstantPaymentMoneyTransfer: Boolean = false,
|
||||||
open var bookedTransactions: List<AccountTransactionEntity> = listOf(),
|
override var bookedTransactions: List<AccountTransactionEntity> = listOf(),
|
||||||
open var unbookedTransactions: List<Any> = listOf(),
|
override var unbookedTransactions: List<Any> = listOf(),
|
||||||
open var id: String = UUID.random().toString(),
|
override var technicalId: String = UUID.random(),
|
||||||
open var userSetDisplayName: String? = null
|
override var userSetDisplayName: String? = null,
|
||||||
|
override var haveAllTransactionsBeenFetched: Boolean = false,
|
||||||
|
override var displayIndex: Int = 0
|
||||||
|
|
||||||
) {
|
) : IBankAccount<AccountTransactionEntity> {
|
||||||
|
|
||||||
internal constructor() : this(CustomerEntity(), "", "", null, null, "") // for object deserializers
|
internal constructor() : this(CustomerEntity(), "", "", null, null, "") // for object deserializers
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,32 @@
|
||||||
package net.dankito.banking.persistence.model
|
package net.dankito.banking.persistence.model
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.*
|
import com.fasterxml.jackson.annotation.*
|
||||||
|
import net.dankito.banking.ui.model.ICustomer
|
||||||
import net.dankito.banking.ui.model.tan.TanMedium
|
import net.dankito.banking.ui.model.tan.TanMedium
|
||||||
import net.dankito.banking.ui.model.tan.TanProcedure
|
import net.dankito.banking.ui.model.tan.TanProcedure
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
@JsonIdentityInfo(property = "technicalId", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
||||||
// had to define all properties as 'var' 'cause MapStruct cannot handle vals (and cannot use Pozo's mapstruct-kotlin as SerializableCustomerBuilder would fail with @Context)
|
// had to define all properties as 'var' 'cause MapStruct cannot handle vals (and cannot use Pozo's mapstruct-kotlin as SerializableCustomerBuilder would fail with @Context)
|
||||||
open class CustomerEntity(
|
open class CustomerEntity(
|
||||||
var bankCode: String,
|
override var bankCode: String,
|
||||||
var customerId: String,
|
override var customerId: String,
|
||||||
var password: String,
|
override var password: String,
|
||||||
var finTsServerAddress: String,
|
override var finTsServerAddress: String,
|
||||||
var bankName: String,
|
override var bankName: String,
|
||||||
var bic: String,
|
override var bic: String,
|
||||||
var customerName: String,
|
override var customerName: String,
|
||||||
var userId: String = customerId,
|
override var userId: String = customerId,
|
||||||
var iconUrl: String? = null,
|
override var iconUrl: String? = null,
|
||||||
var accounts: List<BankAccountEntity> = listOf(),
|
override var accounts: List<BankAccountEntity> = listOf(),
|
||||||
var supportedTanProcedures: List<TanProcedure> = listOf(),
|
override var supportedTanProcedures: List<TanProcedure> = listOf(),
|
||||||
var selectedTanProcedure: TanProcedure? = null,
|
override var selectedTanProcedure: TanProcedure? = null,
|
||||||
var tanMedia: List<TanMedium> = listOf(),
|
override var tanMedia: List<TanMedium> = listOf(),
|
||||||
var id: String = UUID.randomUUID().toString(),
|
override var technicalId: String = UUID.randomUUID().toString(),
|
||||||
var userSetDisplayName: String? = null
|
override var userSetDisplayName: String? = null,
|
||||||
) {
|
override var displayIndex: Int = 0
|
||||||
|
) : ICustomer<BankAccountEntity, AccountTransactionEntity> {
|
||||||
|
|
||||||
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
package net.dankito.banking.persistence
|
package net.dankito.banking.persistence
|
||||||
|
|
||||||
import net.dankito.banking.persistence.mapper.CustomerConverter
|
|
||||||
import net.dankito.banking.persistence.mapper.CycleAvoidingMappingContext
|
|
||||||
import net.dankito.banking.persistence.model.AccountTransactionEntity
|
import net.dankito.banking.persistence.model.AccountTransactionEntity
|
||||||
import net.dankito.banking.persistence.model.BankAccountEntity
|
import net.dankito.banking.persistence.model.BankAccountEntity
|
||||||
import net.dankito.banking.persistence.model.CustomerEntity
|
import net.dankito.banking.persistence.model.CustomerEntity
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
import net.dankito.banking.ui.model.*
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
|
||||||
import net.dankito.banking.ui.model.Customer
|
|
||||||
import net.dankito.banking.util.JacksonJsonSerializer
|
import net.dankito.banking.util.JacksonJsonSerializer
|
||||||
import net.dankito.utils.multiplatform.BigDecimal
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
import net.dankito.utils.multiplatform.Date
|
import net.dankito.utils.multiplatform.Date
|
||||||
|
@ -15,7 +11,6 @@ import net.dankito.utils.multiplatform.File
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mapstruct.factory.Mappers
|
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,7 +67,7 @@ class BankingPersistenceJsonTest {
|
||||||
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
underTest.saveOrUpdateAccount(customers.first(), customers)
|
underTest.saveOrUpdateAccount(customers.first() as TypedCustomer, customers.map { it as TypedCustomer })
|
||||||
|
|
||||||
|
|
||||||
// then
|
// then
|
||||||
|
@ -89,13 +84,13 @@ class BankingPersistenceJsonTest {
|
||||||
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
underTest.saveOrUpdateAccount(customer, listOf(customer))
|
underTest.saveOrUpdateAccount(customer as TypedCustomer, listOf(customer).map { it as TypedCustomer })
|
||||||
|
|
||||||
|
|
||||||
// then
|
// then
|
||||||
val result = serializer.deserializeListOr(file, CustomerEntity::class)
|
val result = serializer.deserializeListOr(file, CustomerEntity::class)
|
||||||
|
|
||||||
assertCustomersEqual(result, listOf(customer))
|
assertCustomersEqual(result, listOf(customer) as List<CustomerEntity>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,9 +102,8 @@ class BankingPersistenceJsonTest {
|
||||||
createCustomer(2),
|
createCustomer(2),
|
||||||
createCustomer(3)
|
createCustomer(3)
|
||||||
)
|
)
|
||||||
val serializableCustomers = Mappers.getMapper(CustomerConverter::class.java).mapCustomers(customers, CycleAvoidingMappingContext())
|
|
||||||
|
|
||||||
serializer.serializeObject(serializableCustomers, file)
|
serializer.serializeObject(customers, file)
|
||||||
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
|
@ -117,19 +111,19 @@ class BankingPersistenceJsonTest {
|
||||||
|
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertCustomersEqual(serializableCustomers, result)
|
assertCustomersEqual(customers, result as List<CustomerEntity>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun createCustomer(countBankAccounts: Int = 0, customerId: String = CustomerId): Customer {
|
private fun createCustomer(countBankAccounts: Int = 0, customerId: String = CustomerId): CustomerEntity {
|
||||||
val result = Customer(BankCode, customerId, Password, FinTsServerAddress, BankName, Bic, CustomerName, UserId, IconUrl)
|
val result = CustomerEntity(BankCode, customerId, Password, FinTsServerAddress, BankName, Bic, CustomerName, UserId, IconUrl)
|
||||||
|
|
||||||
result.accounts = createBankAccounts(countBankAccounts, result)
|
result.accounts = createBankAccounts(countBankAccounts, result)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createBankAccounts(count: Int, customer: Customer): List<BankAccount> {
|
private fun createBankAccounts(count: Int, customer: CustomerEntity): List<BankAccountEntity> {
|
||||||
val random = Random(System.nanoTime())
|
val random = Random(System.nanoTime())
|
||||||
|
|
||||||
return IntRange(1, count).map { accountIndex ->
|
return IntRange(1, count).map { accountIndex ->
|
||||||
|
@ -137,8 +131,8 @@ class BankingPersistenceJsonTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createBankAccount(productName: String, customer: Customer, countTransactions: Int = 0): BankAccount {
|
private fun createBankAccount(productName: String, customer: CustomerEntity, countTransactions: Int = 0): BankAccountEntity {
|
||||||
val result = BankAccount(customer, customer.customerId, "AccountHolder", "DE00" + customer.bankCode + customer.customerId, null,
|
val result = BankAccountEntity(customer, customer.customerId, "AccountHolder", "DE00" + customer.bankCode + customer.customerId, null,
|
||||||
customer.customerId, BigDecimal(84.25), productName = productName)
|
customer.customerId, BigDecimal(84.25), productName = productName)
|
||||||
|
|
||||||
result.bookedTransactions = createAccountTransactions(countTransactions, result)
|
result.bookedTransactions = createAccountTransactions(countTransactions, result)
|
||||||
|
@ -146,14 +140,14 @@ class BankingPersistenceJsonTest {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createAccountTransactions(countTransactions: Int, account: BankAccount): List<AccountTransaction> {
|
private fun createAccountTransactions(countTransactions: Int, account: BankAccountEntity): List<AccountTransactionEntity> {
|
||||||
return IntRange(1, countTransactions).map { transactionIndex ->
|
return IntRange(1, countTransactions).map { transactionIndex ->
|
||||||
createAccountTransaction(transactionIndex, account)
|
createAccountTransaction(transactionIndex, account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createAccountTransaction(transactionIndex: Int, account: BankAccount): AccountTransaction {
|
private fun createAccountTransaction(transactionIndex: Int, account: BankAccountEntity): AccountTransactionEntity {
|
||||||
return AccountTransaction(account, "OtherParty_$transactionIndex", "Usage_$transactionIndex", BigDecimal(transactionIndex.toDouble()), createDate(), null)
|
return AccountTransactionEntity(account, "OtherParty_$transactionIndex", "Usage_$transactionIndex", BigDecimal(transactionIndex.toDouble()), createDate(), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDate(): Date {
|
private fun createDate(): Date {
|
||||||
|
@ -161,11 +155,11 @@ class BankingPersistenceJsonTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun assertCustomersEqual(deserializedCustomers: List<CustomerEntity>, customers: List<Customer>) {
|
private fun assertCustomersEqual(deserializedCustomers: List<CustomerEntity>, customers: List<CustomerEntity>) {
|
||||||
assertThat(deserializedCustomers.size).isEqualTo(customers.size)
|
assertThat(deserializedCustomers.size).isEqualTo(customers.size)
|
||||||
|
|
||||||
deserializedCustomers.forEach { deserializedCustomer ->
|
deserializedCustomers.forEach { deserializedCustomer ->
|
||||||
val customer = customers.firstOrNull { it.technicalId == deserializedCustomer.id }
|
val customer = customers.firstOrNull { it.technicalId == deserializedCustomer.technicalId }
|
||||||
|
|
||||||
if (customer == null) {
|
if (customer == null) {
|
||||||
Assert.fail("Could not find matching customer for deserialized customer $deserializedCustomer. customers = $customers")
|
Assert.fail("Could not find matching customer for deserialized customer $deserializedCustomer. customers = $customers")
|
||||||
|
@ -176,7 +170,7 @@ class BankingPersistenceJsonTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertCustomersEqual(deserializedCustomer: CustomerEntity, customer: Customer) {
|
private fun assertCustomersEqual(deserializedCustomer: CustomerEntity, customer: CustomerEntity) {
|
||||||
assertThat(deserializedCustomer.bankCode).isEqualTo(customer.bankCode)
|
assertThat(deserializedCustomer.bankCode).isEqualTo(customer.bankCode)
|
||||||
assertThat(deserializedCustomer.customerId).isEqualTo(customer.customerId)
|
assertThat(deserializedCustomer.customerId).isEqualTo(customer.customerId)
|
||||||
assertThat(deserializedCustomer.password).isEqualTo(customer.password)
|
assertThat(deserializedCustomer.password).isEqualTo(customer.password)
|
||||||
|
@ -191,11 +185,11 @@ class BankingPersistenceJsonTest {
|
||||||
assertBankAccountsEqual(deserializedCustomer.accounts, customer.accounts)
|
assertBankAccountsEqual(deserializedCustomer.accounts, customer.accounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertBankAccountsEqual(deserializedAccounts: List<BankAccountEntity>, accounts: List<BankAccount>) {
|
private fun assertBankAccountsEqual(deserializedAccounts: List<BankAccountEntity>, accounts: List<BankAccountEntity>) {
|
||||||
assertThat(deserializedAccounts.size).isEqualTo(accounts.size)
|
assertThat(deserializedAccounts.size).isEqualTo(accounts.size)
|
||||||
|
|
||||||
deserializedAccounts.forEach { deserializedAccount ->
|
deserializedAccounts.forEach { deserializedAccount ->
|
||||||
val account = accounts.firstOrNull { it.technicalId == deserializedAccount.id }
|
val account = accounts.firstOrNull { it.technicalId == deserializedAccount.technicalId }
|
||||||
|
|
||||||
if (account == null) {
|
if (account == null) {
|
||||||
Assert.fail("Could not find matching account for deserialized account $deserializedAccount. accounts = $accounts")
|
Assert.fail("Could not find matching account for deserialized account $deserializedAccount. accounts = $accounts")
|
||||||
|
@ -206,9 +200,9 @@ class BankingPersistenceJsonTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertBankAccountsEqual(deserializedAccount: BankAccountEntity, account: BankAccount) {
|
private fun assertBankAccountsEqual(deserializedAccount: BankAccountEntity, account: BankAccountEntity) {
|
||||||
// to check if MapStruct created reference correctly
|
// to check if MapStruct created reference correctly
|
||||||
assertThat(deserializedAccount.customer.id).isEqualTo(account.customer.technicalId)
|
assertThat(deserializedAccount.customer.technicalId).isEqualTo(account.customer.technicalId)
|
||||||
|
|
||||||
assertThat(deserializedAccount.identifier).isEqualTo(account.identifier)
|
assertThat(deserializedAccount.identifier).isEqualTo(account.identifier)
|
||||||
assertThat(deserializedAccount.iban).isEqualTo(account.iban)
|
assertThat(deserializedAccount.iban).isEqualTo(account.iban)
|
||||||
|
@ -219,11 +213,11 @@ class BankingPersistenceJsonTest {
|
||||||
assertAccountTransactionsEqual(deserializedAccount.bookedTransactions, account.bookedTransactions)
|
assertAccountTransactionsEqual(deserializedAccount.bookedTransactions, account.bookedTransactions)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertAccountTransactionsEqual(deserializedTransactions: List<AccountTransactionEntity>, transactions: List<AccountTransaction>) {
|
private fun assertAccountTransactionsEqual(deserializedTransactions: List<AccountTransactionEntity>, transactions: List<AccountTransactionEntity>) {
|
||||||
assertThat(deserializedTransactions.size).isEqualTo(transactions.size)
|
assertThat(deserializedTransactions.size).isEqualTo(transactions.size)
|
||||||
|
|
||||||
deserializedTransactions.forEach { deserializedTransaction ->
|
deserializedTransactions.forEach { deserializedTransaction ->
|
||||||
val transaction = transactions.firstOrNull { it.technicalId == deserializedTransaction.id }
|
val transaction = transactions.firstOrNull { it.technicalId == deserializedTransaction.technicalId }
|
||||||
|
|
||||||
if (transaction == null) {
|
if (transaction == null) {
|
||||||
Assert.fail("Could not find matching transaction for deserialized transaction $deserializedTransaction. transactions = $transactions")
|
Assert.fail("Could not find matching transaction for deserialized transaction $deserializedTransaction. transactions = $transactions")
|
||||||
|
@ -234,9 +228,9 @@ class BankingPersistenceJsonTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertAccountTransactionsEqual(deserializedTransaction: AccountTransactionEntity, transaction: AccountTransaction) {
|
private fun assertAccountTransactionsEqual(deserializedTransaction: AccountTransactionEntity, transaction: AccountTransactionEntity) {
|
||||||
// to check if MapStruct created reference correctly
|
// to check if MapStruct created reference correctly
|
||||||
assertThat(deserializedTransaction.bankAccount.id).isEqualTo(transaction.bankAccount.technicalId)
|
assertThat(deserializedTransaction.bankAccount.technicalId).isEqualTo(transaction.bankAccount.technicalId)
|
||||||
|
|
||||||
assertThat(deserializedTransaction.otherPartyName).isEqualTo(transaction.otherPartyName)
|
assertThat(deserializedTransaction.otherPartyName).isEqualTo(transaction.otherPartyName)
|
||||||
assertThat(deserializedTransaction.unparsedUsage).isEqualTo(transaction.unparsedUsage)
|
assertThat(deserializedTransaction.unparsedUsage).isEqualTo(transaction.unparsedUsage)
|
||||||
|
|
|
@ -3,7 +3,7 @@ package net.dankito.banking.ui.android
|
||||||
import net.dankito.banking.ui.android.util.CurrentActivityTracker
|
import net.dankito.banking.ui.android.util.CurrentActivityTracker
|
||||||
import net.dankito.banking.ui.IRouter
|
import net.dankito.banking.ui.IRouter
|
||||||
import net.dankito.banking.ui.android.dialogs.*
|
import net.dankito.banking.ui.android.dialogs.*
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||||
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
||||||
import net.dankito.banking.ui.model.tan.EnterTanResult
|
import net.dankito.banking.ui.model.tan.EnterTanResult
|
||||||
|
@ -20,7 +20,7 @@ open class RouterAndroid(protected val activityTracker: CurrentActivityTracker)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTanFromUserFromNonUiThread(customer: Customer, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: (EnterTanResult) -> Unit) {
|
override fun getTanFromUserFromNonUiThread(customer: TypedCustomer, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: (EnterTanResult) -> Unit) {
|
||||||
activityTracker.currentOrNextActivity { activity ->
|
activityTracker.currentOrNextActivity { activity ->
|
||||||
activity.runOnUiThread {
|
activity.runOnUiThread {
|
||||||
EnterTanDialog().show(customer, tanChallenge, activity, false) { result ->
|
EnterTanDialog().show(customer, tanChallenge, activity, false) { result ->
|
||||||
|
|
|
@ -6,7 +6,7 @@ import android.view.View
|
||||||
import net.dankito.banking.ui.android.R
|
import net.dankito.banking.ui.android.R
|
||||||
import net.dankito.banking.ui.android.adapter.viewholder.AccountTransactionViewHolder
|
import net.dankito.banking.ui.android.adapter.viewholder.AccountTransactionViewHolder
|
||||||
import net.dankito.banking.ui.android.extensions.showAmount
|
import net.dankito.banking.ui.android.extensions.showAmount
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
import net.dankito.banking.ui.model.IAccountTransaction
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
import net.dankito.utils.android.extensions.asActivity
|
import net.dankito.utils.android.extensions.asActivity
|
||||||
import net.dankito.utils.android.ui.adapter.ListRecyclerAdapter
|
import net.dankito.utils.android.ui.adapter.ListRecyclerAdapter
|
||||||
|
@ -14,14 +14,14 @@ import java.text.DateFormat
|
||||||
|
|
||||||
|
|
||||||
open class AccountTransactionAdapter(protected val presenter: BankingPresenter)
|
open class AccountTransactionAdapter(protected val presenter: BankingPresenter)
|
||||||
: ListRecyclerAdapter<AccountTransaction, AccountTransactionViewHolder>() {
|
: ListRecyclerAdapter<IAccountTransaction, AccountTransactionViewHolder>() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ValueDateFormat = DateFormat.getDateInstance(DateFormat.SHORT)
|
val ValueDateFormat = DateFormat.getDateInstance(DateFormat.SHORT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var selectedTransaction: AccountTransaction? = null
|
var selectedTransaction: IAccountTransaction? = null
|
||||||
|
|
||||||
|
|
||||||
override fun getListItemLayoutId() = R.layout.list_item_account_transaction
|
override fun getListItemLayoutId() = R.layout.list_item_account_transaction
|
||||||
|
@ -34,7 +34,7 @@ open class AccountTransactionAdapter(protected val presenter: BankingPresenter)
|
||||||
return viewHolder
|
return viewHolder
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindItemToView(viewHolder: AccountTransactionViewHolder, item: AccountTransaction) {
|
override fun bindItemToView(viewHolder: AccountTransactionViewHolder, item: IAccountTransaction) {
|
||||||
viewHolder.txtvwDate.text = ValueDateFormat.format(item.valueDate)
|
viewHolder.txtvwDate.text = ValueDateFormat.format(item.valueDate)
|
||||||
|
|
||||||
val label = if (item.showOtherPartyName) item.otherPartyName else item.bookingText
|
val label = if (item.showOtherPartyName) item.otherPartyName else item.bookingText
|
||||||
|
|
|
@ -8,11 +8,11 @@ import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import kotlinx.android.synthetic.main.list_item_bank_account.view.*
|
import kotlinx.android.synthetic.main.list_item_bank_account.view.*
|
||||||
import net.dankito.banking.ui.android.R
|
import net.dankito.banking.ui.android.R
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
import net.dankito.banking.ui.model.TypedBankAccount
|
||||||
import net.dankito.utils.android.ui.adapter.ListAdapter
|
import net.dankito.utils.android.ui.adapter.ListAdapter
|
||||||
|
|
||||||
|
|
||||||
open class BankAccountsAdapter(bankAccounts: List<BankAccount>) : ListAdapter<BankAccount>(bankAccounts) {
|
open class BankAccountsAdapter(bankAccounts: List<TypedBankAccount>) : ListAdapter<TypedBankAccount>(bankAccounts) {
|
||||||
|
|
||||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ open class BankAccountsAdapter(bankAccounts: List<BankAccount>) : ListAdapter<Ba
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun setIcon(bankAccount: BankAccount, imgBankIcon: ImageView) {
|
protected open fun setIcon(bankAccount: TypedBankAccount, imgBankIcon: ImageView) {
|
||||||
try {
|
try {
|
||||||
val iconUrl = bankAccount.customer.iconUrl
|
val iconUrl = bankAccount.customer.iconUrl
|
||||||
imgBankIcon.visibility = if (iconUrl == null) View.GONE else View.VISIBLE
|
imgBankIcon.visibility = if (iconUrl == null) View.GONE else View.VISIBLE
|
||||||
|
|
|
@ -17,12 +17,11 @@ import net.dankito.banking.ui.IRouter
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
import net.dankito.banking.bankfinder.IBankFinder
|
import net.dankito.banking.bankfinder.IBankFinder
|
||||||
import net.dankito.banking.bankfinder.LuceneBankFinder
|
import net.dankito.banking.bankfinder.LuceneBankFinder
|
||||||
|
import net.dankito.banking.persistence.mapper.EntitiesModelCreator
|
||||||
|
import net.dankito.banking.ui.model.mapper.IModelCreator
|
||||||
import net.dankito.utils.multiplatform.toFile
|
import net.dankito.utils.multiplatform.toFile
|
||||||
import net.dankito.banking.util.*
|
import net.dankito.banking.util.*
|
||||||
import net.dankito.banking.util.extraction.IInvoiceDataExtractor
|
import net.dankito.banking.util.extraction.*
|
||||||
import net.dankito.banking.util.extraction.ITextExtractorRegistry
|
|
||||||
import net.dankito.banking.util.extraction.JavaInvoiceDataExtractor
|
|
||||||
import net.dankito.banking.util.extraction.JavaTextExtractorRegistry
|
|
||||||
import net.dankito.text.extraction.TextExtractorRegistry
|
import net.dankito.text.extraction.TextExtractorRegistry
|
||||||
import net.dankito.text.extraction.pdf.PdfBoxAndroidPdfTextExtractor
|
import net.dankito.text.extraction.pdf.PdfBoxAndroidPdfTextExtractor
|
||||||
import net.dankito.text.extraction.pdf.iText2PdfTextExtractor
|
import net.dankito.text.extraction.pdf.iText2PdfTextExtractor
|
||||||
|
@ -91,9 +90,9 @@ class BankingModule(private val applicationContext: Context) {
|
||||||
@Named(DataFolderKey) dataFolder: File,
|
@Named(DataFolderKey) dataFolder: File,
|
||||||
persister: IBankingPersistence, remitteeSearcher: IRemitteeSearcher, bankIconFinder: IBankIconFinder,
|
persister: IBankingPersistence, remitteeSearcher: IRemitteeSearcher, bankIconFinder: IBankIconFinder,
|
||||||
textExtractorRegistry: ITextExtractorRegistry, router: IRouter, invoiceDataExtractor: IInvoiceDataExtractor,
|
textExtractorRegistry: ITextExtractorRegistry, router: IRouter, invoiceDataExtractor: IInvoiceDataExtractor,
|
||||||
serializer: ISerializer, asyncRunner: IAsyncRunner) : BankingPresenter {
|
modelCreator: IModelCreator, serializer: ISerializer, asyncRunner: IAsyncRunner) : BankingPresenter {
|
||||||
return BankingPresenter(bankingClientCreator, bankFinder, dataFolder, persister,
|
return BankingPresenter(bankingClientCreator, bankFinder, dataFolder, persister, router, modelCreator,
|
||||||
router, remitteeSearcher, bankIconFinder, textExtractorRegistry, invoiceDataExtractor, serializer, asyncRunner)
|
remitteeSearcher, bankIconFinder, textExtractorRegistry, invoiceDataExtractor, serializer, asyncRunner)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -110,8 +109,8 @@ class BankingModule(private val applicationContext: Context) {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideBankingClientCreator(serializer: ISerializer) : IBankingClientCreator {
|
fun provideBankingClientCreator(modelCreator: IModelCreator, serializer: ISerializer) : IBankingClientCreator {
|
||||||
return fints4kBankingClientCreator(serializer)
|
return fints4kBankingClientCreator(modelCreator, serializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -151,7 +150,7 @@ class BankingModule(private val applicationContext: Context) {
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideInvoiceDataExtractor() : IInvoiceDataExtractor {
|
fun provideInvoiceDataExtractor() : IInvoiceDataExtractor {
|
||||||
return JavaInvoiceDataExtractor()
|
return NoOpInvoiceDataExtractor()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,6 +166,12 @@ class BankingModule(private val applicationContext: Context) {
|
||||||
return JacksonJsonSerializer()
|
return JacksonJsonSerializer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideModelCreator() : IModelCreator {
|
||||||
|
return EntitiesModelCreator()
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideAsyncRunner() : IAsyncRunner {
|
fun provideAsyncRunner() : IAsyncRunner {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import net.dankito.banking.ui.android.adapter.TanMediumAdapter
|
||||||
import net.dankito.banking.ui.android.adapter.TanProceduresAdapter
|
import net.dankito.banking.ui.android.adapter.TanProceduresAdapter
|
||||||
import net.dankito.banking.ui.android.di.BankingComponent
|
import net.dankito.banking.ui.android.di.BankingComponent
|
||||||
import net.dankito.banking.ui.android.listener.ListItemSelectedListener
|
import net.dankito.banking.ui.android.listener.ListItemSelectedListener
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||||
import net.dankito.banking.ui.model.tan.*
|
import net.dankito.banking.ui.model.tan.*
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
|
@ -41,7 +41,7 @@ open class EnterTanDialog : DialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected lateinit var customer: Customer
|
protected lateinit var customer: TypedCustomer
|
||||||
|
|
||||||
protected lateinit var tanChallenge: TanChallenge
|
protected lateinit var tanChallenge: TanChallenge
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ open class EnterTanDialog : DialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun show(customer: Customer, tanChallenge: TanChallenge, activity: AppCompatActivity,
|
open fun show(customer: TypedCustomer, tanChallenge: TanChallenge, activity: AppCompatActivity,
|
||||||
fullscreen: Boolean = false, tanEnteredCallback: (EnterTanResult) -> Unit) {
|
fullscreen: Boolean = false, tanEnteredCallback: (EnterTanResult) -> Unit) {
|
||||||
|
|
||||||
this.customer = customer
|
this.customer = customer
|
||||||
|
|
|
@ -27,7 +27,7 @@ import net.dankito.banking.ui.android.listener.ListItemSelectedListener
|
||||||
import net.dankito.banking.ui.android.util.StandardAutocompleteCallback
|
import net.dankito.banking.ui.android.util.StandardAutocompleteCallback
|
||||||
import net.dankito.banking.ui.android.util.StandardTextWatcher
|
import net.dankito.banking.ui.android.util.StandardTextWatcher
|
||||||
import net.dankito.banking.search.Remittee
|
import net.dankito.banking.search.Remittee
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
import net.dankito.banking.ui.model.TypedBankAccount
|
||||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||||
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
|
@ -52,7 +52,7 @@ open class TransferMoneyDialog : DialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected lateinit var bankAccount: BankAccount
|
protected lateinit var bankAccount: TypedBankAccount
|
||||||
|
|
||||||
protected var preselectedValues: TransferMoneyData? = null
|
protected var preselectedValues: TransferMoneyData? = null
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import com.mikepenz.materialdrawer.util.removeItemByPosition
|
||||||
import com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView
|
import com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView
|
||||||
import net.dankito.banking.ui.android.R
|
import net.dankito.banking.ui.android.R
|
||||||
import net.dankito.banking.ui.android.extensions.withIcon
|
import net.dankito.banking.ui.android.extensions.withIcon
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ open class DrawerView(
|
||||||
}.flatten()
|
}.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createAccountDrawerItem(customer: Customer): IDrawerItem<*> {
|
private fun createAccountDrawerItem(customer: TypedCustomer): IDrawerItem<*> {
|
||||||
|
|
||||||
val accountItem = AccountDrawerItem()
|
val accountItem = AccountDrawerItem()
|
||||||
.withName(customer.displayName)
|
.withName(customer.displayName)
|
||||||
|
@ -160,7 +160,7 @@ open class DrawerView(
|
||||||
return accountItem
|
return accountItem
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createBankAccountsDrawerItems(customer: Customer): List<IDrawerItem<*>> {
|
private fun createBankAccountsDrawerItems(customer: TypedCustomer): List<IDrawerItem<*>> {
|
||||||
return customer.accounts.map { bankAccount ->
|
return customer.accounts.map { bankAccount ->
|
||||||
SecondaryDrawerItem()
|
SecondaryDrawerItem()
|
||||||
.withName(bankAccount.displayName)
|
.withName(bankAccount.displayName)
|
||||||
|
@ -176,13 +176,13 @@ open class DrawerView(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun closeDrawerAndEditAccount(customer: Customer) {
|
private fun closeDrawerAndEditAccount(customer: TypedCustomer) {
|
||||||
closeDrawer()
|
closeDrawer()
|
||||||
|
|
||||||
editAccount(customer)
|
editAccount(customer)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun editAccount(customer: Customer) {
|
private fun editAccount(customer: TypedCustomer) {
|
||||||
// TODO: implement editing account (e.g. displayed name etc.)
|
// TODO: implement editing account (e.g. displayed name etc.)
|
||||||
|
|
||||||
AlertDialog.Builder(activity)
|
AlertDialog.Builder(activity)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
import net.dankito.banking.util.BankIconFinder
|
import net.dankito.banking.util.BankIconFinder
|
||||||
import net.dankito.banking.bankfinder.LuceneBankFinder
|
import net.dankito.banking.bankfinder.LuceneBankFinder
|
||||||
import net.dankito.banking.persistence.LuceneBankingPersistence
|
import net.dankito.banking.persistence.LuceneBankingPersistence
|
||||||
|
import net.dankito.banking.persistence.mapper.EntitiesModelCreator
|
||||||
import net.dankito.banking.search.LuceneRemitteeSearcher
|
import net.dankito.banking.search.LuceneRemitteeSearcher
|
||||||
import net.dankito.banking.util.JacksonJsonSerializer
|
import net.dankito.banking.util.JacksonJsonSerializer
|
||||||
import net.dankito.banking.util.extraction.JavaTextExtractorRegistry
|
import net.dankito.banking.util.extraction.JavaTextExtractorRegistry
|
||||||
|
@ -32,6 +33,8 @@ class MainWindow : View(messages["application.title"]) {
|
||||||
|
|
||||||
private val indexFolder = ensureFolderExists(dataFolder, "index")
|
private val indexFolder = ensureFolderExists(dataFolder, "index")
|
||||||
|
|
||||||
|
private val modelCreator = EntitiesModelCreator()
|
||||||
|
|
||||||
private val serializer = JacksonJsonSerializer()
|
private val serializer = JacksonJsonSerializer()
|
||||||
|
|
||||||
private val tesseractTextExtractor = Tesseract4CommandlineImageTextExtractor(TesseractConfig(listOf(OcrLanguage.English, OcrLanguage.German)))
|
private val tesseractTextExtractor = Tesseract4CommandlineImageTextExtractor(TesseractConfig(listOf(OcrLanguage.English, OcrLanguage.German)))
|
||||||
|
@ -42,11 +45,11 @@ class MainWindow : View(messages["application.title"]) {
|
||||||
tesseractTextExtractor, TikaTextExtractor()
|
tesseractTextExtractor, TikaTextExtractor()
|
||||||
)))
|
)))
|
||||||
|
|
||||||
private val presenter = BankingPresenter(fints4kBankingClientCreator(serializer),
|
private val presenter = BankingPresenter(fints4kBankingClientCreator(modelCreator, serializer),
|
||||||
LuceneBankFinder(indexFolder), dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder),
|
LuceneBankFinder(indexFolder), dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder),
|
||||||
RouterJavaFx(), LuceneRemitteeSearcher(indexFolder), BankIconFinder(), textExtractorRegistry)
|
RouterJavaFx(), modelCreator, LuceneRemitteeSearcher(indexFolder), BankIconFinder(), textExtractorRegistry)
|
||||||
// private val presenter = BankingPresenter(hbci4jBankingClientCreator(), LuceneBankFinder(indexFolder),
|
// private val presenter = BankingPresenter(hbci4jBankingClientCreator(), LuceneBankFinder(indexFolder),
|
||||||
// dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder), RouterJavaFx(), LuceneRemitteeSearcher(indexFolder),
|
// dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder), RouterJavaFx(), modelCreator, LuceneRemitteeSearcher(indexFolder),
|
||||||
// BankIconFinder(), textExtractorRegistry)
|
// BankIconFinder(), textExtractorRegistry)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import net.dankito.banking.ui.IRouter
|
||||||
import net.dankito.banking.ui.javafx.dialogs.AddAccountDialog
|
import net.dankito.banking.ui.javafx.dialogs.AddAccountDialog
|
||||||
import net.dankito.banking.ui.javafx.dialogs.cashtransfer.TransferMoneyDialog
|
import net.dankito.banking.ui.javafx.dialogs.cashtransfer.TransferMoneyDialog
|
||||||
import net.dankito.banking.ui.javafx.dialogs.tan.EnterTanDialog
|
import net.dankito.banking.ui.javafx.dialogs.tan.EnterTanDialog
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||||
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
||||||
import net.dankito.banking.ui.model.tan.EnterTanResult
|
import net.dankito.banking.ui.model.tan.EnterTanResult
|
||||||
|
@ -22,7 +22,7 @@ open class RouterJavaFx : IRouter {
|
||||||
AddAccountDialog(presenter).show(messages["add.account.dialog.title"])
|
AddAccountDialog(presenter).show(messages["add.account.dialog.title"])
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTanFromUserFromNonUiThread(customer: Customer, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: (EnterTanResult) -> Unit) {
|
override fun getTanFromUserFromNonUiThread(customer: TypedCustomer, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: (EnterTanResult) -> Unit) {
|
||||||
FX.runAndWait {
|
FX.runAndWait {
|
||||||
EnterTanDialog(customer, tanChallenge, presenter) { result ->
|
EnterTanDialog(customer, tanChallenge, presenter) { result ->
|
||||||
callback(result)
|
callback(result)
|
||||||
|
|
|
@ -141,7 +141,7 @@ open class AccountTransactionsControlView(
|
||||||
|
|
||||||
protected open fun updateAccountTransactions(processingIndicatorButton: ProcessingIndicatorButton) {
|
protected open fun updateAccountTransactions(processingIndicatorButton: ProcessingIndicatorButton) {
|
||||||
// TODO: or only update transactions of selected accounts?
|
// TODO: or only update transactions of selected accounts?
|
||||||
presenter.updateAccountsTransactionsAsync { transactions ->
|
presenter.updateAccountsTransactionsAsync {
|
||||||
runLater {
|
runLater {
|
||||||
processingIndicatorButton.resetIsProcessing()
|
processingIndicatorButton.resetIsProcessing()
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import javafx.scene.control.TableView
|
||||||
import javafx.scene.layout.Priority
|
import javafx.scene.layout.Priority
|
||||||
import javafx.scene.paint.Color
|
import javafx.scene.paint.Color
|
||||||
import javafx.util.Callback
|
import javafx.util.Callback
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
import net.dankito.banking.ui.model.IAccountTransaction
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
import net.dankito.utils.javafx.ui.extensions.ensureOnlyUsesSpaceIfVisible
|
import net.dankito.utils.javafx.ui.extensions.ensureOnlyUsesSpaceIfVisible
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
@ -21,8 +21,8 @@ import java.text.DateFormat
|
||||||
|
|
||||||
open class AccountTransactionsTable @JvmOverloads constructor(
|
open class AccountTransactionsTable @JvmOverloads constructor(
|
||||||
protected val presenter: BankingPresenter,
|
protected val presenter: BankingPresenter,
|
||||||
transactions: ObservableList<AccountTransaction> = FXCollections.emptyObservableList<AccountTransaction>()
|
transactions: ObservableList<IAccountTransaction> = FXCollections.emptyObservableList()
|
||||||
) : TableView<AccountTransaction>(transactions) {
|
) : TableView<IAccountTransaction>(transactions) {
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -38,7 +38,7 @@ open class AccountTransactionsTable @JvmOverloads constructor(
|
||||||
|
|
||||||
|
|
||||||
protected open fun initUi() {
|
protected open fun initUi() {
|
||||||
column(messages["account.transactions.table.column.header.value.date"], AccountTransaction::valueDate) {
|
column(messages["account.transactions.table.column.header.value.date"], IAccountTransaction::valueDate) {
|
||||||
prefWidth = 115.0
|
prefWidth = 115.0
|
||||||
|
|
||||||
cellFormat {
|
cellFormat {
|
||||||
|
@ -48,7 +48,7 @@ open class AccountTransactionsTable @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
columns.add(TableColumn<AccountTransaction, AccountTransaction>(messages["account.transactions.table.column.header.usage"]).apply {
|
columns.add(TableColumn<IAccountTransaction, IAccountTransaction>(messages["account.transactions.table.column.header.usage"]).apply {
|
||||||
|
|
||||||
this.cellFormat {
|
this.cellFormat {
|
||||||
contentDisplay = ContentDisplay.GRAPHIC_ONLY
|
contentDisplay = ContentDisplay.GRAPHIC_ONLY
|
||||||
|
@ -80,8 +80,8 @@ open class AccountTransactionsTable @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cellValueFactory = Callback { object : ObjectBinding<AccountTransaction>() {
|
cellValueFactory = Callback { object : ObjectBinding<IAccountTransaction>() {
|
||||||
override fun computeValue(): AccountTransaction {
|
override fun computeValue(): IAccountTransaction {
|
||||||
return it.value
|
return it.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ open class AccountTransactionsTable @JvmOverloads constructor(
|
||||||
weightedWidth(4.0)
|
weightedWidth(4.0)
|
||||||
})
|
})
|
||||||
|
|
||||||
columns.add(TableColumn<AccountTransaction, String>(messages["account.transactions.table.column.header.amount"]).apply {
|
columns.add(TableColumn<IAccountTransaction, String>(messages["account.transactions.table.column.header.amount"]).apply {
|
||||||
prefWidth = 85.0
|
prefWidth = 85.0
|
||||||
|
|
||||||
this.cellFormat {
|
this.cellFormat {
|
||||||
|
|
|
@ -8,8 +8,8 @@ import javafx.scene.input.ContextMenuEvent
|
||||||
import javafx.scene.input.MouseButton
|
import javafx.scene.input.MouseButton
|
||||||
import javafx.scene.input.MouseEvent
|
import javafx.scene.input.MouseEvent
|
||||||
import net.dankito.banking.ui.javafx.dialogs.JavaFxDialogService
|
import net.dankito.banking.ui.javafx.dialogs.JavaFxDialogService
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
import net.dankito.banking.ui.model.IAccountTransaction
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
import net.dankito.banking.ui.model.TypedBankAccount
|
||||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||||
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
|
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
|
@ -24,7 +24,7 @@ open class AccountTransactionsView(private val presenter: BankingPresenter) : Vi
|
||||||
|
|
||||||
protected val balance = SimpleStringProperty("")
|
protected val balance = SimpleStringProperty("")
|
||||||
|
|
||||||
protected val transactionsToDisplay = FXCollections.observableArrayList<AccountTransaction>(listOf())
|
protected val transactionsToDisplay = FXCollections.observableArrayList<IAccountTransaction>(listOf())
|
||||||
|
|
||||||
|
|
||||||
protected var currentMenu: ContextMenu? = null
|
protected var currentMenu: ContextMenu? = null
|
||||||
|
@ -56,7 +56,7 @@ open class AccountTransactionsView(private val presenter: BankingPresenter) : Vi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected open fun tableClicked(event: MouseEvent, selectedItem: AccountTransaction?) {
|
protected open fun tableClicked(event: MouseEvent, selectedItem: IAccountTransaction?) {
|
||||||
if (event.button == MouseButton.PRIMARY || event.button == MouseButton.MIDDLE) {
|
if (event.button == MouseButton.PRIMARY || event.button == MouseButton.MIDDLE) {
|
||||||
currentMenu?.hide()
|
currentMenu?.hide()
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ open class AccountTransactionsView(private val presenter: BankingPresenter) : Vi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun createContextMenuForItems(selectedItem: AccountTransaction): ContextMenu {
|
protected open fun createContextMenuForItems(selectedItem: IAccountTransaction): ContextMenu {
|
||||||
val contextMenu = ContextMenu()
|
val contextMenu = ContextMenu()
|
||||||
|
|
||||||
contextMenu.apply {
|
contextMenu.apply {
|
||||||
|
@ -105,21 +105,21 @@ open class AccountTransactionsView(private val presenter: BankingPresenter) : Vi
|
||||||
return contextMenu
|
return contextMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun showTransactionDetailsDialog(transaction: AccountTransaction) {
|
protected open fun showTransactionDetailsDialog(transaction: IAccountTransaction) {
|
||||||
// TODO:
|
// TODO:
|
||||||
// presenter.showTransactionDetailsWindow(transaction.item)
|
// presenter.showTransactionDetailsWindow(transaction.item)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun newTransferToSameRemittee(transaction: AccountTransaction) {
|
protected open fun newTransferToSameRemittee(transaction: IAccountTransaction) {
|
||||||
presenter.showTransferMoneyDialog(TransferMoneyData.fromAccountTransactionWithoutAmountAndUsage(transaction))
|
presenter.showTransferMoneyDialog(TransferMoneyData.fromAccountTransactionWithoutAmountAndUsage(transaction))
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun newTransferWithSameData(transaction: AccountTransaction) {
|
protected open fun newTransferWithSameData(transaction: IAccountTransaction) {
|
||||||
presenter.showTransferMoneyDialog(TransferMoneyData.fromAccountTransaction(transaction))
|
presenter.showTransferMoneyDialog(TransferMoneyData.fromAccountTransaction(transaction))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected open fun handleSelectedBankAccountsChanged(selectedBankAccounts: List<BankAccount>) {
|
protected open fun handleSelectedBankAccountsChanged(selectedBankAccounts: List<TypedBankAccount>) {
|
||||||
runLater {
|
runLater {
|
||||||
isAccountSelected.value = selectedBankAccounts.isNotEmpty()
|
isAccountSelected.value = selectedBankAccounts.isNotEmpty()
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,13 @@ import javafx.scene.input.KeyCode
|
||||||
import net.dankito.banking.ui.javafx.dialogs.JavaFxDialogService
|
import net.dankito.banking.ui.javafx.dialogs.JavaFxDialogService
|
||||||
import net.dankito.banking.ui.javafx.model.AccountsAccountTreeItem
|
import net.dankito.banking.ui.javafx.model.AccountsAccountTreeItem
|
||||||
import net.dankito.banking.ui.javafx.model.AccountsRootTreeItem
|
import net.dankito.banking.ui.javafx.model.AccountsRootTreeItem
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import tornadofx.FX.Companion.messages
|
import tornadofx.FX.Companion.messages
|
||||||
|
|
||||||
|
|
||||||
open class AccountsTreeView(customers: ObservableList<Customer>, protected val presenter: BankingPresenter)
|
open class AccountsTreeView(customers: ObservableList<TypedCustomer>, protected val presenter: BankingPresenter)
|
||||||
: TreeView<String>(AccountsRootTreeItem(customers)) {
|
: TreeView<String>(AccountsRootTreeItem(customers)) {
|
||||||
|
|
||||||
protected var currentMenu: ContextMenu? = null
|
protected var currentMenu: ContextMenu? = null
|
||||||
|
|
|
@ -12,7 +12,7 @@ import javafx.scene.image.ImageView
|
||||||
import javafx.scene.layout.Priority
|
import javafx.scene.layout.Priority
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.dankito.banking.ui.javafx.dialogs.JavaFxDialogService
|
import net.dankito.banking.ui.javafx.dialogs.JavaFxDialogService
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
import net.dankito.banking.ui.model.TypedBankAccount
|
||||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||||
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
|
@ -49,7 +49,7 @@ open class TransferMoneyDialog @JvmOverloads constructor(
|
||||||
|
|
||||||
protected val bankAccountsSupportingTransferringMoney = FXCollections.observableArrayList(presenter.bankAccounts.filter { it.supportsTransferringMoney })
|
protected val bankAccountsSupportingTransferringMoney = FXCollections.observableArrayList(presenter.bankAccounts.filter { it.supportsTransferringMoney })
|
||||||
|
|
||||||
protected val selectedBankAccount = SimpleObjectProperty<BankAccount>(preselectedValues?.account ?: bankAccountsSupportingTransferringMoney.firstOrNull())
|
protected val selectedBankAccount = SimpleObjectProperty<TypedBankAccount>(preselectedValues?.account ?: bankAccountsSupportingTransferringMoney.firstOrNull())
|
||||||
|
|
||||||
protected val showBankAccounts = SimpleBooleanProperty(bankAccountsSupportingTransferringMoney.size > 1)
|
protected val showBankAccounts = SimpleBooleanProperty(bankAccountsSupportingTransferringMoney.size > 1)
|
||||||
|
|
||||||
|
@ -268,7 +268,7 @@ open class TransferMoneyDialog @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun selectedBankAccountChanged(newValue: BankAccount?) {
|
private fun selectedBankAccountChanged(newValue: TypedBankAccount?) {
|
||||||
supportsInstantPayment.value = newValue?.supportsInstantPaymentMoneyTransfer ?: false
|
supportsInstantPayment.value = newValue?.supportsInstantPaymentMoneyTransfer ?: false
|
||||||
|
|
||||||
if (supportsInstantPayment.value == false) {
|
if (supportsInstantPayment.value == false) {
|
||||||
|
@ -345,7 +345,7 @@ open class TransferMoneyDialog @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun transferMoney() {
|
protected open fun transferMoney() {
|
||||||
remitteeBank.value?.let { remitteeBank ->
|
remitteeBank.value?.let {
|
||||||
val bankAccount = selectedBankAccount.value
|
val bankAccount = selectedBankAccount.value
|
||||||
|
|
||||||
val data = TransferMoneyData(
|
val data = TransferMoneyData(
|
||||||
|
@ -366,7 +366,7 @@ open class TransferMoneyDialog @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun handleTransferMoneyResultOnUiThread(bankAccount: BankAccount, transferData: TransferMoneyData, response: BankingClientResponse) {
|
protected open fun handleTransferMoneyResultOnUiThread(bankAccount: TypedBankAccount, transferData: TransferMoneyData, response: BankingClientResponse) {
|
||||||
val currency = bankAccount.currency
|
val currency = bankAccount.currency
|
||||||
|
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import javafx.scene.text.FontWeight
|
||||||
import net.dankito.banking.ui.javafx.dialogs.tan.controls.ChipTanFlickerCodeView
|
import net.dankito.banking.ui.javafx.dialogs.tan.controls.ChipTanFlickerCodeView
|
||||||
import net.dankito.banking.ui.javafx.dialogs.JavaFxDialogService
|
import net.dankito.banking.ui.javafx.dialogs.JavaFxDialogService
|
||||||
import net.dankito.banking.ui.javafx.dialogs.tan.controls.TanImageView
|
import net.dankito.banking.ui.javafx.dialogs.tan.controls.TanImageView
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||||
import net.dankito.banking.ui.model.tan.*
|
import net.dankito.banking.ui.model.tan.*
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
|
@ -20,7 +20,7 @@ import tornadofx.*
|
||||||
|
|
||||||
|
|
||||||
open class EnterTanDialog(
|
open class EnterTanDialog(
|
||||||
protected val customer: Customer,
|
protected val customer: TypedCustomer,
|
||||||
protected val challenge: TanChallenge,
|
protected val challenge: TanChallenge,
|
||||||
protected val presenter: BankingPresenter,
|
protected val presenter: BankingPresenter,
|
||||||
protected val tanEnteredCallback: (EnterTanResult) -> Unit
|
protected val tanEnteredCallback: (EnterTanResult) -> Unit
|
||||||
|
|
|
@ -2,10 +2,10 @@ package net.dankito.banking.ui.javafx.model
|
||||||
|
|
||||||
import javafx.scene.Node
|
import javafx.scene.Node
|
||||||
import javafx.scene.image.ImageView
|
import javafx.scene.image.ImageView
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
|
|
||||||
|
|
||||||
open class AccountsAccountTreeItem(val customer: Customer) : AccountsTreeItemBase(customer.displayName) {
|
open class AccountsAccountTreeItem(val customer: TypedCustomer) : AccountsTreeItemBase(customer.displayName) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val IconSize = 16.0
|
private const val IconSize = 16.0
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package net.dankito.banking.ui.javafx.model
|
package net.dankito.banking.ui.javafx.model
|
||||||
|
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
import net.dankito.banking.ui.model.TypedBankAccount
|
||||||
|
|
||||||
|
|
||||||
open class AccountsBankAccountTreeItem(val bankAccount: BankAccount) : AccountsTreeItemBase(bankAccount.displayName)
|
open class AccountsBankAccountTreeItem(val bankAccount: TypedBankAccount) : AccountsTreeItemBase(bankAccount.displayName)
|
|
@ -2,13 +2,13 @@ package net.dankito.banking.ui.javafx.model
|
||||||
|
|
||||||
import javafx.collections.ListChangeListener
|
import javafx.collections.ListChangeListener
|
||||||
import javafx.collections.ObservableList
|
import javafx.collections.ObservableList
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
import tornadofx.FX.Companion.messages
|
import tornadofx.FX.Companion.messages
|
||||||
import tornadofx.get
|
import tornadofx.get
|
||||||
import tornadofx.runLater
|
import tornadofx.runLater
|
||||||
|
|
||||||
|
|
||||||
open class AccountsRootTreeItem(customers: ObservableList<Customer>) : AccountsTreeItemBase(messages["accounts.view.all.accounts"]) {
|
open class AccountsRootTreeItem(customers: ObservableList<TypedCustomer>) : AccountsTreeItemBase(messages["accounts.view.all.accounts"]) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setAccounts(customers)
|
setAccounts(customers)
|
||||||
|
@ -18,7 +18,7 @@ open class AccountsRootTreeItem(customers: ObservableList<Customer>) : AccountsT
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun setAccounts(customers: List<Customer>) {
|
protected open fun setAccounts(customers: List<TypedCustomer>) {
|
||||||
isExpanded = customers.isNotEmpty()
|
isExpanded = customers.isNotEmpty()
|
||||||
|
|
||||||
children.setAll(customers.map { AccountsAccountTreeItem(it) })
|
children.setAll(customers.map { AccountsAccountTreeItem(it) })
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
package net.dankito.banking.persistence
|
package net.dankito.banking.persistence
|
||||||
|
|
||||||
|
import net.dankito.banking.ui.model.*
|
||||||
import net.dankito.utils.multiplatform.File
|
import net.dankito.utils.multiplatform.File
|
||||||
import net.dankito.banking.ui.model.Customer
|
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
|
||||||
|
|
||||||
|
|
||||||
interface IBankingPersistence {
|
interface IBankingPersistence {
|
||||||
|
|
||||||
fun saveOrUpdateAccount(customer: Customer, allCustomers: List<Customer>)
|
fun saveOrUpdateAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>)
|
||||||
|
|
||||||
fun deleteAccount(customer: Customer, allCustomers: List<Customer>)
|
fun deleteAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>)
|
||||||
|
|
||||||
fun readPersistedAccounts(): List<Customer>
|
fun readPersistedAccounts(): List<TypedCustomer>
|
||||||
|
|
||||||
|
|
||||||
fun saveOrUpdateAccountTransactions(bankAccount: BankAccount, transactions: List<AccountTransaction>)
|
fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List<IAccountTransaction>)
|
||||||
|
|
||||||
fun saveUrlToFile(url: String, file: File)
|
fun saveUrlToFile(url: String, file: File)
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,25 @@
|
||||||
package net.dankito.banking.persistence
|
package net.dankito.banking.persistence
|
||||||
|
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
import net.dankito.banking.ui.model.*
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
|
||||||
import net.dankito.banking.ui.model.Customer
|
|
||||||
import net.dankito.utils.multiplatform.File
|
import net.dankito.utils.multiplatform.File
|
||||||
|
|
||||||
|
|
||||||
open class NoOpBankingPersistence : IBankingPersistence {
|
open class NoOpBankingPersistence : IBankingPersistence {
|
||||||
|
|
||||||
override fun saveOrUpdateAccount(customer: Customer, allCustomers: List<Customer>) {
|
override fun saveOrUpdateAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deleteAccount(customer: Customer, allCustomers: List<Customer>) {
|
override fun deleteAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun readPersistedAccounts(): List<Customer> {
|
override fun readPersistedAccounts(): List<TypedCustomer> {
|
||||||
return listOf()
|
return listOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun saveOrUpdateAccountTransactions(bankAccount: BankAccount, transactions: List<AccountTransaction>) {
|
override fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List<IAccountTransaction>) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package net.dankito.banking.ui
|
package net.dankito.banking.ui
|
||||||
|
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
||||||
import net.dankito.banking.ui.model.tan.EnterTanResult
|
import net.dankito.banking.ui.model.tan.EnterTanResult
|
||||||
import net.dankito.banking.ui.model.tan.TanChallenge
|
import net.dankito.banking.ui.model.tan.TanChallenge
|
||||||
|
@ -9,7 +9,7 @@ import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium
|
||||||
|
|
||||||
interface BankingClientCallback {
|
interface BankingClientCallback {
|
||||||
|
|
||||||
fun enterTan(customer: Customer, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit)
|
fun enterTan(customer: TypedCustomer, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method gets called for chipTan TAN generators when the bank asks the customer to synchronize her/his TAN generator.
|
* This method gets called for chipTan TAN generators when the bank asks the customer to synchronize her/his TAN generator.
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package net.dankito.banking.ui
|
package net.dankito.banking.ui
|
||||||
|
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
import net.dankito.banking.ui.model.*
|
||||||
import net.dankito.banking.ui.model.Customer
|
|
||||||
import net.dankito.banking.ui.model.MessageLogEntry
|
|
||||||
import net.dankito.banking.ui.model.parameters.GetTransactionsParameter
|
import net.dankito.banking.ui.model.parameters.GetTransactionsParameter
|
||||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||||
import net.dankito.banking.ui.model.responses.AddAccountResponse
|
import net.dankito.banking.ui.model.responses.AddAccountResponse
|
||||||
|
@ -18,7 +16,7 @@ interface IBankingClient {
|
||||||
fun addAccountAsync(callback: (AddAccountResponse) -> Unit)
|
fun addAccountAsync(callback: (AddAccountResponse) -> Unit)
|
||||||
|
|
||||||
fun getTransactionsAsync(
|
fun getTransactionsAsync(
|
||||||
bankAccount: BankAccount,
|
bankAccount: TypedBankAccount,
|
||||||
parameter: GetTransactionsParameter,
|
parameter: GetTransactionsParameter,
|
||||||
callback: (GetTransactionsResponse) -> Unit
|
callback: (GetTransactionsResponse) -> Unit
|
||||||
)
|
)
|
||||||
|
@ -26,6 +24,6 @@ interface IBankingClient {
|
||||||
fun transferMoneyAsync(data: TransferMoneyData, callback: (BankingClientResponse) -> Unit)
|
fun transferMoneyAsync(data: TransferMoneyData, callback: (BankingClientResponse) -> Unit)
|
||||||
|
|
||||||
|
|
||||||
fun dataChanged(customer: Customer)
|
fun dataChanged(customer: TypedCustomer)
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,14 +1,14 @@
|
||||||
package net.dankito.banking.ui
|
package net.dankito.banking.ui
|
||||||
|
|
||||||
import net.dankito.utils.multiplatform.File
|
import net.dankito.utils.multiplatform.File
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
import net.dankito.banking.util.IAsyncRunner
|
import net.dankito.banking.util.IAsyncRunner
|
||||||
|
|
||||||
|
|
||||||
interface IBankingClientCreator {
|
interface IBankingClientCreator {
|
||||||
|
|
||||||
fun createClient(
|
fun createClient(
|
||||||
customer: Customer,
|
customer: TypedCustomer,
|
||||||
dataFolder: File,
|
dataFolder: File,
|
||||||
asyncRunner: IAsyncRunner,
|
asyncRunner: IAsyncRunner,
|
||||||
callback: BankingClientCallback
|
callback: BankingClientCallback
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package net.dankito.banking.ui
|
package net.dankito.banking.ui
|
||||||
|
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
|
||||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||||
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
||||||
import net.dankito.banking.ui.model.tan.EnterTanResult
|
import net.dankito.banking.ui.model.tan.EnterTanResult
|
||||||
|
@ -14,7 +13,7 @@ interface IRouter {
|
||||||
|
|
||||||
fun showAddAccountDialog(presenter: BankingPresenter)
|
fun showAddAccountDialog(presenter: BankingPresenter)
|
||||||
|
|
||||||
fun getTanFromUserFromNonUiThread(customer: Customer, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: (EnterTanResult) -> Unit)
|
fun getTanFromUserFromNonUiThread(customer: TypedCustomer, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: (EnterTanResult) -> Unit)
|
||||||
|
|
||||||
fun getAtcFromUserFromNonUiThread(tanMedium: TanGeneratorTanMedium, callback: (EnterTanGeneratorAtcResult) -> Unit)
|
fun getAtcFromUserFromNonUiThread(tanMedium: TanGeneratorTanMedium, callback: (EnterTanGeneratorAtcResult) -> Unit)
|
||||||
|
|
||||||
|
|
|
@ -7,49 +7,44 @@ import net.dankito.utils.multiplatform.DateFormatter
|
||||||
|
|
||||||
|
|
||||||
open class AccountTransaction(
|
open class AccountTransaction(
|
||||||
open val bankAccount: BankAccount,
|
override val bankAccount: TypedBankAccount,
|
||||||
open val amount: BigDecimal,
|
override val amount: BigDecimal,
|
||||||
open val currency: String,
|
override val currency: String,
|
||||||
open val unparsedUsage: String,
|
override val unparsedUsage: String,
|
||||||
open val bookingDate: Date,
|
override val bookingDate: Date,
|
||||||
open val otherPartyName: String?,
|
override val otherPartyName: String?,
|
||||||
open val otherPartyBankCode: String?,
|
override val otherPartyBankCode: String?,
|
||||||
open val otherPartyAccountId: String?,
|
override val otherPartyAccountId: String?,
|
||||||
open val bookingText: String?,
|
override val bookingText: String?,
|
||||||
open val valueDate: Date,
|
override val valueDate: Date,
|
||||||
open val statementNumber: Int,
|
override val statementNumber: Int,
|
||||||
open val sequenceNumber: Int?,
|
override val sequenceNumber: Int?,
|
||||||
open val openingBalance: BigDecimal?,
|
override val openingBalance: BigDecimal?,
|
||||||
open val closingBalance: BigDecimal?,
|
override val closingBalance: BigDecimal?,
|
||||||
|
|
||||||
open val endToEndReference: String?,
|
override val endToEndReference: String?,
|
||||||
open val customerReference: String?,
|
override val customerReference: String?,
|
||||||
open val mandateReference: String?,
|
override val mandateReference: String?,
|
||||||
open val creditorIdentifier: String?,
|
override val creditorIdentifier: String?,
|
||||||
open val originatorsIdentificationCode: String?,
|
override val originatorsIdentificationCode: String?,
|
||||||
open val compensationAmount: String?,
|
override val compensationAmount: String?,
|
||||||
open val originalAmount: String?,
|
override val originalAmount: String?,
|
||||||
open val sepaUsage: String?,
|
override val sepaUsage: String?,
|
||||||
open val deviantOriginator: String?,
|
override val deviantOriginator: String?,
|
||||||
open val deviantRecipient: String?,
|
override val deviantRecipient: String?,
|
||||||
open val usageWithNoSpecialType: String?,
|
override val usageWithNoSpecialType: String?,
|
||||||
open val primaNotaNumber: String?,
|
override val primaNotaNumber: String?,
|
||||||
open val textKeySupplement: String?,
|
override val textKeySupplement: String?,
|
||||||
|
|
||||||
open val currencyType: String?,
|
override val currencyType: String?,
|
||||||
open val bookingKey: String,
|
override val bookingKey: String,
|
||||||
open val referenceForTheAccountOwner: String,
|
override val referenceForTheAccountOwner: String,
|
||||||
open val referenceOfTheAccountServicingInstitution: String?,
|
override val referenceOfTheAccountServicingInstitution: String?,
|
||||||
open val supplementaryDetails: String?,
|
override val supplementaryDetails: String?,
|
||||||
|
|
||||||
open val transactionReferenceNumber: String,
|
|
||||||
open val relatedReferenceNumber: String?
|
|
||||||
) {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val IdDateFormat = DateFormatter("yyyy.MM.dd")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
override val transactionReferenceNumber: String,
|
||||||
|
override val relatedReferenceNumber: String?
|
||||||
|
) : IAccountTransaction {
|
||||||
|
|
||||||
// for object deserializers
|
// for object deserializers
|
||||||
internal constructor() : this(BankAccount(), null, "", BigDecimal.Zero, Date(), null)
|
internal constructor() : this(BankAccount(), null, "", BigDecimal.Zero, Date(), null)
|
||||||
|
@ -69,29 +64,7 @@ open class AccountTransaction(
|
||||||
0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null, null, "", null)
|
0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null, null, "", null)
|
||||||
|
|
||||||
|
|
||||||
open var technicalId: String = buildTransactionIdentifier()
|
override var technicalId: String = buildTransactionIdentifier()
|
||||||
|
|
||||||
open val transactionIdentifier: String
|
|
||||||
get() = buildTransactionIdentifier()
|
|
||||||
|
|
||||||
protected fun buildTransactionIdentifier() : String {
|
|
||||||
if (bankAccount != null) {
|
|
||||||
return "${bankAccount.technicalId} ${IdDateFormat.format(bookingDate)} ${IdDateFormat.format(valueDate)} $amount $currency $unparsedUsage $otherPartyName $otherPartyBankCode $otherPartyAccountId"
|
|
||||||
}
|
|
||||||
else { // happens for derived classes during initialization. These have to set technicalId after initialization by themselves
|
|
||||||
return "<uninitialized_bank_acccount> ${IdDateFormat.format(bookingDate)} ${IdDateFormat.format(valueDate)} $amount $currency $unparsedUsage $otherPartyName $otherPartyBankCode $otherPartyAccountId"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
open val showOtherPartyName: Boolean
|
|
||||||
get() = otherPartyName.isNullOrBlank() == false /* && type != "ENTGELTABSCHLUSS" && type != "AUSZAHLUNG" */ // TODO
|
|
||||||
|
|
||||||
open val canCreateMoneyTransferFrom: Boolean
|
|
||||||
get() = otherPartyAccountId != null && bankAccount.supportsTransferringMoney
|
|
||||||
|
|
||||||
open val usage: String
|
|
||||||
get() = sepaUsage ?: unparsedUsage
|
|
||||||
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
|
|
|
@ -7,69 +7,47 @@ import kotlin.jvm.JvmOverloads
|
||||||
|
|
||||||
|
|
||||||
open class BankAccount @JvmOverloads constructor(
|
open class BankAccount @JvmOverloads constructor(
|
||||||
open val customer: Customer,
|
override val customer: TypedCustomer,
|
||||||
open var identifier: String,
|
override var identifier: String,
|
||||||
open var accountHolderName: String,
|
override var accountHolderName: String,
|
||||||
open var iban: String?,
|
override var iban: String?,
|
||||||
open var subAccountNumber: String?,
|
override var subAccountNumber: String?,
|
||||||
open var customerId: String,
|
override var customerId: String,
|
||||||
open var balance: BigDecimal = BigDecimal.Zero,
|
override var balance: BigDecimal = BigDecimal.Zero,
|
||||||
open var currency: String = "EUR",
|
override var currency: String = "EUR",
|
||||||
open var type: BankAccountType = BankAccountType.Girokonto,
|
override var type: BankAccountType = BankAccountType.Girokonto,
|
||||||
open var productName: String? = null,
|
override var productName: String? = null,
|
||||||
open var accountLimit: String? = null,
|
override var accountLimit: String? = null,
|
||||||
open var lastRetrievedTransactionsTimestamp: Date? = null,
|
override var lastRetrievedTransactionsTimestamp: Date? = null,
|
||||||
open var supportsRetrievingAccountTransactions: Boolean = false,
|
override var supportsRetrievingAccountTransactions: Boolean = false,
|
||||||
open var supportsRetrievingBalance: Boolean = false,
|
override var supportsRetrievingBalance: Boolean = false,
|
||||||
open var supportsTransferringMoney: Boolean = false,
|
override var supportsTransferringMoney: Boolean = false,
|
||||||
open var supportsInstantPaymentMoneyTransfer: Boolean = false,
|
override var supportsInstantPaymentMoneyTransfer: Boolean = false,
|
||||||
open var bookedTransactions: List<AccountTransaction> = listOf(),
|
override var bookedTransactions: List<IAccountTransaction> = listOf(),
|
||||||
open var unbookedTransactions: List<Any> = listOf()
|
override var unbookedTransactions: List<Any> = listOf()
|
||||||
) : OrderedDisplayable {
|
) : TypedBankAccount {
|
||||||
|
|
||||||
internal constructor() : this(Customer(), null, "") // for object deserializers
|
internal constructor() : this(Customer(), null, "") // for object deserializers
|
||||||
|
|
||||||
/* convenience constructors for languages not supporting default values */
|
/* convenience constructors for languages not supporting default values */
|
||||||
|
|
||||||
constructor(customer: Customer, productName: String?, identifier: String) : this(customer, productName, identifier, BankAccountType.Girokonto)
|
constructor(customer: TypedCustomer, productName: String?, identifier: String) : this(customer, productName, identifier, BankAccountType.Girokonto)
|
||||||
|
|
||||||
constructor(customer: Customer, productName: String?, identifier: String, type: BankAccountType = BankAccountType.Girokonto, balance: BigDecimal = BigDecimal.Zero)
|
constructor(customer: TypedCustomer, productName: String?, identifier: String, type: BankAccountType = BankAccountType.Girokonto, balance: BigDecimal = BigDecimal.Zero)
|
||||||
: this(customer, identifier, "", null, null, "", balance, "EUR", type, productName)
|
: this(customer, identifier, "", null, null, "", balance, "EUR", type, productName)
|
||||||
|
|
||||||
|
|
||||||
open var technicalId: String = UUID.random()
|
override var technicalId: String = UUID.random()
|
||||||
|
|
||||||
|
|
||||||
open var haveAllTransactionsBeenFetched: Boolean = false
|
override var haveAllTransactionsBeenFetched: Boolean = false
|
||||||
|
|
||||||
|
|
||||||
open var userSetDisplayName: String? = null
|
override var userSetDisplayName: String? = null
|
||||||
|
|
||||||
override val displayName: String
|
|
||||||
get() {
|
|
||||||
return userSetDisplayName ?: productName ?: subAccountNumber ?: identifier
|
|
||||||
}
|
|
||||||
|
|
||||||
override var displayIndex: Int = 0
|
override var displayIndex: Int = 0
|
||||||
|
|
||||||
|
|
||||||
open fun addBookedTransactions(retrievedBookedTransactions: List<AccountTransaction>) {
|
|
||||||
val uniqueTransactions = this.bookedTransactions.toMutableSet()
|
|
||||||
|
|
||||||
uniqueTransactions.addAll(retrievedBookedTransactions)
|
|
||||||
|
|
||||||
this.bookedTransactions = uniqueTransactions.toList()
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun addUnbookedTransactions(retrievedUnbookedTransactions: List<Any>) {
|
|
||||||
val uniqueUnbookedTransactions = this.unbookedTransactions.toMutableSet()
|
|
||||||
|
|
||||||
uniqueUnbookedTransactions.addAll(retrievedUnbookedTransactions)
|
|
||||||
|
|
||||||
this.unbookedTransactions = uniqueUnbookedTransactions.toList()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "$accountHolderName ($identifier)"
|
return "$accountHolderName ($identifier)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,22 @@
|
||||||
package net.dankito.banking.ui.model
|
package net.dankito.banking.ui.model
|
||||||
|
|
||||||
import net.dankito.utils.multiplatform.BigDecimal
|
|
||||||
import net.dankito.utils.multiplatform.sum
|
|
||||||
import net.dankito.banking.ui.model.tan.TanMedium
|
import net.dankito.banking.ui.model.tan.TanMedium
|
||||||
import net.dankito.banking.ui.model.tan.TanMediumStatus
|
|
||||||
import net.dankito.banking.ui.model.tan.TanProcedure
|
import net.dankito.banking.ui.model.tan.TanProcedure
|
||||||
import net.dankito.banking.util.sortedByDisplayIndex
|
|
||||||
import net.dankito.utils.multiplatform.UUID
|
import net.dankito.utils.multiplatform.UUID
|
||||||
|
|
||||||
|
|
||||||
open class Customer(
|
open class Customer(
|
||||||
open var bankCode: String,
|
override var bankCode: String,
|
||||||
open var customerId: String,
|
override var customerId: String,
|
||||||
open var password: String,
|
override var password: String,
|
||||||
open var finTsServerAddress: String,
|
override var finTsServerAddress: String,
|
||||||
open var bankName: String,
|
override var bankName: String,
|
||||||
open var bic: String,
|
override var bic: String,
|
||||||
open var customerName: String,
|
override var customerName: String,
|
||||||
open var userId: String = customerId,
|
override var userId: String = customerId,
|
||||||
open var iconUrl: String? = null,
|
override var iconUrl: String? = null,
|
||||||
open var accounts: List<BankAccount> = listOf()
|
override var accounts: List<TypedBankAccount> = listOf()
|
||||||
) : OrderedDisplayable {
|
) : TypedCustomer {
|
||||||
|
|
||||||
|
|
||||||
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
||||||
|
@ -31,40 +27,23 @@ open class Customer(
|
||||||
: this(bankCode, customerId, password, finTsServerAddress, "", "", "")
|
: this(bankCode, customerId, password, finTsServerAddress, "", "", "")
|
||||||
|
|
||||||
|
|
||||||
open var technicalId: String = UUID.random()
|
override var technicalId: String = UUID.random()
|
||||||
|
|
||||||
|
|
||||||
open var supportedTanProcedures: List<TanProcedure> = listOf()
|
override var supportedTanProcedures: List<TanProcedure> = listOf()
|
||||||
|
|
||||||
open var selectedTanProcedure: TanProcedure? = null
|
override var selectedTanProcedure: TanProcedure? = null
|
||||||
|
|
||||||
open var tanMedia: List<TanMedium> = listOf()
|
override var tanMedia: List<TanMedium> = listOf()
|
||||||
|
|
||||||
open val tanMediaSorted: List<TanMedium>
|
|
||||||
get() = tanMedia.sortedByDescending { it.status == TanMediumStatus.Used }
|
|
||||||
|
|
||||||
|
|
||||||
open var userSetDisplayName: String? = null
|
override var userSetDisplayName: String? = null
|
||||||
|
|
||||||
override val displayName: String
|
|
||||||
get() = userSetDisplayName ?: bankName
|
|
||||||
|
|
||||||
override var displayIndex: Int = 0
|
override var displayIndex: Int = 0
|
||||||
|
|
||||||
|
|
||||||
open val accountsSorted: List<BankAccount>
|
|
||||||
get() = accounts.sortedByDisplayIndex()
|
|
||||||
|
|
||||||
|
|
||||||
open val balance: BigDecimal
|
|
||||||
get() = accounts.map { it.balance }.sum()
|
|
||||||
|
|
||||||
open val transactions: List<AccountTransaction>
|
|
||||||
get() = accounts.flatMap { it.bookedTransactions }
|
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "$customerName ($customerId)"
|
return "$bankName $customerId"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
package net.dankito.banking.ui.model
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
|
import net.dankito.utils.multiplatform.Date
|
||||||
|
import net.dankito.utils.multiplatform.DateFormatter
|
||||||
|
|
||||||
|
|
||||||
|
interface IAccountTransaction {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val IdDateFormat = DateFormatter("yyyy.MM.dd")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val bankAccount: IBankAccount<*>
|
||||||
|
val amount: BigDecimal
|
||||||
|
val currency: String
|
||||||
|
val unparsedUsage: String
|
||||||
|
val bookingDate: Date
|
||||||
|
val otherPartyName: String?
|
||||||
|
val otherPartyBankCode: String?
|
||||||
|
val otherPartyAccountId: String?
|
||||||
|
val bookingText: String?
|
||||||
|
val valueDate: Date
|
||||||
|
val statementNumber: Int
|
||||||
|
val sequenceNumber: Int?
|
||||||
|
val openingBalance: BigDecimal?
|
||||||
|
val closingBalance: BigDecimal?
|
||||||
|
|
||||||
|
val endToEndReference: String?
|
||||||
|
val customerReference: String?
|
||||||
|
val mandateReference: String?
|
||||||
|
val creditorIdentifier: String?
|
||||||
|
val originatorsIdentificationCode: String?
|
||||||
|
val compensationAmount: String?
|
||||||
|
val originalAmount: String?
|
||||||
|
val sepaUsage: String?
|
||||||
|
val deviantOriginator: String?
|
||||||
|
val deviantRecipient: String?
|
||||||
|
val usageWithNoSpecialType: String?
|
||||||
|
val primaNotaNumber: String?
|
||||||
|
val textKeySupplement: String?
|
||||||
|
|
||||||
|
val currencyType: String?
|
||||||
|
val bookingKey: String
|
||||||
|
val referenceForTheAccountOwner: String
|
||||||
|
val referenceOfTheAccountServicingInstitution: String?
|
||||||
|
val supplementaryDetails: String?
|
||||||
|
|
||||||
|
val transactionReferenceNumber: String
|
||||||
|
val relatedReferenceNumber: String?
|
||||||
|
|
||||||
|
|
||||||
|
var technicalId: String
|
||||||
|
|
||||||
|
|
||||||
|
val showOtherPartyName: Boolean
|
||||||
|
get() = otherPartyName.isNullOrBlank() == false /* && type != "ENTGELTABSCHLUSS" && type != "AUSZAHLUNG" */ // TODO
|
||||||
|
|
||||||
|
val canCreateMoneyTransferFrom: Boolean
|
||||||
|
get() = otherPartyAccountId != null && bankAccount.supportsTransferringMoney
|
||||||
|
|
||||||
|
val usage: String
|
||||||
|
get() = sepaUsage ?: unparsedUsage
|
||||||
|
|
||||||
|
|
||||||
|
fun buildTransactionIdentifier() : String {
|
||||||
|
if (bankAccount != null) {
|
||||||
|
return "${bankAccount.technicalId} ${IdDateFormat.format(bookingDate)} ${IdDateFormat.format(valueDate)} $amount $currency $unparsedUsage $otherPartyName $otherPartyBankCode $otherPartyAccountId"
|
||||||
|
}
|
||||||
|
else { // happens for derived classes during initialization. These have to set technicalId after initialization by themselves
|
||||||
|
return "<uninitialized_bank_acccount> ${IdDateFormat.format(bookingDate)} ${IdDateFormat.format(valueDate)} $amount $currency $unparsedUsage $otherPartyName $otherPartyBankCode $otherPartyAccountId"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package net.dankito.banking.ui.model
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
|
import net.dankito.utils.multiplatform.Date
|
||||||
|
|
||||||
|
|
||||||
|
typealias TypedBankAccount = IBankAccount<IAccountTransaction>
|
||||||
|
|
||||||
|
|
||||||
|
interface IBankAccount<TTransaction: IAccountTransaction> : OrderedDisplayable {
|
||||||
|
val customer: ICustomer<*, *>
|
||||||
|
var identifier: String
|
||||||
|
var accountHolderName: String
|
||||||
|
var iban: String?
|
||||||
|
var subAccountNumber: String?
|
||||||
|
var customerId: String
|
||||||
|
var balance: BigDecimal
|
||||||
|
var currency: String
|
||||||
|
var type: BankAccountType
|
||||||
|
var productName: String?
|
||||||
|
var accountLimit: String?
|
||||||
|
var lastRetrievedTransactionsTimestamp: Date?
|
||||||
|
var supportsRetrievingAccountTransactions: Boolean
|
||||||
|
var supportsRetrievingBalance: Boolean
|
||||||
|
var supportsTransferringMoney: Boolean
|
||||||
|
var supportsInstantPaymentMoneyTransfer: Boolean
|
||||||
|
var bookedTransactions: List<TTransaction>
|
||||||
|
var unbookedTransactions: List<Any>
|
||||||
|
var technicalId: String
|
||||||
|
var haveAllTransactionsBeenFetched: Boolean
|
||||||
|
var userSetDisplayName: String?
|
||||||
|
|
||||||
|
|
||||||
|
override val displayName: String
|
||||||
|
get() {
|
||||||
|
return userSetDisplayName ?: productName ?: subAccountNumber ?: identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun addBookedTransactions(retrievedBookedTransactions: List<TTransaction>) {
|
||||||
|
val uniqueTransactions = this.bookedTransactions.toMutableSet()
|
||||||
|
|
||||||
|
uniqueTransactions.addAll(retrievedBookedTransactions)
|
||||||
|
|
||||||
|
this.bookedTransactions = uniqueTransactions.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addUnbookedTransactions(retrievedUnbookedTransactions: List<Any>) {
|
||||||
|
val uniqueUnbookedTransactions = this.unbookedTransactions.toMutableSet()
|
||||||
|
|
||||||
|
uniqueUnbookedTransactions.addAll(retrievedUnbookedTransactions)
|
||||||
|
|
||||||
|
this.unbookedTransactions = uniqueUnbookedTransactions.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package net.dankito.banking.ui.model
|
||||||
|
|
||||||
|
import net.dankito.banking.ui.model.tan.TanMedium
|
||||||
|
import net.dankito.banking.ui.model.tan.TanMediumStatus
|
||||||
|
import net.dankito.banking.ui.model.tan.TanProcedure
|
||||||
|
import net.dankito.banking.util.sortedByDisplayIndex
|
||||||
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
|
import net.dankito.utils.multiplatform.sum
|
||||||
|
|
||||||
|
|
||||||
|
typealias TypedCustomer = ICustomer<IBankAccount<IAccountTransaction>, IAccountTransaction>
|
||||||
|
|
||||||
|
|
||||||
|
interface ICustomer<TAccount: IBankAccount<TAccountTransaction>, TAccountTransaction: IAccountTransaction> : OrderedDisplayable {
|
||||||
|
|
||||||
|
var bankCode: String
|
||||||
|
var customerId: String
|
||||||
|
var password: String
|
||||||
|
var finTsServerAddress: String
|
||||||
|
|
||||||
|
var bankName: String
|
||||||
|
var bic: String
|
||||||
|
var customerName: String
|
||||||
|
var userId: String
|
||||||
|
|
||||||
|
var iconUrl: String?
|
||||||
|
|
||||||
|
var accounts: List<TAccount>
|
||||||
|
|
||||||
|
var supportedTanProcedures: List<TanProcedure>
|
||||||
|
var selectedTanProcedure: TanProcedure?
|
||||||
|
var tanMedia: List<TanMedium>
|
||||||
|
|
||||||
|
var userSetDisplayName: String?
|
||||||
|
|
||||||
|
var technicalId: String
|
||||||
|
|
||||||
|
|
||||||
|
override val displayName: String
|
||||||
|
get() = userSetDisplayName ?: bankName
|
||||||
|
|
||||||
|
|
||||||
|
val accountsSorted: List<TAccount>
|
||||||
|
get() = accounts.sortedByDisplayIndex()
|
||||||
|
|
||||||
|
|
||||||
|
val balance: BigDecimal
|
||||||
|
get() = accounts.map { it.balance }.sum()
|
||||||
|
|
||||||
|
val transactions: List<IAccountTransaction>
|
||||||
|
get() = accounts.flatMap { it.bookedTransactions }
|
||||||
|
|
||||||
|
val tanMediaSorted: List<TanMedium>
|
||||||
|
get() = tanMedia.sortedByDescending { it.status == TanMediumStatus.Used }
|
||||||
|
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ import net.dankito.utils.multiplatform.Date
|
||||||
open class MessageLogEntry(
|
open class MessageLogEntry(
|
||||||
val message: String,
|
val message: String,
|
||||||
val time: Date,
|
val time: Date,
|
||||||
val customer: Customer
|
val customer: TypedCustomer
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
package net.dankito.banking.ui.model.mapper
|
||||||
|
|
||||||
|
import net.dankito.banking.ui.model.*
|
||||||
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
|
import net.dankito.utils.multiplatform.Date
|
||||||
|
|
||||||
|
|
||||||
|
open class DefaultModelCreator : IModelCreator {
|
||||||
|
|
||||||
|
override fun createCustomer(bankCode: String, customerId: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||||
|
customerName: String, userId: String, iconUrl: String?): TypedCustomer {
|
||||||
|
|
||||||
|
return Customer(bankCode, customerId, password, finTsServerAddress, bankName, bic, customerName, userId, iconUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun createBankAccount(customer: TypedCustomer, productName: String?, identifier: String): TypedBankAccount {
|
||||||
|
return BankAccount(customer, productName, identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createTransaction(
|
||||||
|
bankAccount: TypedBankAccount,
|
||||||
|
amount: BigDecimal,
|
||||||
|
currency: String,
|
||||||
|
unparsedUsage: String,
|
||||||
|
bookingDate: Date,
|
||||||
|
otherPartyName: String?,
|
||||||
|
otherPartyBankCode: String?,
|
||||||
|
otherPartyAccountId: String?,
|
||||||
|
bookingText: String?,
|
||||||
|
valueDate: Date,
|
||||||
|
statementNumber: Int,
|
||||||
|
sequenceNumber: Int?,
|
||||||
|
openingBalance: BigDecimal?,
|
||||||
|
closingBalance: BigDecimal?,
|
||||||
|
endToEndReference: String?,
|
||||||
|
customerReference: String?,
|
||||||
|
mandateReference: String?,
|
||||||
|
creditorIdentifier: String?,
|
||||||
|
originatorsIdentificationCode: String?,
|
||||||
|
compensationAmount: String?,
|
||||||
|
originalAmount: String?,
|
||||||
|
sepaUsage: String?,
|
||||||
|
deviantOriginator: String?,
|
||||||
|
deviantRecipient: String?,
|
||||||
|
usageWithNoSpecialType: String?,
|
||||||
|
primaNotaNumber: String?,
|
||||||
|
textKeySupplement: String?,
|
||||||
|
currencyType: String?,
|
||||||
|
bookingKey: String,
|
||||||
|
referenceForTheAccountOwner: String,
|
||||||
|
referenceOfTheAccountServicingInstitution: String?,
|
||||||
|
supplementaryDetails: String?,
|
||||||
|
transactionReferenceNumber: String,
|
||||||
|
relatedReferenceNumber: String?
|
||||||
|
) : IAccountTransaction {
|
||||||
|
|
||||||
|
return AccountTransaction(bankAccount, amount, currency, unparsedUsage, bookingDate,
|
||||||
|
otherPartyName, otherPartyBankCode, otherPartyAccountId, bookingText, valueDate, statementNumber, sequenceNumber,
|
||||||
|
openingBalance, closingBalance, endToEndReference, customerReference, mandateReference, creditorIdentifier,
|
||||||
|
originatorsIdentificationCode, compensationAmount, originalAmount, sepaUsage, deviantOriginator, deviantRecipient,
|
||||||
|
usageWithNoSpecialType, primaNotaNumber, textKeySupplement, currencyType, bookingKey, referenceForTheAccountOwner,
|
||||||
|
referenceOfTheAccountServicingInstitution, supplementaryDetails, transactionReferenceNumber, relatedReferenceNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package net.dankito.banking.ui.model.mapper
|
||||||
|
|
||||||
|
import net.dankito.banking.ui.model.*
|
||||||
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
|
import net.dankito.utils.multiplatform.Date
|
||||||
|
|
||||||
|
|
||||||
|
interface IModelCreator {
|
||||||
|
|
||||||
|
fun createCustomer(bankCode: String, customerId: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||||
|
customerName: String = "", userId: String = customerId, iconUrl: String? = null): TypedCustomer
|
||||||
|
|
||||||
|
|
||||||
|
fun createBankAccount(customer: TypedCustomer, productName: String?, identifier: String) : TypedBankAccount
|
||||||
|
|
||||||
|
|
||||||
|
fun createTransaction(
|
||||||
|
bankAccount: TypedBankAccount,
|
||||||
|
amount: BigDecimal,
|
||||||
|
currency: String,
|
||||||
|
unparsedUsage: String,
|
||||||
|
bookingDate: Date,
|
||||||
|
otherPartyName: String?,
|
||||||
|
otherPartyBankCode: String?,
|
||||||
|
otherPartyAccountId: String?,
|
||||||
|
bookingText: String?,
|
||||||
|
valueDate: Date,
|
||||||
|
statementNumber: Int,
|
||||||
|
sequenceNumber: Int?,
|
||||||
|
openingBalance: BigDecimal?,
|
||||||
|
closingBalance: BigDecimal?,
|
||||||
|
|
||||||
|
endToEndReference: String?,
|
||||||
|
customerReference: String?,
|
||||||
|
mandateReference: String?,
|
||||||
|
creditorIdentifier: String?,
|
||||||
|
originatorsIdentificationCode: String?,
|
||||||
|
compensationAmount: String?,
|
||||||
|
originalAmount: String?,
|
||||||
|
sepaUsage: String?,
|
||||||
|
deviantOriginator: String?,
|
||||||
|
deviantRecipient: String?,
|
||||||
|
usageWithNoSpecialType: String?,
|
||||||
|
primaNotaNumber: String?,
|
||||||
|
textKeySupplement: String?,
|
||||||
|
|
||||||
|
currencyType: String?,
|
||||||
|
bookingKey: String,
|
||||||
|
referenceForTheAccountOwner: String,
|
||||||
|
referenceOfTheAccountServicingInstitution: String?,
|
||||||
|
supplementaryDetails: String?,
|
||||||
|
|
||||||
|
transactionReferenceNumber: String,
|
||||||
|
relatedReferenceNumber: String?
|
||||||
|
) : IAccountTransaction
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package net.dankito.banking.ui.model.parameters
|
package net.dankito.banking.ui.model.parameters
|
||||||
|
|
||||||
import net.dankito.utils.multiplatform.Date
|
import net.dankito.utils.multiplatform.Date
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
import net.dankito.banking.ui.model.IAccountTransaction
|
||||||
|
|
||||||
|
|
||||||
open class GetTransactionsParameter(
|
open class GetTransactionsParameter(
|
||||||
|
@ -9,7 +9,7 @@ open class GetTransactionsParameter(
|
||||||
val fromDate: Date? = null,
|
val fromDate: Date? = null,
|
||||||
val toDate: Date? = null,
|
val toDate: Date? = null,
|
||||||
val abortIfTanIsRequired: Boolean = false,
|
val abortIfTanIsRequired: Boolean = false,
|
||||||
val retrievedChunkListener: ((List<AccountTransaction>) -> Unit)? = null
|
val retrievedChunkListener: ((List<IAccountTransaction>) -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
|
|
||||||
constructor() : this(true, null, null) // for Java
|
constructor() : this(true, null, null) // for Java
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
package net.dankito.banking.ui.model.parameters
|
package net.dankito.banking.ui.model.parameters
|
||||||
|
|
||||||
|
import net.dankito.banking.ui.model.*
|
||||||
import net.dankito.utils.multiplatform.BigDecimal
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
|
||||||
|
|
||||||
|
|
||||||
open class TransferMoneyData(
|
open class TransferMoneyData(
|
||||||
val account: BankAccount,
|
val account: TypedBankAccount,
|
||||||
val creditorName: String,
|
val creditorName: String,
|
||||||
val creditorIban: String,
|
val creditorIban: String,
|
||||||
val creditorBic: String,
|
val creditorBic: String,
|
||||||
|
@ -17,9 +16,9 @@ open class TransferMoneyData(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun fromAccountTransactionWithoutAmountAndUsage(transaction: AccountTransaction): TransferMoneyData {
|
fun fromAccountTransactionWithoutAmountAndUsage(transaction: IAccountTransaction): TransferMoneyData {
|
||||||
return TransferMoneyData(
|
return TransferMoneyData(
|
||||||
transaction.bankAccount,
|
transaction.bankAccount as TypedBankAccount,
|
||||||
transaction.otherPartyName ?: "",
|
transaction.otherPartyName ?: "",
|
||||||
transaction.otherPartyAccountId ?: "",
|
transaction.otherPartyAccountId ?: "",
|
||||||
transaction.otherPartyBankCode ?: "",
|
transaction.otherPartyBankCode ?: "",
|
||||||
|
@ -28,9 +27,9 @@ open class TransferMoneyData(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fromAccountTransaction(transaction: AccountTransaction): TransferMoneyData {
|
fun fromAccountTransaction(transaction: IAccountTransaction): TransferMoneyData {
|
||||||
return TransferMoneyData(
|
return TransferMoneyData(
|
||||||
transaction.bankAccount,
|
transaction.bankAccount as TypedBankAccount,
|
||||||
transaction.otherPartyName ?: "",
|
transaction.otherPartyName ?: "",
|
||||||
transaction.otherPartyAccountId ?: "",
|
transaction.otherPartyAccountId ?: "",
|
||||||
transaction.otherPartyBankCode ?: "",
|
transaction.otherPartyBankCode ?: "",
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
package net.dankito.banking.ui.model.responses
|
package net.dankito.banking.ui.model.responses
|
||||||
|
|
||||||
|
import net.dankito.banking.ui.model.*
|
||||||
import net.dankito.utils.multiplatform.BigDecimal
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
import net.dankito.banking.ui.model.Customer
|
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
|
||||||
|
|
||||||
|
|
||||||
open class AddAccountResponse(
|
open class AddAccountResponse(
|
||||||
isSuccessful: Boolean,
|
isSuccessful: Boolean,
|
||||||
errorToShowToUser: String?,
|
errorToShowToUser: String?,
|
||||||
val customer: Customer,
|
val customer: TypedCustomer,
|
||||||
val supportsRetrievingTransactionsOfLast90DaysWithoutTan: Boolean = false,
|
val supportsRetrievingTransactionsOfLast90DaysWithoutTan: Boolean = false,
|
||||||
val bookedTransactionsOfLast90Days: Map<BankAccount, List<AccountTransaction>> = mapOf(),
|
val bookedTransactionsOfLast90Days: Map<TypedBankAccount, List<IAccountTransaction>> = mapOf(),
|
||||||
val unbookedTransactionsOfLast90Days: Map<BankAccount, List<Any>> = mapOf(),
|
val unbookedTransactionsOfLast90Days: Map<TypedBankAccount, List<Any>> = mapOf(),
|
||||||
val balances: Map<BankAccount, BigDecimal> = mapOf(),
|
val balances: Map<TypedBankAccount, BigDecimal> = mapOf(),
|
||||||
userCancelledAction: Boolean = false
|
userCancelledAction: Boolean = false
|
||||||
)
|
)
|
||||||
: BankingClientResponse(isSuccessful, errorToShowToUser, userCancelledAction) {
|
: BankingClientResponse(isSuccessful, errorToShowToUser, userCancelledAction) {
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
package net.dankito.banking.ui.model.responses
|
package net.dankito.banking.ui.model.responses
|
||||||
|
|
||||||
import net.dankito.utils.multiplatform.BigDecimal
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
import net.dankito.banking.ui.model.IAccountTransaction
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
import net.dankito.banking.ui.model.TypedBankAccount
|
||||||
|
|
||||||
|
|
||||||
open class GetTransactionsResponse(
|
open class GetTransactionsResponse(
|
||||||
val bankAccount: BankAccount,
|
val bankAccount: TypedBankAccount,
|
||||||
isSuccessful: Boolean,
|
isSuccessful: Boolean,
|
||||||
errorToShowToUser: String?,
|
errorToShowToUser: String?,
|
||||||
val bookedTransactions: List<AccountTransaction> = listOf(),
|
val bookedTransactions: List<IAccountTransaction> = listOf(),
|
||||||
val unbookedTransactions: List<Any> = listOf(),
|
val unbookedTransactions: List<Any> = listOf(),
|
||||||
val balance: BigDecimal? = null,
|
val balance: BigDecimal? = null,
|
||||||
userCancelledAction: Boolean = false,
|
userCancelledAction: Boolean = false,
|
||||||
|
|
|
@ -15,6 +15,8 @@ import net.dankito.banking.bankfinder.BankInfo
|
||||||
import net.dankito.banking.search.IRemitteeSearcher
|
import net.dankito.banking.search.IRemitteeSearcher
|
||||||
import net.dankito.banking.search.NoOpRemitteeSearcher
|
import net.dankito.banking.search.NoOpRemitteeSearcher
|
||||||
import net.dankito.banking.search.Remittee
|
import net.dankito.banking.search.Remittee
|
||||||
|
import net.dankito.banking.ui.model.mapper.DefaultModelCreator
|
||||||
|
import net.dankito.banking.ui.model.mapper.IModelCreator
|
||||||
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResult
|
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResult
|
||||||
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResultType
|
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResultType
|
||||||
import net.dankito.banking.ui.model.parameters.GetTransactionsParameter
|
import net.dankito.banking.ui.model.parameters.GetTransactionsParameter
|
||||||
|
@ -30,12 +32,13 @@ import net.dankito.utils.multiplatform.log.LoggerFactory
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
|
||||||
open class BankingPresenter(
|
open class BankingPresenter constructor(
|
||||||
protected val bankingClientCreator: IBankingClientCreator,
|
protected val bankingClientCreator: IBankingClientCreator,
|
||||||
protected val bankFinder: IBankFinder,
|
protected val bankFinder: IBankFinder,
|
||||||
protected val dataFolder: File,
|
protected val dataFolder: File,
|
||||||
protected val persister: IBankingPersistence,
|
protected val persister: IBankingPersistence,
|
||||||
protected val router: IRouter,
|
protected val router: IRouter,
|
||||||
|
protected val modelCreator: IModelCreator = DefaultModelCreator(),
|
||||||
protected val remitteeSearcher: IRemitteeSearcher = NoOpRemitteeSearcher(),
|
protected val remitteeSearcher: IRemitteeSearcher = NoOpRemitteeSearcher(),
|
||||||
protected val bankIconFinder: IBankIconFinder = NoOpBankIconFinder(),
|
protected val bankIconFinder: IBankIconFinder = NoOpBankIconFinder(),
|
||||||
protected val textExtractorRegistry: ITextExtractorRegistry = NoOpTextExtractorRegistry(),
|
protected val textExtractorRegistry: ITextExtractorRegistry = NoOpTextExtractorRegistry(),
|
||||||
|
@ -56,25 +59,25 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected val bankingClientsForAccounts = mutableMapOf<Customer, IBankingClient>()
|
protected val bankingClientsForAccounts = mutableMapOf<TypedCustomer, IBankingClient>()
|
||||||
|
|
||||||
protected var selectedBankAccountsField = mutableListOf<BankAccount>()
|
protected var selectedBankAccountsField = mutableListOf<TypedBankAccount>()
|
||||||
|
|
||||||
protected var selectedAccountType = SelectedAccountType.AllAccounts
|
protected var selectedAccountType = SelectedAccountType.AllAccounts
|
||||||
|
|
||||||
protected var saveAccountOnNextEnterTanInvocation = false
|
protected var saveAccountOnNextEnterTanInvocation = false
|
||||||
|
|
||||||
|
|
||||||
protected val accountsChangedListeners = mutableListOf<(List<Customer>) -> Unit>()
|
protected val accountsChangedListeners = mutableListOf<(List<TypedCustomer>) -> Unit>()
|
||||||
|
|
||||||
protected val retrievedAccountTransactionsResponseListeners = mutableListOf<(GetTransactionsResponse) -> Unit>()
|
protected val retrievedAccountTransactionsResponseListeners = mutableListOf<(GetTransactionsResponse) -> Unit>()
|
||||||
|
|
||||||
protected val selectedBankAccountsChangedListeners = mutableListOf<(List<BankAccount>) -> Unit>()
|
protected val selectedBankAccountsChangedListeners = mutableListOf<(List<TypedBankAccount>) -> Unit>()
|
||||||
|
|
||||||
|
|
||||||
protected val callback: BankingClientCallback = object : BankingClientCallback {
|
protected val callback: BankingClientCallback = object : BankingClientCallback {
|
||||||
|
|
||||||
override fun enterTan(customer: Customer, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
|
override fun enterTan(customer: TypedCustomer, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
|
||||||
if (saveAccountOnNextEnterTanInvocation) {
|
if (saveAccountOnNextEnterTanInvocation) {
|
||||||
persistAccount(customer)
|
persistAccount(customer)
|
||||||
saveAccountOnNextEnterTanInvocation = false
|
saveAccountOnNextEnterTanInvocation = false
|
||||||
|
@ -131,14 +134,14 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun addClientForAccount(customer: Customer, client: IBankingClient) {
|
protected open fun addClientForAccount(customer: TypedCustomer, client: IBankingClient) {
|
||||||
bankingClientsForAccounts.put(customer, client)
|
bankingClientsForAccounts.put(customer, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: move BankInfo out of fints4k
|
// TODO: move BankInfo out of fints4k
|
||||||
open fun addAccountAsync(bankInfo: BankInfo, customerId: String, pin: String, callback: (AddAccountResponse) -> Unit) {
|
open fun addAccountAsync(bankInfo: BankInfo, customerId: String, password: String, callback: (AddAccountResponse) -> Unit) {
|
||||||
val customer = Customer(bankInfo.bankCode, customerId, pin, bankInfo.pinTanAddress ?: "", bankInfo.name, bankInfo.bic, "")
|
val customer = modelCreator.createCustomer(bankInfo.bankCode, customerId, password, bankInfo.pinTanAddress ?: "", bankInfo.name, bankInfo.bic, "")
|
||||||
|
|
||||||
val newClient = bankingClientCreator.createClient(customer, dataFolder, asyncRunner, this.callback)
|
val newClient = bankingClientCreator.createClient(customer, dataFolder, asyncRunner, this.callback)
|
||||||
|
|
||||||
|
@ -180,7 +183,7 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun findIconForBankAsync(customer: Customer) {
|
protected open fun findIconForBankAsync(customer: TypedCustomer) {
|
||||||
bankIconFinder.findIconForBankAsync(customer.bankName) { bankIconUrl ->
|
bankIconFinder.findIconForBankAsync(customer.bankName) { bankIconUrl ->
|
||||||
bankIconUrl?.let {
|
bankIconUrl?.let {
|
||||||
try {
|
try {
|
||||||
|
@ -192,7 +195,7 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun handleFindIconForBankResult(customer: Customer, bankIconUrl: String) {
|
protected open fun handleFindIconForBankResult(customer: TypedCustomer, bankIconUrl: String) {
|
||||||
val bankIconFile = saveBankIconToDisk(customer, bankIconUrl)
|
val bankIconFile = saveBankIconToDisk(customer, bankIconUrl)
|
||||||
|
|
||||||
var iconFilePath = bankIconFile.getAbsolutePath()
|
var iconFilePath = bankIconFile.getAbsolutePath()
|
||||||
|
@ -208,7 +211,7 @@ open class BankingPresenter(
|
||||||
callAccountsChangedListeners()
|
callAccountsChangedListeners()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun saveBankIconToDisk(customer: Customer, bankIconUrl: String): File {
|
protected open fun saveBankIconToDisk(customer: TypedCustomer, bankIconUrl: String): File {
|
||||||
val bankIconsDir = File(dataFolder, "bank_icons")
|
val bankIconsDir = File(dataFolder, "bank_icons")
|
||||||
bankIconsDir.mkdirs()
|
bankIconsDir.mkdirs()
|
||||||
|
|
||||||
|
@ -239,7 +242,7 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun deleteAccount(customer: Customer) {
|
open fun deleteAccount(customer: TypedCustomer) {
|
||||||
val wasSelected = isSingleSelectedAccount(customer) or // either account or one of its bank accounts is currently selected
|
val wasSelected = isSingleSelectedAccount(customer) or // either account or one of its bank accounts is currently selected
|
||||||
(customer.accounts.firstOrNull { isSingleSelectedBankAccount(it) } != null)
|
(customer.accounts.firstOrNull { isSingleSelectedBankAccount(it) } != null)
|
||||||
|
|
||||||
|
@ -264,7 +267,7 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun fetchAllAccountTransactionsAsync(customer: Customer,
|
open fun fetchAllAccountTransactionsAsync(customer: TypedCustomer,
|
||||||
callback: (GetTransactionsResponse) -> Unit) {
|
callback: (GetTransactionsResponse) -> Unit) {
|
||||||
|
|
||||||
customer.accounts.forEach { bankAccount ->
|
customer.accounts.forEach { bankAccount ->
|
||||||
|
@ -274,13 +277,13 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun fetchAllAccountTransactionsAsync(bankAccount: BankAccount,
|
open fun fetchAllAccountTransactionsAsync(bankAccount: TypedBankAccount,
|
||||||
callback: (GetTransactionsResponse) -> Unit) {
|
callback: (GetTransactionsResponse) -> Unit) {
|
||||||
|
|
||||||
fetchAccountTransactionsAsync(bankAccount, null, false, callback)
|
fetchAccountTransactionsAsync(bankAccount, null, false, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun fetchAccountTransactionsAsync(bankAccount: BankAccount, fromDate: Date?, abortIfTanIsRequired: Boolean = false,
|
open fun fetchAccountTransactionsAsync(bankAccount: TypedBankAccount, fromDate: Date?, abortIfTanIsRequired: Boolean = false,
|
||||||
callback: (GetTransactionsResponse) -> Unit) {
|
callback: (GetTransactionsResponse) -> Unit) {
|
||||||
|
|
||||||
getBankingClientForAccount(bankAccount.customer)?.let { client ->
|
getBankingClientForAccount(bankAccount.customer)?.let { client ->
|
||||||
|
@ -319,7 +322,7 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun updateBanksAccountsTransactionsAsync(accounts: List<BankAccount>, abortIfTanIsRequired: Boolean = false, callback: (GetTransactionsResponse) -> Unit) {
|
protected open fun updateBanksAccountsTransactionsAsync(accounts: List<TypedBankAccount>, abortIfTanIsRequired: Boolean = false, callback: (GetTransactionsResponse) -> Unit) {
|
||||||
accounts.forEach { bankAccount ->
|
accounts.forEach { bankAccount ->
|
||||||
if (bankAccount.supportsRetrievingAccountTransactions) {
|
if (bankAccount.supportsRetrievingAccountTransactions) {
|
||||||
updateBankAccountTransactionsAsync(bankAccount, abortIfTanIsRequired, callback)
|
updateBankAccountTransactionsAsync(bankAccount, abortIfTanIsRequired, callback)
|
||||||
|
@ -327,7 +330,7 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun updateBankAccountTransactionsAsync(bankAccount: BankAccount, abortIfTanIsRequired: Boolean, callback: (GetTransactionsResponse) -> Unit) {
|
protected open fun updateBankAccountTransactionsAsync(bankAccount: TypedBankAccount, abortIfTanIsRequired: Boolean, callback: (GetTransactionsResponse) -> Unit) {
|
||||||
val fromDate = bankAccount.lastRetrievedTransactionsTimestamp?.let { Date(it.millisSinceEpoch - OneDayMillis) } // one day before last received transactions
|
val fromDate = bankAccount.lastRetrievedTransactionsTimestamp?.let { Date(it.millisSinceEpoch - OneDayMillis) } // one day before last received transactions
|
||||||
|
|
||||||
fetchAccountTransactionsAsync(bankAccount, fromDate, abortIfTanIsRequired, callback)
|
fetchAccountTransactionsAsync(bankAccount, fromDate, abortIfTanIsRequired, callback)
|
||||||
|
@ -347,7 +350,7 @@ open class BankingPresenter(
|
||||||
callRetrievedAccountTransactionsResponseListener(response)
|
callRetrievedAccountTransactionsResponseListener(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun receivedAccountsTransactionChunk(bankAccount: BankAccount, accountTransactionsChunk: List<AccountTransaction>) {
|
protected open fun receivedAccountsTransactionChunk(bankAccount: TypedBankAccount, accountTransactionsChunk: List<IAccountTransaction>) {
|
||||||
if (accountTransactionsChunk.isNotEmpty()) {
|
if (accountTransactionsChunk.isNotEmpty()) {
|
||||||
bankAccount.addBookedTransactions(accountTransactionsChunk)
|
bankAccount.addBookedTransactions(accountTransactionsChunk)
|
||||||
|
|
||||||
|
@ -370,7 +373,7 @@ open class BankingPresenter(
|
||||||
persistAccountTransactions(bankAccount, response.bookedTransactions, response.unbookedTransactions)
|
persistAccountTransactions(bankAccount, response.bookedTransactions, response.unbookedTransactions)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun updateBalance(bankAccount: BankAccount, balance: BigDecimal) {
|
protected open fun updateBalance(bankAccount: TypedBankAccount, balance: BigDecimal) {
|
||||||
bankAccount.balance = balance
|
bankAccount.balance = balance
|
||||||
|
|
||||||
persistAccount(bankAccount.customer)
|
persistAccount(bankAccount.customer)
|
||||||
|
@ -388,25 +391,25 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun accountDisplayIndexUpdated(account: Customer) {
|
open fun accountDisplayIndexUpdated(account: TypedCustomer) {
|
||||||
persistAccount(account)
|
persistAccount(account)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun accountUpdated(bank: Customer) {
|
open fun accountUpdated(bank: TypedCustomer) {
|
||||||
persistAccount(bank)
|
persistAccount(bank)
|
||||||
|
|
||||||
getBankingClientForAccount(bank)?.dataChanged(bank)
|
getBankingClientForAccount(bank)?.dataChanged(bank)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun accountUpdated(account: BankAccount) {
|
open fun accountUpdated(account: TypedBankAccount) {
|
||||||
persistAccount(account.customer)
|
persistAccount(account.customer)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun persistAccount(customer: Customer) {
|
protected open fun persistAccount(customer: ICustomer<*, *>) {
|
||||||
persister.saveOrUpdateAccount(customer, customers)
|
persister.saveOrUpdateAccount(customer as TypedCustomer, customers)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun persistAccountTransactions(bankAccount: BankAccount, bookedTransactions: List<AccountTransaction>, unbookedTransactions: List<Any>) {
|
protected open fun persistAccountTransactions(bankAccount: TypedBankAccount, bookedTransactions: List<IAccountTransaction>, unbookedTransactions: List<Any>) {
|
||||||
persister.saveOrUpdateAccountTransactions(bankAccount, bookedTransactions)
|
persister.saveOrUpdateAccountTransactions(bankAccount, bookedTransactions)
|
||||||
|
|
||||||
// TODO: someday also persist unbooked transactions
|
// TODO: someday also persist unbooked transactions
|
||||||
|
@ -513,11 +516,11 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun searchSelectedAccountTransactions(query: String): List<AccountTransaction> {
|
open fun searchSelectedAccountTransactions(query: String): List<IAccountTransaction> {
|
||||||
return searchAccountTransactions(query, selectedBankAccountsAccountTransactions)
|
return searchAccountTransactions(query, selectedBankAccountsAccountTransactions)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun searchAccountTransactions(query: String, transactions: List<AccountTransaction>): List<AccountTransaction> {
|
open fun searchAccountTransactions(query: String, transactions: List<IAccountTransaction>): List<IAccountTransaction> {
|
||||||
val queryLowercase = query.trim().toLowerCase()
|
val queryLowercase = query.trim().toLowerCase()
|
||||||
|
|
||||||
if (queryLowercase.isEmpty()) {
|
if (queryLowercase.isEmpty()) {
|
||||||
|
@ -532,7 +535,7 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun getMessageLogForAccounts(customers: List<Customer>): List<String> {
|
open fun getMessageLogForAccounts(customers: List<TypedCustomer>): List<String> {
|
||||||
val logEntries = customers.flatMap {
|
val logEntries = customers.flatMap {
|
||||||
getBankingClientForAccount(it)?.messageLogWithoutSensitiveData ?: listOf()
|
getBankingClientForAccount(it)?.messageLogWithoutSensitiveData ?: listOf()
|
||||||
}
|
}
|
||||||
|
@ -556,15 +559,15 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected open fun getBankingClientForAccount(customer: Customer): IBankingClient? {
|
protected open fun getBankingClientForAccount(customer: ICustomer<*, *>): IBankingClient? {
|
||||||
return bankingClientsForAccounts.get(customer)
|
return bankingClientsForAccounts.get(customer as TypedCustomer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open val selectedBankAccounts: List<BankAccount>
|
open val selectedBankAccounts: List<TypedBankAccount>
|
||||||
get() = ArrayList(selectedBankAccountsField)
|
get() = ArrayList(selectedBankAccountsField)
|
||||||
|
|
||||||
open val selectedBankAccountsAccountTransactions: List<AccountTransaction>
|
open val selectedBankAccountsAccountTransactions: List<IAccountTransaction>
|
||||||
get() = getAccountTransactionsForBankAccounts(selectedBankAccounts)
|
get() = getAccountTransactionsForBankAccounts(selectedBankAccounts)
|
||||||
|
|
||||||
open val balanceOfSelectedBankAccounts: BigDecimal
|
open val balanceOfSelectedBankAccounts: BigDecimal
|
||||||
|
@ -574,12 +577,12 @@ open class BankingPresenter(
|
||||||
open val areAllAccountSelected: Boolean
|
open val areAllAccountSelected: Boolean
|
||||||
get() = selectedAccountType == SelectedAccountType.AllAccounts
|
get() = selectedAccountType == SelectedAccountType.AllAccounts
|
||||||
|
|
||||||
open fun isSingleSelectedAccount(customer: Customer): Boolean {
|
open fun isSingleSelectedAccount(customer: TypedCustomer): Boolean {
|
||||||
return selectedAccountType == SelectedAccountType.SingleAccount
|
return selectedAccountType == SelectedAccountType.SingleAccount
|
||||||
&& selectedBankAccountsField.map { it.customer }.toSet().containsExactly(customer)
|
&& selectedBankAccountsField.map { it.customer }.toSet().containsExactly(customer)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun isSingleSelectedBankAccount(bankAccount: BankAccount): Boolean {
|
open fun isSingleSelectedBankAccount(bankAccount: TypedBankAccount): Boolean {
|
||||||
return selectedAccountType == SelectedAccountType.SingleBankAccount
|
return selectedAccountType == SelectedAccountType.SingleBankAccount
|
||||||
&& selectedBankAccountsField.containsExactly(bankAccount)
|
&& selectedBankAccountsField.containsExactly(bankAccount)
|
||||||
}
|
}
|
||||||
|
@ -590,39 +593,39 @@ open class BankingPresenter(
|
||||||
setSelectedBankAccounts(bankAccounts)
|
setSelectedBankAccounts(bankAccounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun selectedAccount(customer: Customer) {
|
open fun selectedAccount(customer: TypedCustomer) {
|
||||||
selectedAccountType = SelectedAccountType.SingleAccount
|
selectedAccountType = SelectedAccountType.SingleAccount
|
||||||
|
|
||||||
setSelectedBankAccounts(customer.accounts)
|
setSelectedBankAccounts(customer.accounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun selectedBankAccount(bankAccount: BankAccount) {
|
open fun selectedBankAccount(bankAccount: TypedBankAccount) {
|
||||||
selectedAccountType = SelectedAccountType.SingleBankAccount
|
selectedAccountType = SelectedAccountType.SingleBankAccount
|
||||||
|
|
||||||
setSelectedBankAccounts(listOf(bankAccount))
|
setSelectedBankAccounts(listOf(bankAccount))
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun setSelectedBankAccounts(bankAccounts: List<BankAccount>) {
|
protected open fun setSelectedBankAccounts(bankAccounts: List<TypedBankAccount>) {
|
||||||
this.selectedBankAccountsField = ArrayList(bankAccounts) // make a copy
|
this.selectedBankAccountsField = ArrayList(bankAccounts) // make a copy
|
||||||
|
|
||||||
callSelectedBankAccountsChangedListeners(selectedBankAccountsField)
|
callSelectedBankAccountsChangedListeners(selectedBankAccountsField)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open val customers: List<Customer>
|
open val customers: List<TypedCustomer>
|
||||||
get() = bankingClientsForAccounts.keys.toList()
|
get() = bankingClientsForAccounts.keys.toList()
|
||||||
|
|
||||||
open val bankAccounts: List<BankAccount>
|
open val bankAccounts: List<TypedBankAccount>
|
||||||
get() = customers.flatMap { it.accounts }
|
get() = customers.flatMap { it.accounts }
|
||||||
|
|
||||||
open val allTransactions: List<AccountTransaction>
|
open val allTransactions: List<IAccountTransaction>
|
||||||
get() = getAccountTransactionsForBankAccounts(bankAccounts)
|
get() = getAccountTransactionsForBankAccounts(bankAccounts)
|
||||||
|
|
||||||
open val balanceOfAllAccounts: BigDecimal
|
open val balanceOfAllAccounts: BigDecimal
|
||||||
get() = getBalanceForAccounts(customers)
|
get() = getBalanceForAccounts(customers)
|
||||||
|
|
||||||
|
|
||||||
open val bankAccountsSupportingRetrievingAccountTransactions: List<BankAccount>
|
open val bankAccountsSupportingRetrievingAccountTransactions: List<TypedBankAccount>
|
||||||
get() = bankAccounts.filter { it.supportsRetrievingAccountTransactions }
|
get() = bankAccounts.filter { it.supportsRetrievingAccountTransactions }
|
||||||
|
|
||||||
open val hasBankAccountsSupportingRetrievingAccountTransactions: Boolean
|
open val hasBankAccountsSupportingRetrievingAccountTransactions: Boolean
|
||||||
|
@ -631,12 +634,12 @@ open class BankingPresenter(
|
||||||
open val doSelectedBankAccountsSupportRetrievingAccountTransactions: Boolean
|
open val doSelectedBankAccountsSupportRetrievingAccountTransactions: Boolean
|
||||||
get() = doBankAccountsSupportRetrievingAccountTransactions(selectedBankAccounts)
|
get() = doBankAccountsSupportRetrievingAccountTransactions(selectedBankAccounts)
|
||||||
|
|
||||||
open fun doBankAccountsSupportRetrievingAccountTransactions(bankAccounts: List<BankAccount>): Boolean {
|
open fun doBankAccountsSupportRetrievingAccountTransactions(bankAccounts: List<TypedBankAccount>): Boolean {
|
||||||
return bankAccounts.firstOrNull { it.supportsRetrievingAccountTransactions } != null
|
return bankAccounts.firstOrNull { it.supportsRetrievingAccountTransactions } != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open val bankAccountsSupportingRetrievingBalance: List<BankAccount>
|
open val bankAccountsSupportingRetrievingBalance: List<TypedBankAccount>
|
||||||
get() = bankAccounts.filter { it.supportsRetrievingBalance }
|
get() = bankAccounts.filter { it.supportsRetrievingBalance }
|
||||||
|
|
||||||
open val hasBankAccountsSupportingRetrievingBalance: Boolean
|
open val hasBankAccountsSupportingRetrievingBalance: Boolean
|
||||||
|
@ -645,12 +648,12 @@ open class BankingPresenter(
|
||||||
open val doSelectedBankAccountsSupportRetrievingBalance: Boolean
|
open val doSelectedBankAccountsSupportRetrievingBalance: Boolean
|
||||||
get() = doBankAccountsSupportRetrievingBalance(selectedBankAccounts)
|
get() = doBankAccountsSupportRetrievingBalance(selectedBankAccounts)
|
||||||
|
|
||||||
open fun doBankAccountsSupportRetrievingBalance(bankAccounts: List<BankAccount>): Boolean {
|
open fun doBankAccountsSupportRetrievingBalance(bankAccounts: List<TypedBankAccount>): Boolean {
|
||||||
return bankAccounts.firstOrNull { it.supportsRetrievingBalance } != null
|
return bankAccounts.firstOrNull { it.supportsRetrievingBalance } != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open val bankAccountsSupportingTransferringMoney: List<BankAccount>
|
open val bankAccountsSupportingTransferringMoney: List<TypedBankAccount>
|
||||||
get() = bankAccounts.filter { it.supportsTransferringMoney }
|
get() = bankAccounts.filter { it.supportsTransferringMoney }
|
||||||
|
|
||||||
open val hasBankAccountsSupportTransferringMoney: Boolean
|
open val hasBankAccountsSupportTransferringMoney: Boolean
|
||||||
|
@ -659,16 +662,16 @@ open class BankingPresenter(
|
||||||
open val doSelectedBankAccountsSupportTransferringMoney: Boolean
|
open val doSelectedBankAccountsSupportTransferringMoney: Boolean
|
||||||
get() = doBankAccountsSupportTransferringMoney(selectedBankAccounts)
|
get() = doBankAccountsSupportTransferringMoney(selectedBankAccounts)
|
||||||
|
|
||||||
open fun doBankAccountsSupportTransferringMoney(bankAccounts: List<BankAccount>): Boolean {
|
open fun doBankAccountsSupportTransferringMoney(bankAccounts: List<TypedBankAccount>): Boolean {
|
||||||
return bankAccounts.firstOrNull { it.supportsTransferringMoney } != null
|
return bankAccounts.firstOrNull { it.supportsTransferringMoney } != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected open fun getAccountTransactionsForBankAccounts(bankAccounts: Collection<BankAccount>): List<AccountTransaction> {
|
protected open fun getAccountTransactionsForBankAccounts(bankAccounts: Collection<TypedBankAccount>): List<IAccountTransaction> {
|
||||||
return bankAccounts.flatMap { it.bookedTransactions }.sortedByDescending { it.valueDate.millisSinceEpoch } // TODO: someday add unbooked transactions
|
return bankAccounts.flatMap { it.bookedTransactions }.sortedByDescending { it.valueDate.millisSinceEpoch } // TODO: someday add unbooked transactions
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getBalanceForAccounts(customers: Collection<Customer>): BigDecimal {
|
protected open fun getBalanceForAccounts(customers: Collection<TypedCustomer>): BigDecimal {
|
||||||
return customers.map { it.balance }.sum()
|
return customers.map { it.balance }.sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,7 +680,7 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun getTanMediaForTanProcedure(bank: Customer, tanProcedure: TanProcedure): List<TanMedium> {
|
open fun getTanMediaForTanProcedure(bank: TypedCustomer, tanProcedure: TanProcedure): List<TanMedium> {
|
||||||
if (ChipTanTanProcedures.contains(tanProcedure.type)) {
|
if (ChipTanTanProcedures.contains(tanProcedure.type)) {
|
||||||
return bank.tanMediaSorted.filterIsInstance<TanGeneratorTanMedium>()
|
return bank.tanMediaSorted.filterIsInstance<TanGeneratorTanMedium>()
|
||||||
}
|
}
|
||||||
|
@ -719,11 +722,11 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun addAccountsChangedListener(listener: (List<Customer>) -> Unit): Boolean {
|
open fun addAccountsChangedListener(listener: (List<TypedCustomer>) -> Unit): Boolean {
|
||||||
return accountsChangedListeners.add(listener)
|
return accountsChangedListeners.add(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun removeAccountsChangedListener(listener: (List<Customer>) -> Unit): Boolean {
|
open fun removeAccountsChangedListener(listener: (List<TypedCustomer>) -> Unit): Boolean {
|
||||||
return accountsChangedListeners.add(listener)
|
return accountsChangedListeners.add(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,15 +754,15 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun addSelectedBankAccountsChangedListener(listener: (List<BankAccount>) -> Unit): Boolean {
|
open fun addSelectedBankAccountsChangedListener(listener: (List<TypedBankAccount>) -> Unit): Boolean {
|
||||||
return selectedBankAccountsChangedListeners.add(listener)
|
return selectedBankAccountsChangedListeners.add(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun removeSelectedBankAccountsChangedListener(listener: (List<BankAccount>) -> Unit): Boolean {
|
open fun removeSelectedBankAccountsChangedListener(listener: (List<TypedBankAccount>) -> Unit): Boolean {
|
||||||
return selectedBankAccountsChangedListeners.add(listener)
|
return selectedBankAccountsChangedListeners.add(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun callSelectedBankAccountsChangedListeners(selectedBankAccounts: List<BankAccount>) {
|
protected open fun callSelectedBankAccountsChangedListeners(selectedBankAccounts: List<TypedBankAccount>) {
|
||||||
val selectedBankAccounts = this.selectedBankAccounts
|
val selectedBankAccounts = this.selectedBankAccounts
|
||||||
|
|
||||||
ArrayList(selectedBankAccountsChangedListeners).forEach {
|
ArrayList(selectedBankAccountsChangedListeners).forEach {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import net.dankito.banking.fints.webclient.IWebClient
|
||||||
import net.dankito.banking.persistence.IBankingPersistence
|
import net.dankito.banking.persistence.IBankingPersistence
|
||||||
import net.dankito.banking.search.IRemitteeSearcher
|
import net.dankito.banking.search.IRemitteeSearcher
|
||||||
import net.dankito.banking.ui.IRouter
|
import net.dankito.banking.ui.IRouter
|
||||||
|
import net.dankito.banking.ui.model.mapper.DefaultModelCreator
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
import net.dankito.banking.util.*
|
import net.dankito.banking.util.*
|
||||||
import net.dankito.banking.util.extraction.NoOpInvoiceDataExtractor
|
import net.dankito.banking.util.extraction.NoOpInvoiceDataExtractor
|
||||||
|
@ -14,7 +15,7 @@ import net.dankito.utils.multiplatform.File
|
||||||
|
|
||||||
class BankingPresenterSwift(dataFolder: File, router: IRouter, webClient: IWebClient, persistence: IBankingPersistence,
|
class BankingPresenterSwift(dataFolder: File, router: IRouter, webClient: IWebClient, persistence: IBankingPersistence,
|
||||||
remitteeSearcher: IRemitteeSearcher, bankIconFinder: IBankIconFinder, serializer: ISerializer, asyncRunner: IAsyncRunner)
|
remitteeSearcher: IRemitteeSearcher, bankIconFinder: IBankIconFinder, serializer: ISerializer, asyncRunner: IAsyncRunner)
|
||||||
: BankingPresenter(fints4kBankingClientCreator(serializer, webClient), InMemoryBankFinder(), dataFolder, persistence, router,
|
: BankingPresenter(fints4kBankingClientCreator(DefaultModelCreator(), serializer, webClient), InMemoryBankFinder(), dataFolder, persistence, router, DefaultModelCreator(),
|
||||||
remitteeSearcher, bankIconFinder, NoOpTextExtractorRegistry(), NoOpInvoiceDataExtractor(), serializer, asyncRunner) {
|
remitteeSearcher, bankIconFinder, NoOpTextExtractorRegistry(), NoOpInvoiceDataExtractor(), serializer, asyncRunner) {
|
||||||
|
|
||||||
}
|
}
|
|
@ -35,6 +35,8 @@
|
||||||
366FA4E224C4ED6C0094F009 /* EnterTanDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4E124C4ED6C0094F009 /* EnterTanDialog.swift */; };
|
366FA4E224C4ED6C0094F009 /* EnterTanDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4E124C4ED6C0094F009 /* EnterTanDialog.swift */; };
|
||||||
366FA4E624C6EBF40094F009 /* EnterTanState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4E524C6EBF40094F009 /* EnterTanState.swift */; };
|
366FA4E624C6EBF40094F009 /* EnterTanState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4E524C6EBF40094F009 /* EnterTanState.swift */; };
|
||||||
3684EB8B2508F6F00001139E /* SearchBarWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3684EB8A2508F6F00001139E /* SearchBarWithLabel.swift */; };
|
3684EB8B2508F6F00001139E /* SearchBarWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3684EB8A2508F6F00001139E /* SearchBarWithLabel.swift */; };
|
||||||
|
3684EB8F250B7F3C0001139E /* BankingUiCommon.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3684EB8E250B7F3C0001139E /* BankingUiCommon.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
|
3684EB90250B7F560001139E /* BankingUiCommon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3684EB8E250B7F3C0001139E /* BankingUiCommon.framework */; };
|
||||||
36B8A4482503D12100C15359 /* ProtectAppSettingsDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B8A4472503D12100C15359 /* ProtectAppSettingsDialog.swift */; };
|
36B8A4482503D12100C15359 /* ProtectAppSettingsDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B8A4472503D12100C15359 /* ProtectAppSettingsDialog.swift */; };
|
||||||
36B8A44B2503D1E800C15359 /* BiometricAuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B8A44A2503D1E800C15359 /* BiometricAuthenticationService.swift */; };
|
36B8A44B2503D1E800C15359 /* BiometricAuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B8A44A2503D1E800C15359 /* BiometricAuthenticationService.swift */; };
|
||||||
36B8A44D2503D96D00C15359 /* AuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B8A44C2503D96D00C15359 /* AuthenticationService.swift */; };
|
36B8A44D2503D96D00C15359 /* AuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B8A44C2503D96D00C15359 /* AuthenticationService.swift */; };
|
||||||
|
@ -44,8 +46,6 @@
|
||||||
36B8A4562503E9B200C15359 /* UIAlertBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B8A4552503E9B200C15359 /* UIAlertBase.swift */; };
|
36B8A4562503E9B200C15359 /* UIAlertBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B8A4552503E9B200C15359 /* UIAlertBase.swift */; };
|
||||||
36B8A4582503EEB600C15359 /* ActionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B8A4572503EEB600C15359 /* ActionSheet.swift */; };
|
36B8A4582503EEB600C15359 /* ActionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B8A4572503EEB600C15359 /* ActionSheet.swift */; };
|
||||||
36BCF85424BA0C54005BEC29 /* BankList.json in Resources */ = {isa = PBXBuildFile; fileRef = 36BCF85324BA0C54005BEC29 /* BankList.json */; };
|
36BCF85424BA0C54005BEC29 /* BankList.json in Resources */ = {isa = PBXBuildFile; fileRef = 36BCF85324BA0C54005BEC29 /* BankList.json */; };
|
||||||
36BCF85824BA4274005BEC29 /* BankingUiCommon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36BCF85524BA41EE005BEC29 /* BankingUiCommon.framework */; };
|
|
||||||
36BCF85924BA4274005BEC29 /* BankingUiCommon.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 36BCF85524BA41EE005BEC29 /* BankingUiCommon.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
|
||||||
36BCF85E24BA4DA8005BEC29 /* MultiplatformUtils.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36BCF85D24BA4DA8005BEC29 /* MultiplatformUtils.framework */; };
|
36BCF85E24BA4DA8005BEC29 /* MultiplatformUtils.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36BCF85D24BA4DA8005BEC29 /* MultiplatformUtils.framework */; };
|
||||||
36BCF85F24BA4DA8005BEC29 /* MultiplatformUtils.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 36BCF85D24BA4DA8005BEC29 /* MultiplatformUtils.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
36BCF85F24BA4DA8005BEC29 /* MultiplatformUtils.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 36BCF85D24BA4DA8005BEC29 /* MultiplatformUtils.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
36BCF86324BA5097005BEC29 /* SwiftUiRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36BCF86224BA5097005BEC29 /* SwiftUiRouter.swift */; };
|
36BCF86324BA5097005BEC29 /* SwiftUiRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36BCF86224BA5097005BEC29 /* SwiftUiRouter.swift */; };
|
||||||
|
@ -138,8 +138,8 @@
|
||||||
dstPath = "";
|
dstPath = "";
|
||||||
dstSubfolderSpec = 10;
|
dstSubfolderSpec = 10;
|
||||||
files = (
|
files = (
|
||||||
|
3684EB8F250B7F3C0001139E /* BankingUiCommon.framework in Embed Frameworks */,
|
||||||
36BCF86A24BA550D005BEC29 /* BankFinder.framework in Embed Frameworks */,
|
36BCF86A24BA550D005BEC29 /* BankFinder.framework in Embed Frameworks */,
|
||||||
36BCF85924BA4274005BEC29 /* BankingUiCommon.framework in Embed Frameworks */,
|
|
||||||
36BCF85F24BA4DA8005BEC29 /* MultiplatformUtils.framework in Embed Frameworks */,
|
36BCF85F24BA4DA8005BEC29 /* MultiplatformUtils.framework in Embed Frameworks */,
|
||||||
36FC92D124B39C47002B12E9 /* fints4k.framework in Embed Frameworks */,
|
36FC92D124B39C47002B12E9 /* fints4k.framework in Embed Frameworks */,
|
||||||
36BCF87124BB0F8A005BEC29 /* fints4kBankingClient.framework in Embed Frameworks */,
|
36BCF87124BB0F8A005BEC29 /* fints4kBankingClient.framework in Embed Frameworks */,
|
||||||
|
@ -179,6 +179,8 @@
|
||||||
366FA4E124C4ED6C0094F009 /* EnterTanDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnterTanDialog.swift; sourceTree = "<group>"; };
|
366FA4E124C4ED6C0094F009 /* EnterTanDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnterTanDialog.swift; sourceTree = "<group>"; };
|
||||||
366FA4E524C6EBF40094F009 /* EnterTanState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnterTanState.swift; sourceTree = "<group>"; };
|
366FA4E524C6EBF40094F009 /* EnterTanState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnterTanState.swift; sourceTree = "<group>"; };
|
||||||
3684EB8A2508F6F00001139E /* SearchBarWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBarWithLabel.swift; sourceTree = "<group>"; };
|
3684EB8A2508F6F00001139E /* SearchBarWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBarWithLabel.swift; sourceTree = "<group>"; };
|
||||||
|
3684EB8C250B7F2B0001139E /* BankingUiCommon.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = BankingUiCommon.framework.dSYM; path = "../BankingUiCommon/build/xcode-frameworks/BankingUiCommon.framework.dSYM"; sourceTree = "<group>"; };
|
||||||
|
3684EB8E250B7F3C0001139E /* BankingUiCommon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BankingUiCommon.framework; path = "../BankingUiCommon/build/xcode-frameworks/BankingUiCommon.framework"; sourceTree = "<group>"; };
|
||||||
36B8A4472503D12100C15359 /* ProtectAppSettingsDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtectAppSettingsDialog.swift; sourceTree = "<group>"; };
|
36B8A4472503D12100C15359 /* ProtectAppSettingsDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtectAppSettingsDialog.swift; sourceTree = "<group>"; };
|
||||||
36B8A44A2503D1E800C15359 /* BiometricAuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BiometricAuthenticationService.swift; sourceTree = "<group>"; };
|
36B8A44A2503D1E800C15359 /* BiometricAuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BiometricAuthenticationService.swift; sourceTree = "<group>"; };
|
||||||
36B8A44C2503D96D00C15359 /* AuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationService.swift; sourceTree = "<group>"; };
|
36B8A44C2503D96D00C15359 /* AuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationService.swift; sourceTree = "<group>"; };
|
||||||
|
@ -264,8 +266,8 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
3684EB90250B7F560001139E /* BankingUiCommon.framework in Frameworks */,
|
||||||
36BCF86924BA550D005BEC29 /* BankFinder.framework in Frameworks */,
|
36BCF86924BA550D005BEC29 /* BankFinder.framework in Frameworks */,
|
||||||
36BCF85824BA4274005BEC29 /* BankingUiCommon.framework in Frameworks */,
|
|
||||||
36BCF85E24BA4DA8005BEC29 /* MultiplatformUtils.framework in Frameworks */,
|
36BCF85E24BA4DA8005BEC29 /* MultiplatformUtils.framework in Frameworks */,
|
||||||
36FC92D024B39C47002B12E9 /* fints4k.framework in Frameworks */,
|
36FC92D024B39C47002B12E9 /* fints4k.framework in Frameworks */,
|
||||||
36BCF87024BB0F8A005BEC29 /* fints4kBankingClient.framework in Frameworks */,
|
36BCF87024BB0F8A005BEC29 /* fints4kBankingClient.framework in Frameworks */,
|
||||||
|
@ -419,6 +421,8 @@
|
||||||
36FC928F24B39A05002B12E9 = {
|
36FC928F24B39A05002B12E9 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
3684EB8E250B7F3C0001139E /* BankingUiCommon.framework */,
|
||||||
|
3684EB8C250B7F2B0001139E /* BankingUiCommon.framework.dSYM */,
|
||||||
36FC929A24B39A05002B12E9 /* BankingiOSApp */,
|
36FC929A24B39A05002B12E9 /* BankingiOSApp */,
|
||||||
36FC92B424B39A08002B12E9 /* BankingiOSAppTests */,
|
36FC92B424B39A08002B12E9 /* BankingiOSAppTests */,
|
||||||
36FC92BF24B39A08002B12E9 /* BankingiOSAppUITests */,
|
36FC92BF24B39A08002B12E9 /* BankingiOSAppUITests */,
|
||||||
|
|
|
@ -15,7 +15,7 @@ let previewImageTanChallenge = ImageTanChallenge(image: TanImage(mimeType: "imag
|
||||||
let previewFlickerCodeTanChallenge = FlickerCodeTanChallenge(flickerCode: FlickerCode(challengeHHD_UC: "", parsedDataSet: "", decodingError: nil), messageToShowToUser: "", tanProcedure: previewTanProcedures[0])
|
let previewFlickerCodeTanChallenge = FlickerCodeTanChallenge(flickerCode: FlickerCode(challengeHHD_UC: "", parsedDataSet: "", decodingError: nil), messageToShowToUser: "", tanProcedure: previewTanProcedures[0])
|
||||||
|
|
||||||
|
|
||||||
func createPreviewBanks() -> [Customer] {
|
func createPreviewBanks() -> [ICustomer] {
|
||||||
let bank1 = Customer(bankCode: "", customerId: "", password: "", finTsServerAddress: "", bankName: "Abzockbank", bic: "", customerName: "Marieke Musterfrau", userId: "", iconUrl: "", accounts: [])
|
let bank1 = Customer(bankCode: "", customerId: "", password: "", finTsServerAddress: "", bankName: "Abzockbank", bic: "", customerName: "Marieke Musterfrau", userId: "", iconUrl: "", accounts: [])
|
||||||
|
|
||||||
bank1.accounts = [
|
bank1.accounts = [
|
||||||
|
|
|
@ -89,7 +89,32 @@ extension AccountTransaction : Identifiable {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extension Array where Element == Customer {
|
func ==(lhs: ICustomer, rhs: ICustomer) -> Bool {
|
||||||
|
return lhs.technicalId == rhs.technicalId
|
||||||
|
}
|
||||||
|
|
||||||
|
func !=(lhs: ICustomer, rhs: ICustomer) -> Bool {
|
||||||
|
return lhs.technicalId != rhs.technicalId
|
||||||
|
}
|
||||||
|
|
||||||
|
func ==(lhs: IBankAccount, rhs: IBankAccount) -> Bool {
|
||||||
|
return lhs.technicalId == rhs.technicalId
|
||||||
|
}
|
||||||
|
|
||||||
|
func !=(lhs: IBankAccount, rhs: IBankAccount) -> Bool {
|
||||||
|
return lhs.technicalId != rhs.technicalId
|
||||||
|
}
|
||||||
|
|
||||||
|
func ==(lhs: IAccountTransaction, rhs: IAccountTransaction) -> Bool {
|
||||||
|
return lhs.technicalId == rhs.technicalId
|
||||||
|
}
|
||||||
|
|
||||||
|
func !=(lhs: IAccountTransaction, rhs: IAccountTransaction) -> Bool {
|
||||||
|
return lhs.technicalId != rhs.technicalId
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension Array where Element == ICustomer {
|
||||||
|
|
||||||
func sumBalances() -> CommonBigDecimal {
|
func sumBalances() -> CommonBigDecimal {
|
||||||
return CommonBigDecimal(decimal_: self.map { $0.balance.decimal }.sum())
|
return CommonBigDecimal(decimal_: self.map { $0.balance.decimal }.sum())
|
||||||
|
@ -97,7 +122,7 @@ extension Array where Element == Customer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Array where Element == AccountTransaction {
|
extension Array where Element == IAccountTransaction {
|
||||||
|
|
||||||
func sumAmounts() -> CommonBigDecimal {
|
func sumAmounts() -> CommonBigDecimal {
|
||||||
return CommonBigDecimal(decimal_: self.map { $0.amount.decimal }.sum())
|
return CommonBigDecimal(decimal_: self.map { $0.amount.decimal }.sum())
|
||||||
|
|
|
@ -6,8 +6,8 @@ class AppData : ObservableObject {
|
||||||
|
|
||||||
@Inject private var presenter: BankingPresenterSwift
|
@Inject private var presenter: BankingPresenterSwift
|
||||||
|
|
||||||
@Published var banks: [Customer] = []
|
@Published var banks: [ICustomer] = []
|
||||||
@Published var banksSorted: [Customer] = []
|
@Published var banksSorted: [ICustomer] = []
|
||||||
|
|
||||||
@Published var hasAtLeastOneAccountBeenAdded: Bool = false
|
@Published var hasAtLeastOneAccountBeenAdded: Bool = false
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ class AppData : ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private func setFieldsForBanks(_ banks: [Customer]) {
|
private func setFieldsForBanks(_ banks: [ICustomer]) {
|
||||||
self.banks = presenter.customers
|
self.banks = presenter.customers
|
||||||
self.banksSorted = banks.sortedByDisplayIndex()
|
self.banksSorted = banks.sortedByDisplayIndex()
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func saveOrUpdateAccount(customer: Customer, allCustomers: [Customer]) {
|
func saveOrUpdateAccount(customer: ICustomer, allCustomers: [ICustomer]) {
|
||||||
do {
|
do {
|
||||||
let mapped = mapper.map(customer, context)
|
let mapped = mapper.map(customer, context)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setIds(_ customer: Customer, _ mappedCustomer: PersistedCustomer) {
|
private func setIds(_ customer: ICustomer, _ mappedCustomer: PersistedCustomer) {
|
||||||
customer.technicalId = mappedCustomer.objectIDAsString
|
customer.technicalId = mappedCustomer.objectIDAsString
|
||||||
|
|
||||||
for account in customer.accounts {
|
for account in customer.accounts {
|
||||||
|
@ -58,7 +58,7 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func readPersistedAccounts_() -> [Customer] {
|
func readPersistedAccounts_() -> [ICustomer] {
|
||||||
var customers: [PersistedCustomer] = []
|
var customers: [PersistedCustomer] = []
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -73,7 +73,7 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
|
||||||
return customers.map( { mapper.map($0) } )
|
return customers.map( { mapper.map($0) } )
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteAccount(customer: Customer, allCustomers: [Customer]) {
|
func deleteAccount(customer: ICustomer, allCustomers: [ICustomer]) {
|
||||||
do {
|
do {
|
||||||
let mapped = mapper.map(customer, context)
|
let mapped = mapper.map(customer, context)
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveOrUpdateAccountTransactions(bankAccount: BankAccount, transactions: [AccountTransaction]) {
|
func saveOrUpdateAccountTransactions(bankAccount: IBankAccount, transactions: [IAccountTransaction]) {
|
||||||
if let persistedAccount = context.objectByID(bankAccount.technicalId) as? PersistedBankAccount {
|
if let persistedAccount = context.objectByID(bankAccount.technicalId) as? PersistedBankAccount {
|
||||||
for transaction in transactions {
|
for transaction in transactions {
|
||||||
if transaction.technicalId.isCoreDataId == false { // TODO: or also update already persisted transactions?
|
if transaction.technicalId.isCoreDataId == false { // TODO: or also update already persisted transactions?
|
||||||
|
@ -96,7 +96,7 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
|
||||||
|
|
||||||
transaction.technicalId = mappedTransaction.objectIDAsString
|
transaction.technicalId = mappedTransaction.objectIDAsString
|
||||||
} catch {
|
} catch {
|
||||||
NSLog("Could not save transaction \(transaction.transactionIdentifier) of account \(bankAccount.displayName): \(error)")
|
NSLog("Could not save transaction \(transaction.buildTransactionIdentifier()) of account \(bankAccount.displayName): \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,14 @@ class EnterTanState : Identifiable {
|
||||||
|
|
||||||
let id: Foundation.UUID = UUID()
|
let id: Foundation.UUID = UUID()
|
||||||
|
|
||||||
let customer: Customer
|
let customer: ICustomer
|
||||||
|
|
||||||
let tanChallenge: TanChallenge
|
let tanChallenge: TanChallenge
|
||||||
|
|
||||||
let callback: (EnterTanResult) -> Void
|
let callback: (EnterTanResult) -> Void
|
||||||
|
|
||||||
|
|
||||||
init(_ customer: Customer, _ tanChallenge: TanChallenge, _ callback: @escaping (EnterTanResult) -> Void) {
|
init(_ customer: ICustomer, _ tanChallenge: TanChallenge, _ callback: @escaping (EnterTanResult) -> Void) {
|
||||||
self.customer = customer
|
self.customer = customer
|
||||||
self.tanChallenge = tanChallenge
|
self.tanChallenge = tanChallenge
|
||||||
self.callback = callback
|
self.callback = callback
|
||||||
|
|
|
@ -5,7 +5,7 @@ import BankingUiSwift
|
||||||
|
|
||||||
class Mapper {
|
class Mapper {
|
||||||
|
|
||||||
func map(_ customer: PersistedCustomer) -> Customer {
|
func map(_ customer: PersistedCustomer) -> ICustomer {
|
||||||
let mapped = Customer(bankCode: map(customer.bankCode), customerId: map(customer.customerId), password: map(customer.password), finTsServerAddress: map(customer.finTsServerAddress), bankName: map(customer.bankName), bic: map(customer.bic), customerName: map(customer.customerName), userId: map(customer.userId), iconUrl: customer.iconUrl, accounts: [])
|
let mapped = Customer(bankCode: map(customer.bankCode), customerId: map(customer.customerId), password: map(customer.password), finTsServerAddress: map(customer.finTsServerAddress), bankName: map(customer.bankName), bic: map(customer.bic), customerName: map(customer.customerName), userId: map(customer.userId), iconUrl: customer.iconUrl, accounts: [])
|
||||||
|
|
||||||
mapped.userSetDisplayName = customer.userSetDisplayName
|
mapped.userSetDisplayName = customer.userSetDisplayName
|
||||||
|
@ -23,7 +23,7 @@ class Mapper {
|
||||||
return mapped
|
return mapped
|
||||||
}
|
}
|
||||||
|
|
||||||
func map(_ customer: Customer, _ context: NSManagedObjectContext) -> PersistedCustomer {
|
func map(_ customer: ICustomer, _ context: NSManagedObjectContext) -> PersistedCustomer {
|
||||||
let mapped = context.objectByID(customer.technicalId) ?? PersistedCustomer(context: context)
|
let mapped = context.objectByID(customer.technicalId) ?? PersistedCustomer(context: context)
|
||||||
|
|
||||||
mapped.bankCode = customer.bankCode
|
mapped.bankCode = customer.bankCode
|
||||||
|
@ -50,11 +50,11 @@ class Mapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func map(_ customer: Customer, _ accounts: [PersistedBankAccount]?) -> [BankAccount] {
|
func map(_ customer: ICustomer, _ accounts: [PersistedBankAccount]?) -> [IBankAccount] {
|
||||||
return accounts?.map( { map(customer, $0) } ) ?? []
|
return accounts?.map( { map(customer, $0) } ) ?? []
|
||||||
}
|
}
|
||||||
|
|
||||||
func map(_ customer: Customer, _ account: PersistedBankAccount) -> BankAccount {
|
func map(_ customer: ICustomer, _ account: PersistedBankAccount) -> IBankAccount {
|
||||||
let mapped = BankAccount(customer: customer, identifier: map(account.identifier), accountHolderName: map(account.accountHolderName), iban: account.iban, subAccountNumber: account.subAccountNumber, customerId: map(account.customerId), balance: map(account.balance), currency: map(account.currency), type: map(account.type), productName: account.productName, accountLimit: account.accountLimit, lastRetrievedTransactionsTimestamp: map(account.lastRetrievedTransactionsTimestamp), supportsRetrievingAccountTransactions: account.supportsRetrievingAccountTransactions, supportsRetrievingBalance: account.supportsRetrievingBalance, supportsTransferringMoney: account.supportsTransferringMoney, supportsInstantPaymentMoneyTransfer: account.supportsInstantPaymentMoneyTransfer, bookedTransactions: [], unbookedTransactions: [])
|
let mapped = BankAccount(customer: customer, identifier: map(account.identifier), accountHolderName: map(account.accountHolderName), iban: account.iban, subAccountNumber: account.subAccountNumber, customerId: map(account.customerId), balance: map(account.balance), currency: map(account.currency), type: map(account.type), productName: account.productName, accountLimit: account.accountLimit, lastRetrievedTransactionsTimestamp: map(account.lastRetrievedTransactionsTimestamp), supportsRetrievingAccountTransactions: account.supportsRetrievingAccountTransactions, supportsRetrievingBalance: account.supportsRetrievingBalance, supportsTransferringMoney: account.supportsTransferringMoney, supportsInstantPaymentMoneyTransfer: account.supportsInstantPaymentMoneyTransfer, bookedTransactions: [], unbookedTransactions: [])
|
||||||
|
|
||||||
mapped.haveAllTransactionsBeenFetched = account.haveAllTransactionsBeenFetched
|
mapped.haveAllTransactionsBeenFetched = account.haveAllTransactionsBeenFetched
|
||||||
|
@ -69,11 +69,11 @@ class Mapper {
|
||||||
return mapped
|
return mapped
|
||||||
}
|
}
|
||||||
|
|
||||||
func map(_ customer: PersistedCustomer, _ accounts: [BankAccount], _ context: NSManagedObjectContext) -> [PersistedBankAccount] {
|
func map(_ customer: PersistedCustomer, _ accounts: [IBankAccount], _ context: NSManagedObjectContext) -> [PersistedBankAccount] {
|
||||||
return accounts.map( { map(customer, $0, context) } )
|
return accounts.map( { map(customer, $0, context) } )
|
||||||
}
|
}
|
||||||
|
|
||||||
func map(_ customer: PersistedCustomer, _ account: BankAccount, _ context: NSManagedObjectContext) -> PersistedBankAccount {
|
func map(_ customer: PersistedCustomer, _ account: IBankAccount, _ context: NSManagedObjectContext) -> PersistedBankAccount {
|
||||||
let mapped = context.objectByID(account.technicalId) ?? PersistedBankAccount(context: context)
|
let mapped = context.objectByID(account.technicalId) ?? PersistedBankAccount(context: context)
|
||||||
|
|
||||||
mapped.customer = customer
|
mapped.customer = customer
|
||||||
|
@ -136,11 +136,11 @@ class Mapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func map(_ account: BankAccount, _ transactions: Set<PersistedAccountTransaction>?) -> [AccountTransaction] {
|
func map(_ account: IBankAccount, _ transactions: Set<PersistedAccountTransaction>?) -> [IAccountTransaction] {
|
||||||
return transactions?.map( {map(account, $0) } ) ?? []
|
return transactions?.map( {map(account, $0) } ) ?? []
|
||||||
}
|
}
|
||||||
|
|
||||||
func map(_ account: BankAccount, _ transaction: PersistedAccountTransaction) -> AccountTransaction {
|
func map(_ account: IBankAccount, _ transaction: PersistedAccountTransaction) -> IAccountTransaction {
|
||||||
let mapped = AccountTransaction(bankAccount: account, amount: map(transaction.amount), currency: map(transaction.currency), unparsedUsage: map(transaction.unparsedUsage), bookingDate: map(transaction.bookingDate), otherPartyName: transaction.otherPartyName, otherPartyBankCode: transaction.otherPartyBankCode, otherPartyAccountId: transaction.otherPartyAccountId, bookingText: transaction.bookingText, valueDate: map(transaction.valueDate), statementNumber: Int32(transaction.statementNumber), sequenceNumber: map(transaction.sequenceNumber), openingBalance: map(transaction.openingBalance), closingBalance: map(transaction.closingBalance), endToEndReference: transaction.endToEndReference, customerReference: transaction.customerReference, mandateReference: transaction.mandateReference, creditorIdentifier: transaction.creditorIdentifier, originatorsIdentificationCode: transaction.originatorsIdentificationCode, compensationAmount: transaction.compensationAmount, originalAmount: transaction.originalAmount, sepaUsage: transaction.sepaUsage, deviantOriginator: transaction.deviantOriginator, deviantRecipient: transaction.deviantRecipient, usageWithNoSpecialType: transaction.usageWithNoSpecialType, primaNotaNumber: transaction.primaNotaNumber, textKeySupplement: transaction.textKeySupplement, currencyType: transaction.currencyType, bookingKey: map(transaction.bookingKey), referenceForTheAccountOwner: map(transaction.referenceForTheAccountOwner), referenceOfTheAccountServicingInstitution: transaction.referenceOfTheAccountServicingInstitution, supplementaryDetails: transaction.supplementaryDetails, transactionReferenceNumber: map(transaction.transactionReferenceNumber), relatedReferenceNumber: transaction.relatedReferenceNumber)
|
let mapped = AccountTransaction(bankAccount: account, amount: map(transaction.amount), currency: map(transaction.currency), unparsedUsage: map(transaction.unparsedUsage), bookingDate: map(transaction.bookingDate), otherPartyName: transaction.otherPartyName, otherPartyBankCode: transaction.otherPartyBankCode, otherPartyAccountId: transaction.otherPartyAccountId, bookingText: transaction.bookingText, valueDate: map(transaction.valueDate), statementNumber: Int32(transaction.statementNumber), sequenceNumber: map(transaction.sequenceNumber), openingBalance: map(transaction.openingBalance), closingBalance: map(transaction.closingBalance), endToEndReference: transaction.endToEndReference, customerReference: transaction.customerReference, mandateReference: transaction.mandateReference, creditorIdentifier: transaction.creditorIdentifier, originatorsIdentificationCode: transaction.originatorsIdentificationCode, compensationAmount: transaction.compensationAmount, originalAmount: transaction.originalAmount, sepaUsage: transaction.sepaUsage, deviantOriginator: transaction.deviantOriginator, deviantRecipient: transaction.deviantRecipient, usageWithNoSpecialType: transaction.usageWithNoSpecialType, primaNotaNumber: transaction.primaNotaNumber, textKeySupplement: transaction.textKeySupplement, currencyType: transaction.currencyType, bookingKey: map(transaction.bookingKey), referenceForTheAccountOwner: map(transaction.referenceForTheAccountOwner), referenceOfTheAccountServicingInstitution: transaction.referenceOfTheAccountServicingInstitution, supplementaryDetails: transaction.supplementaryDetails, transactionReferenceNumber: map(transaction.transactionReferenceNumber), relatedReferenceNumber: transaction.relatedReferenceNumber)
|
||||||
|
|
||||||
mapped.technicalId = transaction.objectIDAsString
|
mapped.technicalId = transaction.objectIDAsString
|
||||||
|
@ -149,11 +149,11 @@ class Mapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func map(_ account: PersistedBankAccount, _ transactions: [AccountTransaction], _ context: NSManagedObjectContext) -> [PersistedAccountTransaction] {
|
func map(_ account: PersistedBankAccount, _ transactions: [IAccountTransaction], _ context: NSManagedObjectContext) -> [PersistedAccountTransaction] {
|
||||||
return transactions.map( {map(account, $0, context) } )
|
return transactions.map( {map(account, $0, context) } )
|
||||||
}
|
}
|
||||||
|
|
||||||
func map(_ account: PersistedBankAccount, _ transaction: AccountTransaction, _ context: NSManagedObjectContext) -> PersistedAccountTransaction {
|
func map(_ account: PersistedBankAccount, _ transaction: IAccountTransaction, _ context: NSManagedObjectContext) -> PersistedAccountTransaction {
|
||||||
let mapped = context.objectByID(transaction.technicalId) ?? PersistedAccountTransaction(context: context)
|
let mapped = context.objectByID(transaction.technicalId) ?? PersistedAccountTransaction(context: context)
|
||||||
|
|
||||||
mapped.account = account
|
mapped.account = account
|
||||||
|
|
|
@ -11,7 +11,7 @@ extension Message {
|
||||||
secondaryButton: .cancel())
|
secondaryButton: .cancel())
|
||||||
}
|
}
|
||||||
|
|
||||||
static func createAskUserToDeleteAccountMessage(_ bank: Customer, _ deleteAccount: @escaping (Customer) -> Void) -> Message {
|
static func createAskUserToDeleteAccountMessage(_ bank: ICustomer, _ deleteAccount: @escaping (ICustomer) -> Void) -> Message {
|
||||||
return Message(title: Text("Really delete account '\(bank.displayName)'?"),
|
return Message(title: Text("Really delete account '\(bank.displayName)'?"),
|
||||||
message: Text("All data for this account will be permanently deleted locally."),
|
message: Text("All data for this account will be permanently deleted locally."),
|
||||||
primaryButton: .destructive(Text("Delete"), action: { deleteAccount(bank) } ),
|
primaryButton: .destructive(Text("Delete"), action: { deleteAccount(bank) } ),
|
||||||
|
|
|
@ -9,7 +9,7 @@ class SwiftUiRouter : IRouter {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTanFromUserFromNonUiThread(customer: Customer, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: @escaping (EnterTanResult) -> Void) {
|
func getTanFromUserFromNonUiThread(customer: ICustomer, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: @escaping (EnterTanResult) -> Void) {
|
||||||
let enterTanState = EnterTanState(customer, tanChallenge, callback)
|
let enterTanState = EnterTanState(customer, tanChallenge, callback)
|
||||||
|
|
||||||
SceneDelegate.navigateToView(EnterTanDialog(enterTanState))
|
SceneDelegate.navigateToView(EnterTanDialog(enterTanState))
|
||||||
|
|
|
@ -9,7 +9,7 @@ struct AccountTransactionsDialog: View {
|
||||||
|
|
||||||
private let title: String
|
private let title: String
|
||||||
|
|
||||||
private let allTransactions: [AccountTransaction]
|
private let allTransactions: [IAccountTransaction]
|
||||||
|
|
||||||
private let balanceOfAllTransactions: CommonBigDecimal
|
private let balanceOfAllTransactions: CommonBigDecimal
|
||||||
|
|
||||||
|
@ -20,10 +20,10 @@ struct AccountTransactionsDialog: View {
|
||||||
|
|
||||||
@State private var showFetchAllTransactionsOverlay: Bool
|
@State private var showFetchAllTransactionsOverlay: Bool
|
||||||
|
|
||||||
@State private var accountsForWhichNotAllTransactionsHaveBeenFetched: [BankAccount]
|
@State private var accountsForWhichNotAllTransactionsHaveBeenFetched: [IBankAccount]
|
||||||
|
|
||||||
|
|
||||||
@State private var filteredTransactions: [AccountTransaction]
|
@State private var filteredTransactions: [IAccountTransaction]
|
||||||
|
|
||||||
@State private var balanceOfFilteredTransactions: CommonBigDecimal
|
@State private var balanceOfFilteredTransactions: CommonBigDecimal
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ struct AccountTransactionsDialog: View {
|
||||||
@Inject private var presenter: BankingPresenterSwift
|
@Inject private var presenter: BankingPresenterSwift
|
||||||
|
|
||||||
|
|
||||||
init(allBanks: [Customer]) {
|
init(allBanks: [ICustomer]) {
|
||||||
let allAccounts = allBanks.flatMap { $0.accounts }
|
let allAccounts = allBanks.flatMap { $0.accounts }
|
||||||
|
|
||||||
self.init("All accounts", allAccounts.flatMap { $0.bookedTransactions }, allBanks.sumBalances(), allAccounts.filter { $0.haveAllTransactionsBeenFetched == false })
|
self.init("All accounts", allAccounts.flatMap { $0.bookedTransactions }, allBanks.sumBalances(), allAccounts.filter { $0.haveAllTransactionsBeenFetched == false })
|
||||||
|
@ -53,19 +53,19 @@ struct AccountTransactionsDialog: View {
|
||||||
presenter.selectedAllBankAccounts()
|
presenter.selectedAllBankAccounts()
|
||||||
}
|
}
|
||||||
|
|
||||||
init(bank: Customer) {
|
init(bank: ICustomer) {
|
||||||
self.init(bank.displayName, bank.accounts.flatMap { $0.bookedTransactions }, bank.balance, bank.accounts.filter { $0.haveAllTransactionsBeenFetched == false })
|
self.init(bank.displayName, bank.accounts.flatMap { $0.bookedTransactions }, bank.balance, bank.accounts.filter { $0.haveAllTransactionsBeenFetched == false })
|
||||||
|
|
||||||
presenter.selectedAccount(customer: bank)
|
presenter.selectedAccount(customer: bank)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(account: BankAccount) {
|
init(account: IBankAccount) {
|
||||||
self.init(account.displayName, account.bookedTransactions, account.balance, account.haveAllTransactionsBeenFetched ? [] : [account])
|
self.init(account.displayName, account.bookedTransactions, account.balance, account.haveAllTransactionsBeenFetched ? [] : [account])
|
||||||
|
|
||||||
presenter.selectedBankAccount(bankAccount: account)
|
presenter.selectedBankAccount(bankAccount: account)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate init(_ title: String, _ transactions: [AccountTransaction], _ balance: CommonBigDecimal, _ accountsForWhichNotAllTransactionsHaveBeenFetched: [BankAccount] = []) {
|
fileprivate init(_ title: String, _ transactions: [IAccountTransaction], _ balance: CommonBigDecimal, _ accountsForWhichNotAllTransactionsHaveBeenFetched: [IBankAccount] = []) {
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
||||||
self.allTransactions = transactions
|
self.allTransactions = transactions
|
||||||
|
@ -74,7 +74,7 @@ struct AccountTransactionsDialog: View {
|
||||||
self.balanceOfAllTransactions = balance
|
self.balanceOfAllTransactions = balance
|
||||||
self._balanceOfFilteredTransactions = State(initialValue: balance)
|
self._balanceOfFilteredTransactions = State(initialValue: balance)
|
||||||
|
|
||||||
self.areMoreThanOneBanksTransactionsDisplayed = Set(allTransactions.compactMap { $0.bankAccount }.compactMap { $0.customer }).count > 1
|
self.areMoreThanOneBanksTransactionsDisplayed = Set(allTransactions.compactMap { $0.bankAccount }.compactMap { $0.customer as! Customer }).count > 1
|
||||||
|
|
||||||
_accountsForWhichNotAllTransactionsHaveBeenFetched = State(initialValue: accountsForWhichNotAllTransactionsHaveBeenFetched)
|
_accountsForWhichNotAllTransactionsHaveBeenFetched = State(initialValue: accountsForWhichNotAllTransactionsHaveBeenFetched)
|
||||||
_haveAllTransactionsBeenFetched = State(initialValue: accountsForWhichNotAllTransactionsHaveBeenFetched.isEmpty)
|
_haveAllTransactionsBeenFetched = State(initialValue: accountsForWhichNotAllTransactionsHaveBeenFetched.isEmpty)
|
||||||
|
@ -173,7 +173,7 @@ struct AccountTransactionsDialog: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func fetchAllTransactions(_ accounts: [BankAccount]) {
|
private func fetchAllTransactions(_ accounts: [IBankAccount]) {
|
||||||
accounts.forEach { account in
|
accounts.forEach { account in
|
||||||
presenter.fetchAllAccountTransactionsAsync(bankAccount: account, callback: self.handleGetAllTransactionsResult)
|
presenter.fetchAllAccountTransactionsAsync(bankAccount: account, callback: self.handleGetAllTransactionsResult)
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ struct AccountTransactionsDialog: View {
|
||||||
struct AccountTransactionsDialog_Previews: PreviewProvider {
|
struct AccountTransactionsDialog_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
AccountTransactionsDialog(previewBanks[0].displayName, [
|
AccountTransactionsDialog(previewBanks[0].displayName, [
|
||||||
AccountTransaction(bankAccount: previewBanks[0].accounts[0], amount: CommonBigDecimal(double: 1234.56), currency: "€", unparsedUsage: "Usage", bookingDate: CommonDate(year: 2020, month: 5, day: 7), otherPartyName: "Marieke Musterfrau", otherPartyBankCode: nil, otherPartyAccountId: nil, bookingText: "SEPA Ueberweisung", valueDate: CommonDate(year: 2020, month: 5, day: 7))
|
AccountTransaction(bankAccount: previewBanks[0].accounts[0] as! BankAccount, amount: CommonBigDecimal(double: 1234.56), currency: "€", unparsedUsage: "Usage", bookingDate: CommonDate(year: 2020, month: 5, day: 7), otherPartyName: "Marieke Musterfrau", otherPartyBankCode: nil, otherPartyAccountId: nil, bookingText: "SEPA Ueberweisung", valueDate: CommonDate(year: 2020, month: 5, day: 7))
|
||||||
],
|
],
|
||||||
CommonBigDecimal(double: 84.12))
|
CommonBigDecimal(double: 84.12))
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ struct AccountsDialog: View {
|
||||||
Form {
|
Form {
|
||||||
AllBanksListItem(banks: data.banks)
|
AllBanksListItem(banks: data.banks)
|
||||||
|
|
||||||
ForEach(data.banks.sortedByDisplayIndex()) { bank in
|
ForEach(data.banks.sortedByDisplayIndex(), id: \.technicalId) { bank in
|
||||||
BankListItem(bank: bank)
|
BankListItem(bank: bank)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ struct AddAccountDialog: View {
|
||||||
isTryingToAddAccount = true
|
isTryingToAddAccount = true
|
||||||
UIApplication.hideKeyboard()
|
UIApplication.hideKeyboard()
|
||||||
|
|
||||||
presenter.addAccountAsync(bankInfo: bank, customerId: customerId, pin: password) { (response) in
|
presenter.addAccountAsync(bankInfo: bank, customerId: customerId, password: password) { (response) in
|
||||||
self.handleAddAccountResponse(response)
|
self.handleAddAccountResponse(response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ struct BankAccountSettingsDialog: View {
|
||||||
@Inject private var presenter: BankingPresenterSwift
|
@Inject private var presenter: BankingPresenterSwift
|
||||||
|
|
||||||
|
|
||||||
private let account: BankAccount
|
private let account: IBankAccount
|
||||||
|
|
||||||
@State private var displayName: String
|
@State private var displayName: String
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ struct BankAccountSettingsDialog: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
init(_ account: BankAccount) {
|
init(_ account: IBankAccount) {
|
||||||
self.account = account
|
self.account = account
|
||||||
|
|
||||||
_displayName = State(initialValue: account.displayName)
|
_displayName = State(initialValue: account.displayName)
|
||||||
|
@ -79,8 +79,8 @@ struct BankAccountSettingsDialog: View {
|
||||||
private func donePressed() {
|
private func donePressed() {
|
||||||
if hasUnsavedData {
|
if hasUnsavedData {
|
||||||
account.userSetDisplayName = displayName
|
account.userSetDisplayName = displayName
|
||||||
|
|
||||||
presenter.accountUpdated(account: account.customer)
|
presenter.accountUpdated(account: account)
|
||||||
}
|
}
|
||||||
|
|
||||||
closeDialog()
|
closeDialog()
|
||||||
|
|
|
@ -10,7 +10,7 @@ struct BankSettingsDialog: View {
|
||||||
@Inject private var presenter: BankingPresenterSwift
|
@Inject private var presenter: BankingPresenterSwift
|
||||||
|
|
||||||
|
|
||||||
private let bank: Customer
|
private let bank: ICustomer
|
||||||
|
|
||||||
@State private var displayName: String
|
@State private var displayName: String
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ struct BankSettingsDialog: View {
|
||||||
|
|
||||||
@State private var selectedTanProcedure: TanProcedure?
|
@State private var selectedTanProcedure: TanProcedure?
|
||||||
|
|
||||||
@State private var accountsSorted: [BankAccount]
|
@State private var accountsSorted: [IBankAccount]
|
||||||
|
|
||||||
@State private var askUserToDeleteAccountOrSaveChangesMessage: Message? = nil
|
@State private var askUserToDeleteAccountOrSaveChangesMessage: Message? = nil
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ struct BankSettingsDialog: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
init(_ bank: Customer) {
|
init(_ bank: ICustomer) {
|
||||||
self.bank = bank
|
self.bank = bank
|
||||||
|
|
||||||
_displayName = State(initialValue: bank.displayName)
|
_displayName = State(initialValue: bank.displayName)
|
||||||
|
@ -75,7 +75,7 @@ struct BankSettingsDialog: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
Section(header: SectionHeaderWithRightAlignedEditButton("Accounts")) {
|
Section(header: SectionHeaderWithRightAlignedEditButton("Accounts")) {
|
||||||
ForEach(accountsSorted) { account in
|
ForEach(accountsSorted, id: \.technicalId) { account in
|
||||||
NavigationLink(destination: LazyView(BankAccountSettingsDialog(account))) {
|
NavigationLink(destination: LazyView(BankAccountSettingsDialog(account))) {
|
||||||
Text(account.displayName)
|
Text(account.displayName)
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ struct BankSettingsDialog: View {
|
||||||
func reorderAccounts(from source: IndexSet, to destination: Int) {
|
func reorderAccounts(from source: IndexSet, to destination: Int) {
|
||||||
accountsSorted = accountsSorted.reorder(from: source, to: destination)
|
accountsSorted = accountsSorted.reorder(from: source, to: destination)
|
||||||
|
|
||||||
presenter.accountUpdated(account: bank)
|
presenter.accountDisplayIndexUpdated(account: bank)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ struct BankSettingsDialog: View {
|
||||||
self.askUserToDeleteAccountOrSaveChangesMessage = Message.createAskUserToDeleteAccountMessage(bank, self.deleteAccount)
|
self.askUserToDeleteAccountOrSaveChangesMessage = Message.createAskUserToDeleteAccountMessage(bank, self.deleteAccount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteAccount(bank: Customer) {
|
func deleteAccount(bank: ICustomer) {
|
||||||
presenter.deleteAccount(customer: bank)
|
presenter.deleteAccount(customer: bank)
|
||||||
|
|
||||||
closeDialog()
|
closeDialog()
|
||||||
|
@ -135,7 +135,7 @@ struct BankSettingsDialog: View {
|
||||||
|
|
||||||
bank.selectedTanProcedure = selectedTanProcedure
|
bank.selectedTanProcedure = selectedTanProcedure
|
||||||
|
|
||||||
presenter.accountUpdated(account: bank)
|
presenter.accountUpdated(bank: bank)
|
||||||
}
|
}
|
||||||
|
|
||||||
closeDialog()
|
closeDialog()
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct EnterTanDialog: View {
|
||||||
|
|
||||||
private var tanChallenge: TanChallenge
|
private var tanChallenge: TanChallenge
|
||||||
|
|
||||||
private var customer: Customer
|
private var customer: ICustomer
|
||||||
|
|
||||||
private var customersTanMedia: [TanMedium] = []
|
private var customersTanMedia: [TanMedium] = []
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ struct SettingsDialog: View {
|
||||||
Form {
|
Form {
|
||||||
Section(header: SectionHeaderWithRightAlignedEditButton("Bank Credentials", isEditButtonEnabled: data.hasAtLeastOneAccountBeenAdded),
|
Section(header: SectionHeaderWithRightAlignedEditButton("Bank Credentials", isEditButtonEnabled: data.hasAtLeastOneAccountBeenAdded),
|
||||||
footer: footer) {
|
footer: footer) {
|
||||||
ForEach(data.banksSorted) { bank in
|
ForEach(data.banksSorted, id: \.technicalId) { bank in
|
||||||
NavigationLink(destination: LazyView(BankSettingsDialog(bank))) {
|
NavigationLink(destination: LazyView(BankSettingsDialog(bank))) {
|
||||||
IconedTitleView(bank)
|
IconedTitleView(bank)
|
||||||
}
|
}
|
||||||
|
@ -68,11 +68,11 @@ struct SettingsDialog: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func askUserToDeleteAccount(_ bankToDelete: Customer) {
|
func askUserToDeleteAccount(_ bankToDelete: ICustomer) {
|
||||||
self.askToDeleteAccountMessage = Message.createAskUserToDeleteAccountMessage(bankToDelete, self.deleteAccountWithSecurityChecks)
|
self.askToDeleteAccountMessage = Message.createAskUserToDeleteAccountMessage(bankToDelete, self.deleteAccountWithSecurityChecks)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteAccountWithSecurityChecks(_ bankToDelete: Customer) {
|
func deleteAccountWithSecurityChecks(_ bankToDelete: ICustomer) {
|
||||||
// don't know why but when deleting last bank application crashes if we don't delete bank async
|
// don't know why but when deleting last bank application crashes if we don't delete bank async
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
if self.presenter.customers.count == 1 {
|
if self.presenter.customers.count == 1 {
|
||||||
|
@ -88,7 +88,7 @@ struct SettingsDialog: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func deleteAccount(_ bankToDelete: Customer) {
|
private func deleteAccount(_ bankToDelete: ICustomer) {
|
||||||
self.presenter.deleteAccount(customer: bankToDelete)
|
self.presenter.deleteAccount(customer: bankToDelete)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|