1
1
package fr .dossierfacile .process .file .service .documentrules ;
2
2
3
- import fr .dossierfacile .common .entity .*;
4
- import fr .dossierfacile .common .entity .ocr .PublicPayslipFile ;
5
- import fr .dossierfacile .common .enums .DocumentCategory ;
6
- import fr .dossierfacile .common .enums .DocumentSubCategory ;
3
+ import fr .dossierfacile .common .entity .BarCodeFileAnalysis ;
4
+ import fr .dossierfacile .common .entity .Document ;
5
+ import fr .dossierfacile .common .entity .File ;
6
+ import fr .dossierfacile .common .entity .ParsedFileAnalysis ;
7
+ import fr .dossierfacile .common .entity .ocr .PayslipFile ;
7
8
import fr .dossierfacile .common .enums .ParsedFileAnalysisStatus ;
8
9
import fr .dossierfacile .common .enums .ParsedFileClassification ;
9
10
import fr .dossierfacile .process .file .barcode .twoddoc .parsing .TwoDDocDataType ;
12
13
import lombok .RequiredArgsConstructor ;
13
14
import lombok .extern .slf4j .Slf4j ;
14
15
import org .springframework .stereotype .Service ;
15
- import org .springframework .util .CollectionUtils ;
16
16
17
- import java .time .LocalDate ;
18
17
import java .time .YearMonth ;
19
- import java .util .Comparator ;
20
- import java .util .List ;
21
18
import java .util .Map ;
22
- import java .util .Optional ;
23
- import java .util .stream .Collectors ;
24
19
25
20
@ Service
26
21
@ RequiredArgsConstructor
27
22
@ Slf4j
28
- public class PublicPayslipRulesValidationService implements RulesValidationService {
29
- @ Override
30
- public boolean shouldBeApplied (Document document ) {
31
- return document .getDocumentCategory () == DocumentCategory .FINANCIAL
32
- && document .getDocumentSubCategory () == DocumentSubCategory .SALARY
33
- && !CollectionUtils .isEmpty (document .getFiles ())
34
- && document .getFiles ().stream ().anyMatch ((f ) -> f .getParsedFileAnalysis () != null
35
- && f .getParsedFileAnalysis ().getParsedFile () != null
36
- && f .getParsedFileAnalysis ().getParsedFile ().getClassification () == ParsedFileClassification .PUBLIC_PAYSLIP );
37
- }
38
-
39
- private PublicPayslipFile fromQR (BarCodeFileAnalysis barCodeFileAnalysis ) {
23
+ public class PublicPayslipRulesValidationService extends AbstractPayslipRulesValidationService implements RulesValidationService {
24
+ private PayslipFile fromQR (BarCodeFileAnalysis barCodeFileAnalysis ) {
40
25
Map <String , String > dataWithLabel = (Map <String , String >) barCodeFileAnalysis .getVerifiedData ();
41
- return PublicPayslipFile .builder ()
26
+ return PayslipFile .builder ()
27
+ .classification (ParsedFileClassification .PUBLIC_PAYSLIP )
42
28
.fullname (dataWithLabel .get (TwoDDocDataType .ID_10 .getLabel ()))
43
29
.month (YearMonth .from (TwoDDocUtil .getLocalDateFrom2DDocHexDate (dataWithLabel .get (TwoDDocDataType .ID_54 .getLabel ()))))
44
30
.netTaxableIncome (Double .parseDouble (dataWithLabel .get (TwoDDocDataType .ID_58 .getLabel ()).replace (" " , "" ).replace (',' , '.' )))
45
31
.cumulativeNetTaxableIncome (Double .parseDouble (dataWithLabel .get (TwoDDocDataType .ID_59 .getLabel ()).replace (" " , "" ).replace (',' , '.' )))
46
32
.build ();
47
33
}
48
34
49
- private boolean checkQRCode (Document document ) {
35
+ @ Override
36
+ protected boolean checkQRCode (Document document ) {
50
37
for (File dfFile : document .getFiles ()) {
51
38
ParsedFileAnalysis analysis = dfFile .getParsedFileAnalysis ();
52
39
if (analysis == null || dfFile .getFileAnalysis () == null || analysis .getAnalysisStatus () == ParsedFileAnalysisStatus .FAILED ) {
53
40
continue ;
54
41
}
55
42
if (analysis .getClassification () == ParsedFileClassification .PUBLIC_PAYSLIP ) {
56
- PublicPayslipFile qrDocument = fromQR (dfFile .getFileAnalysis ());
57
- PublicPayslipFile parsedDocument = (PublicPayslipFile ) analysis .getParsedFile ();
43
+ PayslipFile qrDocument = fromQR (dfFile .getFileAnalysis ());
44
+ PayslipFile parsedDocument = (PayslipFile ) analysis .getParsedFile ();
58
45
59
46
if (qrDocument == null
60
47
|| qrDocument .getFullname () == null
61
48
|| qrDocument .getMonth () == null
62
49
|| qrDocument .getCumulativeNetTaxableIncome () == 0
63
50
|| !PersonNameComparator .equalsWithNormalization (qrDocument .getFullname (), parsedDocument .getFullname ())
64
51
|| !qrDocument .getMonth ().equals (parsedDocument .getMonth ())
65
- || qrDocument .getNetTaxableIncome () != parsedDocument .getNetTaxableIncome ()
66
- || qrDocument .getCumulativeNetTaxableIncome () != parsedDocument .getCumulativeNetTaxableIncome ()) {
52
+ || Math . abs ( qrDocument .getNetTaxableIncome () - parsedDocument .getNetTaxableIncome ()) > 1
53
+ || Math . abs ( qrDocument .getCumulativeNetTaxableIncome () - parsedDocument .getCumulativeNetTaxableIncome ()) > 1 ) {
67
54
return false ;
68
55
}
69
56
}
70
57
}
71
58
return true ;
72
59
}
73
60
74
- private boolean checkNamesRule (Document document ) {
75
- Person documentOwner = Optional .ofNullable ((Person ) document .getTenant ()).orElseGet (() -> document .getGuarantor ());
76
- for (File dfFile : document .getFiles ()) {
77
- ParsedFileAnalysis analysis = dfFile .getParsedFileAnalysis ();
78
- PublicPayslipFile parsedFile = (PublicPayslipFile ) analysis .getParsedFile ();
79
-
80
- String fullname = parsedFile .getFullname ().toUpperCase ().replaceFirst ("^(MR |MME |MLLE )" , "" );
81
-
82
- if (!PersonNameComparator .bearlyEqualsTo (fullname , documentOwner .getLastName (), documentOwner .getFirstName ())
83
- && !PersonNameComparator .bearlyEqualsTo (fullname , documentOwner .getPreferredName (), documentOwner .getFirstName ())) {
84
- return false ;
85
- }
86
- }
87
- return true ;
88
- }
89
-
90
- private List <List <YearMonth >> getExpectedMonthsLists () {
91
- LocalDate localDate = LocalDate .now ();
92
- YearMonth yearMonth = YearMonth .now ();
93
- return (localDate .getDayOfMonth () <= 15 ) ?
94
- List .of (
95
- List .of (yearMonth .minusMonths (1 ), yearMonth .minusMonths (2 ), yearMonth .minusMonths (3 )),
96
- List .of (yearMonth .minusMonths (2 ), yearMonth .minusMonths (3 ), yearMonth .minusMonths (4 ))) :
97
- List .of (
98
- List .of (yearMonth , yearMonth .minusMonths (1 ), yearMonth .minusMonths (2 )),
99
- List .of (yearMonth .minusMonths (1 ), yearMonth .minusMonths (2 ), yearMonth .minusMonths (3 )));
100
- }
101
-
102
- private boolean checkMonthsValidityRule (Document document ) {
103
- List <List <YearMonth >> expectedMonthsList = getExpectedMonthsLists ();
104
-
105
- List <YearMonth > presentMonths = document .getFiles ().stream ()
106
- .map (file -> ((PublicPayslipFile ) file .getParsedFileAnalysis ().getParsedFile ()).getMonth ())
107
- .toList ();
108
-
109
- return expectedMonthsList .stream ().anyMatch (
110
- expectedMonths -> expectedMonths .stream ().allMatch (month -> presentMonths .contains (month ))
111
- );
112
- }
113
-
114
- private boolean checkAmountValidityRule (Document document ) {
115
- List <PublicPayslipFile > recentFiles = document .getFiles ().stream ()
116
- .map (file -> (PublicPayslipFile ) file .getParsedFileAnalysis ().getParsedFile ())
117
- .sorted (Comparator .comparing (PublicPayslipFile ::getMonth ).reversed ())
118
- .limit (3 )
119
- .collect (Collectors .toList ());
120
-
121
- double monthlyAverage = recentFiles .stream ()
122
- .mapToDouble (PublicPayslipFile ::getNetTaxableIncome )
123
- .sum () / recentFiles .size ();
124
-
125
- // Check percentage difference
126
- double diffPercentage = Math .abs ((monthlyAverage - document .getMonthlySum ()) / document .getMonthlySum ());
127
- return (diffPercentage <= 0.2 );
128
- }
129
-
130
61
@ Override
131
- public DocumentAnalysisReport process (Document document , DocumentAnalysisReport report ) {
132
-
133
- try {
134
- if (CollectionUtils .isEmpty (document .getFiles ()) || document .getFiles ().stream ()
135
- .anyMatch (f -> f .getParsedFileAnalysis () == null || f .getParsedFileAnalysis ().getParsedFile () == null )
136
- ) {
137
- report .setAnalysisStatus (DocumentAnalysisStatus .UNDEFINED );
138
- return report ;
139
- }
140
-
141
- if (!checkQRCode (document )) {
142
- log .error ("Document mismatch to QR CODE :" + document .getId ());
143
- report .getBrokenRules ().add (DocumentBrokenRule .builder ()
144
- .rule (DocumentRule .R_PAYSLIP_QRCHECK )
145
- .message (DocumentRule .R_PAYSLIP_QRCHECK .getDefaultMessage ())
146
- .build ());
147
- report .setAnalysisStatus (DocumentAnalysisStatus .DENIED );
148
- } else if (!checkNamesRule (document )) {
149
- log .error ("Document names mismatches :" + document .getId ());
150
- report .getBrokenRules ().add (DocumentBrokenRule .builder ()
151
- .rule (DocumentRule .R_PAYSLIP_NAME )
152
- .message (DocumentRule .R_PAYSLIP_NAME .getDefaultMessage ())
153
- .build ());
154
- report .setAnalysisStatus (DocumentAnalysisStatus .DENIED );
155
- } else if (!checkMonthsValidityRule (document )) {
156
- log .error ("Document is expired :" + document .getId ());
157
- report .getBrokenRules ().add (DocumentBrokenRule .builder ()
158
- .rule (DocumentRule .R_PAYSLIP_MONTHS )
159
- .message (DocumentRule .R_PAYSLIP_MONTHS .getDefaultMessage ())
160
- .build ());
161
- report .setAnalysisStatus (DocumentAnalysisStatus .DENIED );
162
- } else if (!checkAmountValidityRule (document )) {
163
- log .error ("Amount specified on document mismatch :" + document .getId ());
164
- report .getBrokenRules ().add (DocumentBrokenRule .builder ()
165
- .rule (DocumentRule .R_PAYSLIP_AMOUNT_MISMATCHES )
166
- .message (DocumentRule .R_PAYSLIP_AMOUNT_MISMATCHES .getDefaultMessage ())
167
- .build ());
168
- report .setAnalysisStatus (DocumentAnalysisStatus .DENIED );
169
- } else {
170
- report .setAnalysisStatus (DocumentAnalysisStatus .CHECKED );
171
- }
172
-
173
- } catch (Exception e ) {
174
- log .error ("Error during the rules validation execution pocess" , e );
175
- report .setAnalysisStatus (DocumentAnalysisStatus .UNDEFINED );
176
- }
177
- return report ;
62
+ protected ParsedFileClassification getPayslipClassification () {
63
+ return ParsedFileClassification .PUBLIC_PAYSLIP ;
178
64
}
65
+
179
66
}
0 commit comments