Extracted interfaces for UI model classes Customer, BankAccount and AccountTransaction. So entities can implement these interfaces directly, there's no need for mapping anymore

This commit is contained in:
dankito 2020-09-11 12:25:05 +02:00
parent ddf2336ed5
commit 07941380ec
116 changed files with 1631 additions and 868 deletions

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -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

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -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

View File

@ -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

View File

@ -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

88
docs/res/icons/new.pdf Normal file
View File

@ -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

View File

@ -14,9 +14,7 @@ import net.dankito.banking.LuceneConfig.Companion.OtherPartyAccountIdFieldName
import net.dankito.banking.LuceneConfig.Companion.OtherPartyBankCodeFieldName
import net.dankito.banking.LuceneConfig.Companion.OtherPartyNameFieldName
import net.dankito.banking.LuceneConfig.Companion.UsageFieldName
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.ui.model.*
import net.dankito.banking.util.ISerializer
import net.dankito.banking.util.JacksonJsonSerializer
import net.dankito.utils.lucene.index.DocumentsWriter
@ -47,7 +45,7 @@ open class LuceneBankingPersistence(
protected val fields = FieldBuilder()
override fun saveOrUpdateAccountTransactions(bankAccount: BankAccount, transactions: List<AccountTransaction>) {
override fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List<IAccountTransaction>) {
val writer = getWriter()
transactions.forEach { transaction ->
@ -60,7 +58,7 @@ open class LuceneBankingPersistence(
writer.flushChangesToDisk()
}
protected open fun createFieldsForAccountTransaction(bankAccount: BankAccount, transaction: AccountTransaction): List<IndexableField?> {
protected open fun createFieldsForAccountTransaction(bankAccount: TypedBankAccount, transaction: IAccountTransaction): List<IndexableField?> {
return listOf(
fields.keywordField(BankAccountIdFieldName, bankAccount.technicalId),
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 {
deleteAccountTransactions(customer.accounts)
} catch (e: Exception) {
@ -89,7 +87,7 @@ open class LuceneBankingPersistence(
super.deleteAccount(customer, allCustomers)
}
protected open fun deleteAccountTransactions(bankAccounts: List<BankAccount>) {
protected open fun deleteAccountTransactions(bankAccounts: List<TypedBankAccount>) {
val writer = getWriter()
val bankAccountIds = bankAccounts.map { it.technicalId }

View File

@ -5,12 +5,14 @@ import net.dankito.banking.ui.model.Customer
import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.BankAccount
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.junit.After
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.mock
import java.io.File
import java.math.BigDecimal
import java.text.SimpleDateFormat
import java.util.*
@ -211,7 +213,7 @@ class LuceneRemitteeSearcherTest {
otherPartyName: String = randomString(), otherPartyBankCode: String = randomString(),
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 {

View File

@ -17,10 +17,6 @@ compileTestKotlin {
dependencies {
implementation project(':BankingUiCommon')
implementation("org.mapstruct:mapstruct:$mapStructVersion")
kapt("org.mapstruct:mapstruct-processor:$mapStructVersion")
testImplementation "junit:junit:$junitVersion"

View File

@ -1,13 +1,9 @@
package net.dankito.banking.persistence
import net.dankito.banking.persistence.mapper.CustomerConverter
import net.dankito.banking.persistence.model.CustomerEntity
import net.dankito.banking.ui.model.*
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 org.mapstruct.factory.Mappers
import java.io.FileOutputStream
import java.net.URL
@ -17,39 +13,32 @@ open class BankingPersistenceJson(
protected val serializer: ISerializer
) : IBankingPersistence {
protected val mapper = Mappers.getMapper(CustomerConverter::class.java)
init {
jsonFile.absoluteFile.parentFile.mkdirs()
}
override fun saveOrUpdateAccount(customer: Customer, allCustomers: List<Customer>) {
override fun saveOrUpdateAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
saveAllCustomers(allCustomers)
}
override fun deleteAccount(customer: Customer, allCustomers: List<Customer>) {
override fun deleteAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
saveAllCustomers(allCustomers)
}
override fun readPersistedAccounts(): List<Customer> {
val deserializedCustomers = serializer.deserializeListOr(jsonFile, CustomerEntity::class)
return mapper.mapCustomerEntities(deserializedCustomers)
override fun readPersistedAccounts(): List<TypedCustomer> {
return serializer.deserializeListOr(jsonFile, CustomerEntity::class).map { it as TypedCustomer }
}
override fun saveOrUpdateAccountTransactions(bankAccount: BankAccount, transactions: List<AccountTransaction>) {
override fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List<IAccountTransaction>) {
// done when called saveOrUpdateAccount()
// TODO: or also call saveAllCustomers()?
}
protected open fun saveAllCustomers(allCustomers: List<Customer>) {
val mappedCustomers = mapper.mapCustomers(allCustomers)
serializer.serializeObject(mappedCustomers, jsonFile)
protected open fun saveAllCustomers(allCustomers: List<TypedCustomer>) {
serializer.serializeObject(allCustomers, jsonFile)
}

View File

@ -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>
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -2,57 +2,63 @@ package net.dankito.banking.persistence.model
import com.fasterxml.jackson.annotation.JsonIdentityInfo
import com.fasterxml.jackson.annotation.ObjectIdGenerators
import net.dankito.banking.ui.model.IAccountTransaction
import net.dankito.utils.multiplatform.BigDecimal
import net.dankito.utils.multiplatform.Date
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
open class AccountTransactionEntity(
open var bankAccount: BankAccountEntity,
open var amount: BigDecimal,
open var currency: String,
open var unparsedUsage: String,
open var bookingDate: Date,
open var otherPartyName: String?,
open var otherPartyBankCode: String?,
open var otherPartyAccountId: String?,
open var bookingText: String?,
open var valueDate: Date,
open var statementNumber: Int,
open var sequenceNumber: Int?,
open var openingBalance: BigDecimal?,
open var closingBalance: BigDecimal?,
override var bankAccount: BankAccountEntity,
override var amount: BigDecimal,
override var currency: String,
override var unparsedUsage: String,
override var bookingDate: Date,
override var otherPartyName: String?,
override var otherPartyBankCode: String?,
override var otherPartyAccountId: String?,
override var bookingText: String?,
override var valueDate: Date,
override var statementNumber: Int,
override var sequenceNumber: Int?,
override var openingBalance: BigDecimal?,
override var closingBalance: BigDecimal?,
open var endToEndReference: String?,
open var customerReference: String?,
open var mandateReference: String?,
open var creditorIdentifier: String?,
open var originatorsIdentificationCode: String?,
open var compensationAmount: String?,
open var originalAmount: String?,
open var sepaUsage: String?,
open var deviantOriginator: String?,
open var deviantRecipient: String?,
open var usageWithNoSpecialType: String?,
open var primaNotaNumber: String?,
open var textKeySupplement: String?,
override var endToEndReference: String?,
override var customerReference: String?,
override var mandateReference: String?,
override var creditorIdentifier: String?,
override var originatorsIdentificationCode: String?,
override var compensationAmount: String?,
override var originalAmount: String?,
override var sepaUsage: String?,
override var deviantOriginator: String?,
override var deviantRecipient: String?,
override var usageWithNoSpecialType: String?,
override var primaNotaNumber: String?,
override var textKeySupplement: String?,
open var currencyType: String?,
open var bookingKey: String,
open var referenceForTheAccountOwner: String,
open var referenceOfTheAccountServicingInstitution: String?,
open var supplementaryDetails: String?,
override var currencyType: String?,
override var bookingKey: String,
override var referenceForTheAccountOwner: String,
override var referenceOfTheAccountServicingInstitution: String?,
override var supplementaryDetails: String?,
open var transactionReferenceNumber: String,
open var relatedReferenceNumber: String?,
var id: String = UUID.random().toString()
) {
override var transactionReferenceNumber: String,
override var relatedReferenceNumber: String?,
override var technicalId: String = UUID.random()
) : IAccountTransaction {
// for object deserializers
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,
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)
}

View File

@ -2,37 +2,39 @@ package net.dankito.banking.persistence.model
import com.fasterxml.jackson.annotation.JsonIdentityInfo
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.Date
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)
open class BankAccountEntity(
open var customer: CustomerEntity,
open var identifier: String,
open var accountHolderName: String,
open var iban: String?,
open var subAccountNumber: String?,
open var customerId: String,
open var balance: BigDecimal = BigDecimal.Zero,
open var currency: String = "EUR",
open var type: BankAccountType = BankAccountType.Girokonto,
open var productName: String? = null,
open var accountLimit: String? = null,
open var lastRetrievedTransactionsTimestamp: Date? = null,
open var supportsRetrievingAccountTransactions: Boolean = false,
open var supportsRetrievingBalance: Boolean = false,
open var supportsTransferringMoney: Boolean = false,
open var supportsInstantPaymentMoneyTransfer: Boolean = false,
open var bookedTransactions: List<AccountTransactionEntity> = listOf(),
open var unbookedTransactions: List<Any> = listOf(),
open var id: String = UUID.random().toString(),
open var userSetDisplayName: String? = null
override var customer: CustomerEntity,
override var identifier: String,
override var accountHolderName: String,
override var iban: String?,
override var subAccountNumber: String?,
override var customerId: String,
override var balance: BigDecimal = BigDecimal.Zero,
override var currency: String = "EUR",
override var type: BankAccountType = BankAccountType.Girokonto,
override var productName: String? = null,
override var accountLimit: String? = null,
override var lastRetrievedTransactionsTimestamp: Date? = null,
override var supportsRetrievingAccountTransactions: Boolean = false,
override var supportsRetrievingBalance: Boolean = false,
override var supportsTransferringMoney: Boolean = false,
override var supportsInstantPaymentMoneyTransfer: Boolean = false,
override var bookedTransactions: List<AccountTransactionEntity> = listOf(),
override var unbookedTransactions: List<Any> = listOf(),
override var technicalId: String = UUID.random(),
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

View File

@ -1,30 +1,32 @@
package net.dankito.banking.persistence.model
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.TanProcedure
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)
open class CustomerEntity(
var bankCode: String,
var customerId: String,
var password: String,
var finTsServerAddress: String,
var bankName: String,
var bic: String,
var customerName: String,
var userId: String = customerId,
var iconUrl: String? = null,
var accounts: List<BankAccountEntity> = listOf(),
var supportedTanProcedures: List<TanProcedure> = listOf(),
var selectedTanProcedure: TanProcedure? = null,
var tanMedia: List<TanMedium> = listOf(),
var id: String = UUID.randomUUID().toString(),
var userSetDisplayName: String? = null
) {
override var bankCode: String,
override var customerId: String,
override var password: String,
override var finTsServerAddress: String,
override var bankName: String,
override var bic: String,
override var customerName: String,
override var userId: String = customerId,
override var iconUrl: String? = null,
override var accounts: List<BankAccountEntity> = listOf(),
override var supportedTanProcedures: List<TanProcedure> = listOf(),
override var selectedTanProcedure: TanProcedure? = null,
override var tanMedia: List<TanMedium> = listOf(),
override var technicalId: String = UUID.randomUUID().toString(),
override var userSetDisplayName: String? = null,
override var displayIndex: Int = 0
) : ICustomer<BankAccountEntity, AccountTransactionEntity> {
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers

View File

@ -1,13 +1,9 @@
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.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 net.dankito.banking.ui.model.*
import net.dankito.banking.util.JacksonJsonSerializer
import net.dankito.utils.multiplatform.BigDecimal
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.junit.Assert
import org.junit.Test
import org.mapstruct.factory.Mappers
import kotlin.random.Random
@ -72,7 +67,7 @@ class BankingPersistenceJsonTest {
// when
underTest.saveOrUpdateAccount(customers.first(), customers)
underTest.saveOrUpdateAccount(customers.first() as TypedCustomer, customers.map { it as TypedCustomer })
// then
@ -89,13 +84,13 @@ class BankingPersistenceJsonTest {
// when
underTest.saveOrUpdateAccount(customer, listOf(customer))
underTest.saveOrUpdateAccount(customer as TypedCustomer, listOf(customer).map { it as TypedCustomer })
// then
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(3)
)
val serializableCustomers = Mappers.getMapper(CustomerConverter::class.java).mapCustomers(customers, CycleAvoidingMappingContext())
serializer.serializeObject(serializableCustomers, file)
serializer.serializeObject(customers, file)
// when
@ -117,19 +111,19 @@ class BankingPersistenceJsonTest {
// then
assertCustomersEqual(serializableCustomers, result)
assertCustomersEqual(customers, result as List<CustomerEntity>)
}
private fun createCustomer(countBankAccounts: Int = 0, customerId: String = CustomerId): Customer {
val result = Customer(BankCode, customerId, Password, FinTsServerAddress, BankName, Bic, CustomerName, UserId, IconUrl)
private fun createCustomer(countBankAccounts: Int = 0, customerId: String = CustomerId): CustomerEntity {
val result = CustomerEntity(BankCode, customerId, Password, FinTsServerAddress, BankName, Bic, CustomerName, UserId, IconUrl)
result.accounts = createBankAccounts(countBankAccounts, 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())
return IntRange(1, count).map { accountIndex ->
@ -137,8 +131,8 @@ class BankingPersistenceJsonTest {
}
}
private fun createBankAccount(productName: String, customer: Customer, countTransactions: Int = 0): BankAccount {
val result = BankAccount(customer, customer.customerId, "AccountHolder", "DE00" + customer.bankCode + customer.customerId, null,
private fun createBankAccount(productName: String, customer: CustomerEntity, countTransactions: Int = 0): BankAccountEntity {
val result = BankAccountEntity(customer, customer.customerId, "AccountHolder", "DE00" + customer.bankCode + customer.customerId, null,
customer.customerId, BigDecimal(84.25), productName = productName)
result.bookedTransactions = createAccountTransactions(countTransactions, result)
@ -146,14 +140,14 @@ class BankingPersistenceJsonTest {
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 ->
createAccountTransaction(transactionIndex, account)
}
}
private fun createAccountTransaction(transactionIndex: Int, account: BankAccount): AccountTransaction {
return AccountTransaction(account, "OtherParty_$transactionIndex", "Usage_$transactionIndex", BigDecimal(transactionIndex.toDouble()), createDate(), null)
private fun createAccountTransaction(transactionIndex: Int, account: BankAccountEntity): AccountTransactionEntity {
return AccountTransactionEntity(account, "OtherParty_$transactionIndex", "Usage_$transactionIndex", BigDecimal(transactionIndex.toDouble()), createDate(), null)
}
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)
deserializedCustomers.forEach { deserializedCustomer ->
val customer = customers.firstOrNull { it.technicalId == deserializedCustomer.id }
val customer = customers.firstOrNull { it.technicalId == deserializedCustomer.technicalId }
if (customer == null) {
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.customerId).isEqualTo(customer.customerId)
assertThat(deserializedCustomer.password).isEqualTo(customer.password)
@ -191,11 +185,11 @@ class BankingPersistenceJsonTest {
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)
deserializedAccounts.forEach { deserializedAccount ->
val account = accounts.firstOrNull { it.technicalId == deserializedAccount.id }
val account = accounts.firstOrNull { it.technicalId == deserializedAccount.technicalId }
if (account == null) {
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
assertThat(deserializedAccount.customer.id).isEqualTo(account.customer.technicalId)
assertThat(deserializedAccount.customer.technicalId).isEqualTo(account.customer.technicalId)
assertThat(deserializedAccount.identifier).isEqualTo(account.identifier)
assertThat(deserializedAccount.iban).isEqualTo(account.iban)
@ -219,11 +213,11 @@ class BankingPersistenceJsonTest {
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)
deserializedTransactions.forEach { deserializedTransaction ->
val transaction = transactions.firstOrNull { it.technicalId == deserializedTransaction.id }
val transaction = transactions.firstOrNull { it.technicalId == deserializedTransaction.technicalId }
if (transaction == null) {
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
assertThat(deserializedTransaction.bankAccount.id).isEqualTo(transaction.bankAccount.technicalId)
assertThat(deserializedTransaction.bankAccount.technicalId).isEqualTo(transaction.bankAccount.technicalId)
assertThat(deserializedTransaction.otherPartyName).isEqualTo(transaction.otherPartyName)
assertThat(deserializedTransaction.unparsedUsage).isEqualTo(transaction.unparsedUsage)

View File

@ -3,7 +3,7 @@ package net.dankito.banking.ui.android
import net.dankito.banking.ui.android.util.CurrentActivityTracker
import net.dankito.banking.ui.IRouter
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.tan.EnterTanGeneratorAtcResult
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 ->
activity.runOnUiThread {
EnterTanDialog().show(customer, tanChallenge, activity, false) { result ->

View File

@ -6,7 +6,7 @@ import android.view.View
import net.dankito.banking.ui.android.R
import net.dankito.banking.ui.android.adapter.viewholder.AccountTransactionViewHolder
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.utils.android.extensions.asActivity
import net.dankito.utils.android.ui.adapter.ListRecyclerAdapter
@ -14,14 +14,14 @@ import java.text.DateFormat
open class AccountTransactionAdapter(protected val presenter: BankingPresenter)
: ListRecyclerAdapter<AccountTransaction, AccountTransactionViewHolder>() {
: ListRecyclerAdapter<IAccountTransaction, AccountTransactionViewHolder>() {
companion object {
val ValueDateFormat = DateFormat.getDateInstance(DateFormat.SHORT)
}
var selectedTransaction: AccountTransaction? = null
var selectedTransaction: IAccountTransaction? = null
override fun getListItemLayoutId() = R.layout.list_item_account_transaction
@ -34,7 +34,7 @@ open class AccountTransactionAdapter(protected val presenter: BankingPresenter)
return viewHolder
}
override fun bindItemToView(viewHolder: AccountTransactionViewHolder, item: AccountTransaction) {
override fun bindItemToView(viewHolder: AccountTransactionViewHolder, item: IAccountTransaction) {
viewHolder.txtvwDate.text = ValueDateFormat.format(item.valueDate)
val label = if (item.showOtherPartyName) item.otherPartyName else item.bookingText

View File

@ -8,11 +8,11 @@ import android.view.ViewGroup
import android.widget.ImageView
import kotlinx.android.synthetic.main.list_item_bank_account.view.*
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
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? {
@ -30,7 +30,7 @@ open class BankAccountsAdapter(bankAccounts: List<BankAccount>) : ListAdapter<Ba
return view
}
protected open fun setIcon(bankAccount: BankAccount, imgBankIcon: ImageView) {
protected open fun setIcon(bankAccount: TypedBankAccount, imgBankIcon: ImageView) {
try {
val iconUrl = bankAccount.customer.iconUrl
imgBankIcon.visibility = if (iconUrl == null) View.GONE else View.VISIBLE

View File

@ -17,12 +17,11 @@ import net.dankito.banking.ui.IRouter
import net.dankito.banking.ui.presenter.BankingPresenter
import net.dankito.banking.bankfinder.IBankFinder
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.banking.util.*
import net.dankito.banking.util.extraction.IInvoiceDataExtractor
import net.dankito.banking.util.extraction.ITextExtractorRegistry
import net.dankito.banking.util.extraction.JavaInvoiceDataExtractor
import net.dankito.banking.util.extraction.JavaTextExtractorRegistry
import net.dankito.banking.util.extraction.*
import net.dankito.text.extraction.TextExtractorRegistry
import net.dankito.text.extraction.pdf.PdfBoxAndroidPdfTextExtractor
import net.dankito.text.extraction.pdf.iText2PdfTextExtractor
@ -91,9 +90,9 @@ class BankingModule(private val applicationContext: Context) {
@Named(DataFolderKey) dataFolder: File,
persister: IBankingPersistence, remitteeSearcher: IRemitteeSearcher, bankIconFinder: IBankIconFinder,
textExtractorRegistry: ITextExtractorRegistry, router: IRouter, invoiceDataExtractor: IInvoiceDataExtractor,
serializer: ISerializer, asyncRunner: IAsyncRunner) : BankingPresenter {
return BankingPresenter(bankingClientCreator, bankFinder, dataFolder, persister,
router, remitteeSearcher, bankIconFinder, textExtractorRegistry, invoiceDataExtractor, serializer, asyncRunner)
modelCreator: IModelCreator, serializer: ISerializer, asyncRunner: IAsyncRunner) : BankingPresenter {
return BankingPresenter(bankingClientCreator, bankFinder, dataFolder, persister, router, modelCreator,
remitteeSearcher, bankIconFinder, textExtractorRegistry, invoiceDataExtractor, serializer, asyncRunner)
}
@Provides
@ -110,8 +109,8 @@ class BankingModule(private val applicationContext: Context) {
@Provides
@Singleton
fun provideBankingClientCreator(serializer: ISerializer) : IBankingClientCreator {
return fints4kBankingClientCreator(serializer)
fun provideBankingClientCreator(modelCreator: IModelCreator, serializer: ISerializer) : IBankingClientCreator {
return fints4kBankingClientCreator(modelCreator, serializer)
}
@Provides
@ -151,7 +150,7 @@ class BankingModule(private val applicationContext: Context) {
@Provides
@Singleton
fun provideInvoiceDataExtractor() : IInvoiceDataExtractor {
return JavaInvoiceDataExtractor()
return NoOpInvoiceDataExtractor()
}
@ -167,6 +166,12 @@ class BankingModule(private val applicationContext: Context) {
return JacksonJsonSerializer()
}
@Provides
@Singleton
fun provideModelCreator() : IModelCreator {
return EntitiesModelCreator()
}
@Provides
@Singleton
fun provideAsyncRunner() : IAsyncRunner {

View File

@ -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.di.BankingComponent
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.tan.*
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
@ -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) {
this.customer = customer

View File

@ -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.StandardTextWatcher
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.responses.BankingClientResponse
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

View File

@ -20,7 +20,7 @@ import com.mikepenz.materialdrawer.util.removeItemByPosition
import com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView
import net.dankito.banking.ui.android.R
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 org.slf4j.LoggerFactory
@ -139,7 +139,7 @@ open class DrawerView(
}.flatten()
}
private fun createAccountDrawerItem(customer: Customer): IDrawerItem<*> {
private fun createAccountDrawerItem(customer: TypedCustomer): IDrawerItem<*> {
val accountItem = AccountDrawerItem()
.withName(customer.displayName)
@ -160,7 +160,7 @@ open class DrawerView(
return accountItem
}
private fun createBankAccountsDrawerItems(customer: Customer): List<IDrawerItem<*>> {
private fun createBankAccountsDrawerItems(customer: TypedCustomer): List<IDrawerItem<*>> {
return customer.accounts.map { bankAccount ->
SecondaryDrawerItem()
.withName(bankAccount.displayName)
@ -176,13 +176,13 @@ open class DrawerView(
return false
}
private fun closeDrawerAndEditAccount(customer: Customer) {
private fun closeDrawerAndEditAccount(customer: TypedCustomer) {
closeDrawer()
editAccount(customer)
}
private fun editAccount(customer: Customer) {
private fun editAccount(customer: TypedCustomer) {
// TODO: implement editing account (e.g. displayed name etc.)
AlertDialog.Builder(activity)

View File

@ -11,6 +11,7 @@ import net.dankito.banking.ui.presenter.BankingPresenter
import net.dankito.banking.util.BankIconFinder
import net.dankito.banking.bankfinder.LuceneBankFinder
import net.dankito.banking.persistence.LuceneBankingPersistence
import net.dankito.banking.persistence.mapper.EntitiesModelCreator
import net.dankito.banking.search.LuceneRemitteeSearcher
import net.dankito.banking.util.JacksonJsonSerializer
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 modelCreator = EntitiesModelCreator()
private val serializer = JacksonJsonSerializer()
private val tesseractTextExtractor = Tesseract4CommandlineImageTextExtractor(TesseractConfig(listOf(OcrLanguage.English, OcrLanguage.German)))
@ -42,11 +45,11 @@ class MainWindow : View(messages["application.title"]) {
tesseractTextExtractor, TikaTextExtractor()
)))
private val presenter = BankingPresenter(fints4kBankingClientCreator(serializer),
private val presenter = BankingPresenter(fints4kBankingClientCreator(modelCreator, serializer),
LuceneBankFinder(indexFolder), dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder),
RouterJavaFx(), LuceneRemitteeSearcher(indexFolder), BankIconFinder(), textExtractorRegistry)
RouterJavaFx(), modelCreator, LuceneRemitteeSearcher(indexFolder), BankIconFinder(), textExtractorRegistry)
// private val presenter = BankingPresenter(hbci4jBankingClientCreator(), LuceneBankFinder(indexFolder),
// dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder), RouterJavaFx(), LuceneRemitteeSearcher(indexFolder),
// dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder), RouterJavaFx(), modelCreator, LuceneRemitteeSearcher(indexFolder),
// BankIconFinder(), textExtractorRegistry)

View File

@ -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.cashtransfer.TransferMoneyDialog
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.tan.EnterTanGeneratorAtcResult
import net.dankito.banking.ui.model.tan.EnterTanResult
@ -22,7 +22,7 @@ open class RouterJavaFx : IRouter {
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 {
EnterTanDialog(customer, tanChallenge, presenter) { result ->
callback(result)

View File

@ -141,7 +141,7 @@ open class AccountTransactionsControlView(
protected open fun updateAccountTransactions(processingIndicatorButton: ProcessingIndicatorButton) {
// TODO: or only update transactions of selected accounts?
presenter.updateAccountsTransactionsAsync { transactions ->
presenter.updateAccountsTransactionsAsync {
runLater {
processingIndicatorButton.resetIsProcessing()
}

View File

@ -11,7 +11,7 @@ import javafx.scene.control.TableView
import javafx.scene.layout.Priority
import javafx.scene.paint.Color
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.utils.javafx.ui.extensions.ensureOnlyUsesSpaceIfVisible
import tornadofx.*
@ -21,8 +21,8 @@ import java.text.DateFormat
open class AccountTransactionsTable @JvmOverloads constructor(
protected val presenter: BankingPresenter,
transactions: ObservableList<AccountTransaction> = FXCollections.emptyObservableList<AccountTransaction>()
) : TableView<AccountTransaction>(transactions) {
transactions: ObservableList<IAccountTransaction> = FXCollections.emptyObservableList()
) : TableView<IAccountTransaction>(transactions) {
companion object {
@ -38,7 +38,7 @@ open class AccountTransactionsTable @JvmOverloads constructor(
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
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 {
contentDisplay = ContentDisplay.GRAPHIC_ONLY
@ -80,8 +80,8 @@ open class AccountTransactionsTable @JvmOverloads constructor(
}
}
cellValueFactory = Callback { object : ObjectBinding<AccountTransaction>() {
override fun computeValue(): AccountTransaction {
cellValueFactory = Callback { object : ObjectBinding<IAccountTransaction>() {
override fun computeValue(): IAccountTransaction {
return it.value
}
@ -90,7 +90,7 @@ open class AccountTransactionsTable @JvmOverloads constructor(
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
this.cellFormat {

View File

@ -8,8 +8,8 @@ import javafx.scene.input.ContextMenuEvent
import javafx.scene.input.MouseButton
import javafx.scene.input.MouseEvent
import net.dankito.banking.ui.javafx.dialogs.JavaFxDialogService
import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.BankAccount
import net.dankito.banking.ui.model.IAccountTransaction
import net.dankito.banking.ui.model.TypedBankAccount
import net.dankito.banking.ui.model.parameters.TransferMoneyData
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
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 transactionsToDisplay = FXCollections.observableArrayList<AccountTransaction>(listOf())
protected val transactionsToDisplay = FXCollections.observableArrayList<IAccountTransaction>(listOf())
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) {
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()
contextMenu.apply {
@ -105,21 +105,21 @@ open class AccountTransactionsView(private val presenter: BankingPresenter) : Vi
return contextMenu
}
protected open fun showTransactionDetailsDialog(transaction: AccountTransaction) {
protected open fun showTransactionDetailsDialog(transaction: IAccountTransaction) {
// TODO:
// presenter.showTransactionDetailsWindow(transaction.item)
}
protected open fun newTransferToSameRemittee(transaction: AccountTransaction) {
protected open fun newTransferToSameRemittee(transaction: IAccountTransaction) {
presenter.showTransferMoneyDialog(TransferMoneyData.fromAccountTransactionWithoutAmountAndUsage(transaction))
}
protected open fun newTransferWithSameData(transaction: AccountTransaction) {
protected open fun newTransferWithSameData(transaction: IAccountTransaction) {
presenter.showTransferMoneyDialog(TransferMoneyData.fromAccountTransaction(transaction))
}
protected open fun handleSelectedBankAccountsChanged(selectedBankAccounts: List<BankAccount>) {
protected open fun handleSelectedBankAccountsChanged(selectedBankAccounts: List<TypedBankAccount>) {
runLater {
isAccountSelected.value = selectedBankAccounts.isNotEmpty()

View File

@ -10,13 +10,13 @@ import javafx.scene.input.KeyCode
import net.dankito.banking.ui.javafx.dialogs.JavaFxDialogService
import net.dankito.banking.ui.javafx.model.AccountsAccountTreeItem
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 tornadofx.*
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)) {
protected var currentMenu: ContextMenu? = null

View File

@ -12,7 +12,7 @@ import javafx.scene.image.ImageView
import javafx.scene.layout.Priority
import kotlinx.coroutines.*
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.responses.BankingClientResponse
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 selectedBankAccount = SimpleObjectProperty<BankAccount>(preselectedValues?.account ?: bankAccountsSupportingTransferringMoney.firstOrNull())
protected val selectedBankAccount = SimpleObjectProperty<TypedBankAccount>(preselectedValues?.account ?: bankAccountsSupportingTransferringMoney.firstOrNull())
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
if (supportsInstantPayment.value == false) {
@ -345,7 +345,7 @@ open class TransferMoneyDialog @JvmOverloads constructor(
}
protected open fun transferMoney() {
remitteeBank.value?.let { remitteeBank ->
remitteeBank.value?.let {
val bankAccount = selectedBankAccount.value
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
if (response.isSuccessful) {

View File

@ -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.JavaFxDialogService
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.tan.*
import net.dankito.banking.ui.presenter.BankingPresenter
@ -20,7 +20,7 @@ import tornadofx.*
open class EnterTanDialog(
protected val customer: Customer,
protected val customer: TypedCustomer,
protected val challenge: TanChallenge,
protected val presenter: BankingPresenter,
protected val tanEnteredCallback: (EnterTanResult) -> Unit

View File

@ -2,10 +2,10 @@ package net.dankito.banking.ui.javafx.model
import javafx.scene.Node
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 {
private const val IconSize = 16.0

View File

@ -1,6 +1,6 @@
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)

View File

@ -2,13 +2,13 @@ package net.dankito.banking.ui.javafx.model
import javafx.collections.ListChangeListener
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.get
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 {
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()
children.setAll(customers.map { AccountsAccountTreeItem(it) })

View File

@ -1,21 +1,19 @@
package net.dankito.banking.persistence
import net.dankito.banking.ui.model.*
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 {
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)

View File

@ -1,27 +1,25 @@
package net.dankito.banking.persistence
import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.BankAccount
import net.dankito.banking.ui.model.Customer
import net.dankito.banking.ui.model.*
import net.dankito.utils.multiplatform.File
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()
}
override fun saveOrUpdateAccountTransactions(bankAccount: BankAccount, transactions: List<AccountTransaction>) {
override fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List<IAccountTransaction>) {
}

View File

@ -1,6 +1,6 @@
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.EnterTanResult
import net.dankito.banking.ui.model.tan.TanChallenge
@ -9,7 +9,7 @@ import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium
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.

View File

@ -1,8 +1,6 @@
package net.dankito.banking.ui
import net.dankito.banking.ui.model.BankAccount
import net.dankito.banking.ui.model.Customer
import net.dankito.banking.ui.model.MessageLogEntry
import net.dankito.banking.ui.model.*
import net.dankito.banking.ui.model.parameters.GetTransactionsParameter
import net.dankito.banking.ui.model.parameters.TransferMoneyData
import net.dankito.banking.ui.model.responses.AddAccountResponse
@ -18,7 +16,7 @@ interface IBankingClient {
fun addAccountAsync(callback: (AddAccountResponse) -> Unit)
fun getTransactionsAsync(
bankAccount: BankAccount,
bankAccount: TypedBankAccount,
parameter: GetTransactionsParameter,
callback: (GetTransactionsResponse) -> Unit
)
@ -26,6 +24,6 @@ interface IBankingClient {
fun transferMoneyAsync(data: TransferMoneyData, callback: (BankingClientResponse) -> Unit)
fun dataChanged(customer: Customer)
fun dataChanged(customer: TypedCustomer)
}

View File

@ -1,14 +1,14 @@
package net.dankito.banking.ui
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
interface IBankingClientCreator {
fun createClient(
customer: Customer,
customer: TypedCustomer,
dataFolder: File,
asyncRunner: IAsyncRunner,
callback: BankingClientCallback

View File

@ -1,7 +1,6 @@
package net.dankito.banking.ui
import net.dankito.banking.ui.model.Customer
import net.dankito.banking.ui.model.BankAccount
import net.dankito.banking.ui.model.TypedCustomer
import net.dankito.banking.ui.model.parameters.TransferMoneyData
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
import net.dankito.banking.ui.model.tan.EnterTanResult
@ -14,7 +13,7 @@ interface IRouter {
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)

View File

@ -7,49 +7,44 @@ import net.dankito.utils.multiplatform.DateFormatter
open class AccountTransaction(
open val bankAccount: BankAccount,
open val amount: BigDecimal,
open val currency: String,
open val unparsedUsage: String,
open val bookingDate: Date,
open val otherPartyName: String?,
open val otherPartyBankCode: String?,
open val otherPartyAccountId: String?,
open val bookingText: String?,
open val valueDate: Date,
open val statementNumber: Int,
open val sequenceNumber: Int?,
open val openingBalance: BigDecimal?,
open val closingBalance: BigDecimal?,
override val bankAccount: TypedBankAccount,
override val amount: BigDecimal,
override val currency: String,
override val unparsedUsage: String,
override val bookingDate: Date,
override val otherPartyName: String?,
override val otherPartyBankCode: String?,
override val otherPartyAccountId: String?,
override val bookingText: String?,
override val valueDate: Date,
override val statementNumber: Int,
override val sequenceNumber: Int?,
override val openingBalance: BigDecimal?,
override val closingBalance: BigDecimal?,
open val endToEndReference: String?,
open val customerReference: String?,
open val mandateReference: String?,
open val creditorIdentifier: String?,
open val originatorsIdentificationCode: String?,
open val compensationAmount: String?,
open val originalAmount: String?,
open val sepaUsage: String?,
open val deviantOriginator: String?,
open val deviantRecipient: String?,
open val usageWithNoSpecialType: String?,
open val primaNotaNumber: String?,
open val textKeySupplement: String?,
override val endToEndReference: String?,
override val customerReference: String?,
override val mandateReference: String?,
override val creditorIdentifier: String?,
override val originatorsIdentificationCode: String?,
override val compensationAmount: String?,
override val originalAmount: String?,
override val sepaUsage: String?,
override val deviantOriginator: String?,
override val deviantRecipient: String?,
override val usageWithNoSpecialType: String?,
override val primaNotaNumber: String?,
override val textKeySupplement: String?,
open val currencyType: String?,
open val bookingKey: String,
open val referenceForTheAccountOwner: String,
open val referenceOfTheAccountServicingInstitution: String?,
open val supplementaryDetails: String?,
open val transactionReferenceNumber: String,
open val relatedReferenceNumber: String?
) {
companion object {
val IdDateFormat = DateFormatter("yyyy.MM.dd")
}
override val currencyType: String?,
override val bookingKey: String,
override val referenceForTheAccountOwner: String,
override val referenceOfTheAccountServicingInstitution: String?,
override val supplementaryDetails: String?,
override val transactionReferenceNumber: String,
override val relatedReferenceNumber: String?
) : IAccountTransaction {
// for object deserializers
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)
open 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 var technicalId: String = buildTransactionIdentifier()
override fun equals(other: Any?): Boolean {

View File

@ -7,69 +7,47 @@ import kotlin.jvm.JvmOverloads
open class BankAccount @JvmOverloads constructor(
open val customer: Customer,
open var identifier: String,
open var accountHolderName: String,
open var iban: String?,
open var subAccountNumber: String?,
open var customerId: String,
open var balance: BigDecimal = BigDecimal.Zero,
open var currency: String = "EUR",
open var type: BankAccountType = BankAccountType.Girokonto,
open var productName: String? = null,
open var accountLimit: String? = null,
open var lastRetrievedTransactionsTimestamp: Date? = null,
open var supportsRetrievingAccountTransactions: Boolean = false,
open var supportsRetrievingBalance: Boolean = false,
open var supportsTransferringMoney: Boolean = false,
open var supportsInstantPaymentMoneyTransfer: Boolean = false,
open var bookedTransactions: List<AccountTransaction> = listOf(),
open var unbookedTransactions: List<Any> = listOf()
) : OrderedDisplayable {
override val customer: TypedCustomer,
override var identifier: String,
override var accountHolderName: String,
override var iban: String?,
override var subAccountNumber: String?,
override var customerId: String,
override var balance: BigDecimal = BigDecimal.Zero,
override var currency: String = "EUR",
override var type: BankAccountType = BankAccountType.Girokonto,
override var productName: String? = null,
override var accountLimit: String? = null,
override var lastRetrievedTransactionsTimestamp: Date? = null,
override var supportsRetrievingAccountTransactions: Boolean = false,
override var supportsRetrievingBalance: Boolean = false,
override var supportsTransferringMoney: Boolean = false,
override var supportsInstantPaymentMoneyTransfer: Boolean = false,
override var bookedTransactions: List<IAccountTransaction> = listOf(),
override var unbookedTransactions: List<Any> = listOf()
) : TypedBankAccount {
internal constructor() : this(Customer(), null, "") // for object deserializers
/* 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)
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 val displayName: String
get() {
return userSetDisplayName ?: productName ?: subAccountNumber ?: identifier
}
override var userSetDisplayName: String? = null
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 {
return "$accountHolderName ($identifier)"
}

View File

@ -1,26 +1,22 @@
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.TanMediumStatus
import net.dankito.banking.ui.model.tan.TanProcedure
import net.dankito.banking.util.sortedByDisplayIndex
import net.dankito.utils.multiplatform.UUID
open class Customer(
open var bankCode: String,
open var customerId: String,
open var password: String,
open var finTsServerAddress: String,
open var bankName: String,
open var bic: String,
open var customerName: String,
open var userId: String = customerId,
open var iconUrl: String? = null,
open var accounts: List<BankAccount> = listOf()
) : OrderedDisplayable {
override var bankCode: String,
override var customerId: String,
override var password: String,
override var finTsServerAddress: String,
override var bankName: String,
override var bic: String,
override var customerName: String,
override var userId: String = customerId,
override var iconUrl: String? = null,
override var accounts: List<TypedBankAccount> = listOf()
) : TypedCustomer {
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
@ -31,40 +27,23 @@ open class Customer(
: 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()
open val tanMediaSorted: List<TanMedium>
get() = tanMedia.sortedByDescending { it.status == TanMediumStatus.Used }
override var tanMedia: List<TanMedium> = listOf()
open var userSetDisplayName: String? = null
override val displayName: String
get() = userSetDisplayName ?: bankName
override var userSetDisplayName: String? = null
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 {
return "$customerName ($customerId)"
return "$bankName $customerId"
}
}

View File

@ -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"
}
}
}

View File

@ -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()
}
}

View File

@ -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 }
}

View File

@ -6,7 +6,7 @@ import net.dankito.utils.multiplatform.Date
open class MessageLogEntry(
val message: String,
val time: Date,
val customer: Customer
val customer: TypedCustomer
) {
override fun toString(): String {

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -1,7 +1,7 @@
package net.dankito.banking.ui.model.parameters
import net.dankito.utils.multiplatform.Date
import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.IAccountTransaction
open class GetTransactionsParameter(
@ -9,7 +9,7 @@ open class GetTransactionsParameter(
val fromDate: Date? = null,
val toDate: Date? = null,
val abortIfTanIsRequired: Boolean = false,
val retrievedChunkListener: ((List<AccountTransaction>) -> Unit)? = null
val retrievedChunkListener: ((List<IAccountTransaction>) -> Unit)? = null
) {
constructor() : this(true, null, null) // for Java

View File

@ -1,12 +1,11 @@
package net.dankito.banking.ui.model.parameters
import net.dankito.banking.ui.model.*
import net.dankito.utils.multiplatform.BigDecimal
import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.BankAccount
open class TransferMoneyData(
val account: BankAccount,
val account: TypedBankAccount,
val creditorName: String,
val creditorIban: String,
val creditorBic: String,
@ -17,9 +16,9 @@ open class TransferMoneyData(
companion object {
fun fromAccountTransactionWithoutAmountAndUsage(transaction: AccountTransaction): TransferMoneyData {
fun fromAccountTransactionWithoutAmountAndUsage(transaction: IAccountTransaction): TransferMoneyData {
return TransferMoneyData(
transaction.bankAccount,
transaction.bankAccount as TypedBankAccount,
transaction.otherPartyName ?: "",
transaction.otherPartyAccountId ?: "",
transaction.otherPartyBankCode ?: "",
@ -28,9 +27,9 @@ open class TransferMoneyData(
)
}
fun fromAccountTransaction(transaction: AccountTransaction): TransferMoneyData {
fun fromAccountTransaction(transaction: IAccountTransaction): TransferMoneyData {
return TransferMoneyData(
transaction.bankAccount,
transaction.bankAccount as TypedBankAccount,
transaction.otherPartyName ?: "",
transaction.otherPartyAccountId ?: "",
transaction.otherPartyBankCode ?: "",

View File

@ -1,19 +1,17 @@
package net.dankito.banking.ui.model.responses
import net.dankito.banking.ui.model.*
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(
isSuccessful: Boolean,
errorToShowToUser: String?,
val customer: Customer,
val customer: TypedCustomer,
val supportsRetrievingTransactionsOfLast90DaysWithoutTan: Boolean = false,
val bookedTransactionsOfLast90Days: Map<BankAccount, List<AccountTransaction>> = mapOf(),
val unbookedTransactionsOfLast90Days: Map<BankAccount, List<Any>> = mapOf(),
val balances: Map<BankAccount, BigDecimal> = mapOf(),
val bookedTransactionsOfLast90Days: Map<TypedBankAccount, List<IAccountTransaction>> = mapOf(),
val unbookedTransactionsOfLast90Days: Map<TypedBankAccount, List<Any>> = mapOf(),
val balances: Map<TypedBankAccount, BigDecimal> = mapOf(),
userCancelledAction: Boolean = false
)
: BankingClientResponse(isSuccessful, errorToShowToUser, userCancelledAction) {

View File

@ -1,15 +1,15 @@
package net.dankito.banking.ui.model.responses
import net.dankito.utils.multiplatform.BigDecimal
import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.BankAccount
import net.dankito.banking.ui.model.IAccountTransaction
import net.dankito.banking.ui.model.TypedBankAccount
open class GetTransactionsResponse(
val bankAccount: BankAccount,
val bankAccount: TypedBankAccount,
isSuccessful: Boolean,
errorToShowToUser: String?,
val bookedTransactions: List<AccountTransaction> = listOf(),
val bookedTransactions: List<IAccountTransaction> = listOf(),
val unbookedTransactions: List<Any> = listOf(),
val balance: BigDecimal? = null,
userCancelledAction: Boolean = false,

View File

@ -15,6 +15,8 @@ import net.dankito.banking.bankfinder.BankInfo
import net.dankito.banking.search.IRemitteeSearcher
import net.dankito.banking.search.NoOpRemitteeSearcher
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.ExtractTransferMoneyDataFromPdfResultType
import net.dankito.banking.ui.model.parameters.GetTransactionsParameter
@ -30,12 +32,13 @@ import net.dankito.utils.multiplatform.log.LoggerFactory
import kotlin.collections.ArrayList
open class BankingPresenter(
open class BankingPresenter constructor(
protected val bankingClientCreator: IBankingClientCreator,
protected val bankFinder: IBankFinder,
protected val dataFolder: File,
protected val persister: IBankingPersistence,
protected val router: IRouter,
protected val modelCreator: IModelCreator = DefaultModelCreator(),
protected val remitteeSearcher: IRemitteeSearcher = NoOpRemitteeSearcher(),
protected val bankIconFinder: IBankIconFinder = NoOpBankIconFinder(),
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 saveAccountOnNextEnterTanInvocation = false
protected val accountsChangedListeners = mutableListOf<(List<Customer>) -> Unit>()
protected val accountsChangedListeners = mutableListOf<(List<TypedCustomer>) -> 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 {
override fun enterTan(customer: Customer, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
override fun enterTan(customer: TypedCustomer, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
if (saveAccountOnNextEnterTanInvocation) {
persistAccount(customer)
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)
}
// TODO: move BankInfo out of fints4k
open fun addAccountAsync(bankInfo: BankInfo, customerId: String, pin: String, callback: (AddAccountResponse) -> Unit) {
val customer = Customer(bankInfo.bankCode, customerId, pin, bankInfo.pinTanAddress ?: "", bankInfo.name, bankInfo.bic, "")
open fun addAccountAsync(bankInfo: BankInfo, customerId: String, password: String, callback: (AddAccountResponse) -> Unit) {
val customer = modelCreator.createCustomer(bankInfo.bankCode, customerId, password, bankInfo.pinTanAddress ?: "", bankInfo.name, bankInfo.bic, "")
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 ->
bankIconUrl?.let {
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)
var iconFilePath = bankIconFile.getAbsolutePath()
@ -208,7 +211,7 @@ open class BankingPresenter(
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")
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
(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) {
customer.accounts.forEach { bankAccount ->
@ -274,13 +277,13 @@ open class BankingPresenter(
}
}
open fun fetchAllAccountTransactionsAsync(bankAccount: BankAccount,
open fun fetchAllAccountTransactionsAsync(bankAccount: TypedBankAccount,
callback: (GetTransactionsResponse) -> Unit) {
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) {
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 ->
if (bankAccount.supportsRetrievingAccountTransactions) {
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
fetchAccountTransactionsAsync(bankAccount, fromDate, abortIfTanIsRequired, callback)
@ -347,7 +350,7 @@ open class BankingPresenter(
callRetrievedAccountTransactionsResponseListener(response)
}
protected open fun receivedAccountsTransactionChunk(bankAccount: BankAccount, accountTransactionsChunk: List<AccountTransaction>) {
protected open fun receivedAccountsTransactionChunk(bankAccount: TypedBankAccount, accountTransactionsChunk: List<IAccountTransaction>) {
if (accountTransactionsChunk.isNotEmpty()) {
bankAccount.addBookedTransactions(accountTransactionsChunk)
@ -370,7 +373,7 @@ open class BankingPresenter(
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
persistAccount(bankAccount.customer)
@ -388,25 +391,25 @@ open class BankingPresenter(
}
}
open fun accountDisplayIndexUpdated(account: Customer) {
open fun accountDisplayIndexUpdated(account: TypedCustomer) {
persistAccount(account)
}
open fun accountUpdated(bank: Customer) {
open fun accountUpdated(bank: TypedCustomer) {
persistAccount(bank)
getBankingClientForAccount(bank)?.dataChanged(bank)
}
open fun accountUpdated(account: BankAccount) {
open fun accountUpdated(account: TypedBankAccount) {
persistAccount(account.customer)
}
protected open fun persistAccount(customer: Customer) {
persister.saveOrUpdateAccount(customer, customers)
protected open fun persistAccount(customer: ICustomer<*, *>) {
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)
// 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)
}
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()
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 {
getBankingClientForAccount(it)?.messageLogWithoutSensitiveData ?: listOf()
}
@ -556,15 +559,15 @@ open class BankingPresenter(
}
protected open fun getBankingClientForAccount(customer: Customer): IBankingClient? {
return bankingClientsForAccounts.get(customer)
protected open fun getBankingClientForAccount(customer: ICustomer<*, *>): IBankingClient? {
return bankingClientsForAccounts.get(customer as TypedCustomer)
}
open val selectedBankAccounts: List<BankAccount>
open val selectedBankAccounts: List<TypedBankAccount>
get() = ArrayList(selectedBankAccountsField)
open val selectedBankAccountsAccountTransactions: List<AccountTransaction>
open val selectedBankAccountsAccountTransactions: List<IAccountTransaction>
get() = getAccountTransactionsForBankAccounts(selectedBankAccounts)
open val balanceOfSelectedBankAccounts: BigDecimal
@ -574,12 +577,12 @@ open class BankingPresenter(
open val areAllAccountSelected: Boolean
get() = selectedAccountType == SelectedAccountType.AllAccounts
open fun isSingleSelectedAccount(customer: Customer): Boolean {
open fun isSingleSelectedAccount(customer: TypedCustomer): Boolean {
return selectedAccountType == SelectedAccountType.SingleAccount
&& selectedBankAccountsField.map { it.customer }.toSet().containsExactly(customer)
}
open fun isSingleSelectedBankAccount(bankAccount: BankAccount): Boolean {
open fun isSingleSelectedBankAccount(bankAccount: TypedBankAccount): Boolean {
return selectedAccountType == SelectedAccountType.SingleBankAccount
&& selectedBankAccountsField.containsExactly(bankAccount)
}
@ -590,39 +593,39 @@ open class BankingPresenter(
setSelectedBankAccounts(bankAccounts)
}
open fun selectedAccount(customer: Customer) {
open fun selectedAccount(customer: TypedCustomer) {
selectedAccountType = SelectedAccountType.SingleAccount
setSelectedBankAccounts(customer.accounts)
}
open fun selectedBankAccount(bankAccount: BankAccount) {
open fun selectedBankAccount(bankAccount: TypedBankAccount) {
selectedAccountType = SelectedAccountType.SingleBankAccount
setSelectedBankAccounts(listOf(bankAccount))
}
protected open fun setSelectedBankAccounts(bankAccounts: List<BankAccount>) {
protected open fun setSelectedBankAccounts(bankAccounts: List<TypedBankAccount>) {
this.selectedBankAccountsField = ArrayList(bankAccounts) // make a copy
callSelectedBankAccountsChangedListeners(selectedBankAccountsField)
}
open val customers: List<Customer>
open val customers: List<TypedCustomer>
get() = bankingClientsForAccounts.keys.toList()
open val bankAccounts: List<BankAccount>
open val bankAccounts: List<TypedBankAccount>
get() = customers.flatMap { it.accounts }
open val allTransactions: List<AccountTransaction>
open val allTransactions: List<IAccountTransaction>
get() = getAccountTransactionsForBankAccounts(bankAccounts)
open val balanceOfAllAccounts: BigDecimal
get() = getBalanceForAccounts(customers)
open val bankAccountsSupportingRetrievingAccountTransactions: List<BankAccount>
open val bankAccountsSupportingRetrievingAccountTransactions: List<TypedBankAccount>
get() = bankAccounts.filter { it.supportsRetrievingAccountTransactions }
open val hasBankAccountsSupportingRetrievingAccountTransactions: Boolean
@ -631,12 +634,12 @@ open class BankingPresenter(
open val doSelectedBankAccountsSupportRetrievingAccountTransactions: Boolean
get() = doBankAccountsSupportRetrievingAccountTransactions(selectedBankAccounts)
open fun doBankAccountsSupportRetrievingAccountTransactions(bankAccounts: List<BankAccount>): Boolean {
open fun doBankAccountsSupportRetrievingAccountTransactions(bankAccounts: List<TypedBankAccount>): Boolean {
return bankAccounts.firstOrNull { it.supportsRetrievingAccountTransactions } != null
}
open val bankAccountsSupportingRetrievingBalance: List<BankAccount>
open val bankAccountsSupportingRetrievingBalance: List<TypedBankAccount>
get() = bankAccounts.filter { it.supportsRetrievingBalance }
open val hasBankAccountsSupportingRetrievingBalance: Boolean
@ -645,12 +648,12 @@ open class BankingPresenter(
open val doSelectedBankAccountsSupportRetrievingBalance: Boolean
get() = doBankAccountsSupportRetrievingBalance(selectedBankAccounts)
open fun doBankAccountsSupportRetrievingBalance(bankAccounts: List<BankAccount>): Boolean {
open fun doBankAccountsSupportRetrievingBalance(bankAccounts: List<TypedBankAccount>): Boolean {
return bankAccounts.firstOrNull { it.supportsRetrievingBalance } != null
}
open val bankAccountsSupportingTransferringMoney: List<BankAccount>
open val bankAccountsSupportingTransferringMoney: List<TypedBankAccount>
get() = bankAccounts.filter { it.supportsTransferringMoney }
open val hasBankAccountsSupportTransferringMoney: Boolean
@ -659,16 +662,16 @@ open class BankingPresenter(
open val doSelectedBankAccountsSupportTransferringMoney: Boolean
get() = doBankAccountsSupportTransferringMoney(selectedBankAccounts)
open fun doBankAccountsSupportTransferringMoney(bankAccounts: List<BankAccount>): Boolean {
open fun doBankAccountsSupportTransferringMoney(bankAccounts: List<TypedBankAccount>): Boolean {
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
}
protected open fun getBalanceForAccounts(customers: Collection<Customer>): BigDecimal {
protected open fun getBalanceForAccounts(customers: Collection<TypedCustomer>): BigDecimal {
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)) {
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)
}
open fun removeAccountsChangedListener(listener: (List<Customer>) -> Unit): Boolean {
open fun removeAccountsChangedListener(listener: (List<TypedCustomer>) -> Unit): Boolean {
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)
}
open fun removeSelectedBankAccountsChangedListener(listener: (List<BankAccount>) -> Unit): Boolean {
open fun removeSelectedBankAccountsChangedListener(listener: (List<TypedBankAccount>) -> Unit): Boolean {
return selectedBankAccountsChangedListeners.add(listener)
}
protected open fun callSelectedBankAccountsChangedListeners(selectedBankAccounts: List<BankAccount>) {
protected open fun callSelectedBankAccountsChangedListeners(selectedBankAccounts: List<TypedBankAccount>) {
val selectedBankAccounts = this.selectedBankAccounts
ArrayList(selectedBankAccountsChangedListeners).forEach {

View File

@ -5,6 +5,7 @@ import net.dankito.banking.fints.webclient.IWebClient
import net.dankito.banking.persistence.IBankingPersistence
import net.dankito.banking.search.IRemitteeSearcher
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.util.*
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,
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) {
}

View File

@ -35,6 +35,8 @@
366FA4E224C4ED6C0094F009 /* EnterTanDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4E124C4ED6C0094F009 /* EnterTanDialog.swift */; };
366FA4E624C6EBF40094F009 /* EnterTanState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4E524C6EBF40094F009 /* EnterTanState.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 */; };
36B8A44B2503D1E800C15359 /* BiometricAuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B8A44A2503D1E800C15359 /* BiometricAuthenticationService.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 */; };
36B8A4582503EEB600C15359 /* ActionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B8A4572503EEB600C15359 /* ActionSheet.swift */; };
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 */; };
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 */; };
@ -138,8 +138,8 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
3684EB8F250B7F3C0001139E /* BankingUiCommon.framework in Embed Frameworks */,
36BCF86A24BA550D005BEC29 /* BankFinder.framework in Embed Frameworks */,
36BCF85924BA4274005BEC29 /* BankingUiCommon.framework in Embed Frameworks */,
36BCF85F24BA4DA8005BEC29 /* MultiplatformUtils.framework in Embed Frameworks */,
36FC92D124B39C47002B12E9 /* fints4k.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>"; };
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>"; };
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>"; };
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>"; };
@ -264,8 +266,8 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
3684EB90250B7F560001139E /* BankingUiCommon.framework in Frameworks */,
36BCF86924BA550D005BEC29 /* BankFinder.framework in Frameworks */,
36BCF85824BA4274005BEC29 /* BankingUiCommon.framework in Frameworks */,
36BCF85E24BA4DA8005BEC29 /* MultiplatformUtils.framework in Frameworks */,
36FC92D024B39C47002B12E9 /* fints4k.framework in Frameworks */,
36BCF87024BB0F8A005BEC29 /* fints4kBankingClient.framework in Frameworks */,
@ -419,6 +421,8 @@
36FC928F24B39A05002B12E9 = {
isa = PBXGroup;
children = (
3684EB8E250B7F3C0001139E /* BankingUiCommon.framework */,
3684EB8C250B7F2B0001139E /* BankingUiCommon.framework.dSYM */,
36FC929A24B39A05002B12E9 /* BankingiOSApp */,
36FC92B424B39A08002B12E9 /* BankingiOSAppTests */,
36FC92BF24B39A08002B12E9 /* BankingiOSAppUITests */,

View File

@ -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])
func createPreviewBanks() -> [Customer] {
func createPreviewBanks() -> [ICustomer] {
let bank1 = Customer(bankCode: "", customerId: "", password: "", finTsServerAddress: "", bankName: "Abzockbank", bic: "", customerName: "Marieke Musterfrau", userId: "", iconUrl: "", accounts: [])
bank1.accounts = [

View File

@ -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 {
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 {
return CommonBigDecimal(decimal_: self.map { $0.amount.decimal }.sum())

View File

@ -6,8 +6,8 @@ class AppData : ObservableObject {
@Inject private var presenter: BankingPresenterSwift
@Published var banks: [Customer] = []
@Published var banksSorted: [Customer] = []
@Published var banks: [ICustomer] = []
@Published var banksSorted: [ICustomer] = []
@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.banksSorted = banks.sortedByDisplayIndex()

View File

@ -19,7 +19,7 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
}
func saveOrUpdateAccount(customer: Customer, allCustomers: [Customer]) {
func saveOrUpdateAccount(customer: ICustomer, allCustomers: [ICustomer]) {
do {
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
for account in customer.accounts {
@ -58,7 +58,7 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
}
func readPersistedAccounts_() -> [Customer] {
func readPersistedAccounts_() -> [ICustomer] {
var customers: [PersistedCustomer] = []
do {
@ -73,7 +73,7 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
return customers.map( { mapper.map($0) } )
}
func deleteAccount(customer: Customer, allCustomers: [Customer]) {
func deleteAccount(customer: ICustomer, allCustomers: [ICustomer]) {
do {
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 {
for transaction in 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
} 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)")
}
}
}

View File

@ -6,14 +6,14 @@ class EnterTanState : Identifiable {
let id: Foundation.UUID = UUID()
let customer: Customer
let customer: ICustomer
let tanChallenge: TanChallenge
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.tanChallenge = tanChallenge
self.callback = callback

View File

@ -5,7 +5,7 @@ import BankingUiSwift
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: [])
mapped.userSetDisplayName = customer.userSetDisplayName
@ -23,7 +23,7 @@ class Mapper {
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)
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) } ) ?? []
}
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: [])
mapped.haveAllTransactionsBeenFetched = account.haveAllTransactionsBeenFetched
@ -69,11 +69,11 @@ class Mapper {
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) } )
}
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)
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) } ) ?? []
}
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)
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) } )
}
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)
mapped.account = account

View File

@ -11,7 +11,7 @@ extension Message {
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)'?"),
message: Text("All data for this account will be permanently deleted locally."),
primaryButton: .destructive(Text("Delete"), action: { deleteAccount(bank) } ),

View File

@ -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)
SceneDelegate.navigateToView(EnterTanDialog(enterTanState))

View File

@ -9,7 +9,7 @@ struct AccountTransactionsDialog: View {
private let title: String
private let allTransactions: [AccountTransaction]
private let allTransactions: [IAccountTransaction]
private let balanceOfAllTransactions: CommonBigDecimal
@ -20,10 +20,10 @@ struct AccountTransactionsDialog: View {
@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
@ -45,7 +45,7 @@ struct AccountTransactionsDialog: View {
@Inject private var presenter: BankingPresenterSwift
init(allBanks: [Customer]) {
init(allBanks: [ICustomer]) {
let allAccounts = allBanks.flatMap { $0.accounts }
self.init("All accounts", allAccounts.flatMap { $0.bookedTransactions }, allBanks.sumBalances(), allAccounts.filter { $0.haveAllTransactionsBeenFetched == false })
@ -53,19 +53,19 @@ struct AccountTransactionsDialog: View {
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 })
presenter.selectedAccount(customer: bank)
}
init(account: BankAccount) {
init(account: IBankAccount) {
self.init(account.displayName, account.bookedTransactions, account.balance, account.haveAllTransactionsBeenFetched ? [] : [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.allTransactions = transactions
@ -74,7 +74,7 @@ struct AccountTransactionsDialog: View {
self.balanceOfAllTransactions = 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)
_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
presenter.fetchAllAccountTransactionsAsync(bankAccount: account, callback: self.handleGetAllTransactionsResult)
}
@ -224,7 +224,7 @@ struct AccountTransactionsDialog: View {
struct AccountTransactionsDialog_Previews: PreviewProvider {
static var previews: some View {
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))
}

View File

@ -22,7 +22,7 @@ struct AccountsDialog: View {
Form {
AllBanksListItem(banks: data.banks)
ForEach(data.banks.sortedByDisplayIndex()) { bank in
ForEach(data.banks.sortedByDisplayIndex(), id: \.technicalId) { bank in
BankListItem(bank: bank)
}

View File

@ -85,7 +85,7 @@ struct AddAccountDialog: View {
isTryingToAddAccount = true
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)
}
}

View File

@ -9,7 +9,7 @@ struct BankAccountSettingsDialog: View {
@Inject private var presenter: BankingPresenterSwift
private let account: BankAccount
private let account: IBankAccount
@State private var displayName: String
@ -21,7 +21,7 @@ struct BankAccountSettingsDialog: View {
}
init(_ account: BankAccount) {
init(_ account: IBankAccount) {
self.account = account
_displayName = State(initialValue: account.displayName)
@ -79,8 +79,8 @@ struct BankAccountSettingsDialog: View {
private func donePressed() {
if hasUnsavedData {
account.userSetDisplayName = displayName
presenter.accountUpdated(account: account.customer)
presenter.accountUpdated(account: account)
}
closeDialog()

View File

@ -10,7 +10,7 @@ struct BankSettingsDialog: View {
@Inject private var presenter: BankingPresenterSwift
private let bank: Customer
private let bank: ICustomer
@State private var displayName: String
@ -19,7 +19,7 @@ struct BankSettingsDialog: View {
@State private var selectedTanProcedure: TanProcedure?
@State private var accountsSorted: [BankAccount]
@State private var accountsSorted: [IBankAccount]
@State private var askUserToDeleteAccountOrSaveChangesMessage: Message? = nil
@ -32,7 +32,7 @@ struct BankSettingsDialog: View {
}
init(_ bank: Customer) {
init(_ bank: ICustomer) {
self.bank = bank
_displayName = State(initialValue: bank.displayName)
@ -75,7 +75,7 @@ struct BankSettingsDialog: View {
}
Section(header: SectionHeaderWithRightAlignedEditButton("Accounts")) {
ForEach(accountsSorted) { account in
ForEach(accountsSorted, id: \.technicalId) { account in
NavigationLink(destination: LazyView(BankAccountSettingsDialog(account))) {
Text(account.displayName)
}
@ -102,7 +102,7 @@ struct BankSettingsDialog: View {
func reorderAccounts(from source: IndexSet, to destination: Int) {
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)
}
func deleteAccount(bank: Customer) {
func deleteAccount(bank: ICustomer) {
presenter.deleteAccount(customer: bank)
closeDialog()
@ -135,7 +135,7 @@ struct BankSettingsDialog: View {
bank.selectedTanProcedure = selectedTanProcedure
presenter.accountUpdated(account: bank)
presenter.accountUpdated(bank: bank)
}
closeDialog()

View File

@ -11,7 +11,7 @@ struct EnterTanDialog: View {
private var tanChallenge: TanChallenge
private var customer: Customer
private var customer: ICustomer
private var customersTanMedia: [TanMedium] = []

View File

@ -18,7 +18,7 @@ struct SettingsDialog: View {
Form {
Section(header: SectionHeaderWithRightAlignedEditButton("Bank Credentials", isEditButtonEnabled: data.hasAtLeastOneAccountBeenAdded),
footer: footer) {
ForEach(data.banksSorted) { bank in
ForEach(data.banksSorted, id: \.technicalId) { bank in
NavigationLink(destination: LazyView(BankSettingsDialog(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)
}
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
DispatchQueue.main.async {
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)
}

Some files were not shown because too many files have changed in this diff Show More