Coverage for jbank/svm.py: 94%

# Coverage for jbank/svm.py : 94%

## 62 statements

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1 from os.path import basename

2 from typing import Union, Dict, List, Optional, Any

3 from django.core.exceptions import ValidationError

4 from django.utils.translation import gettext as _

5 from pytz import timezone

6 from jbank.parsers import parse_filename_suffix, parse_records, convert_date_fields, convert_decimal_fields

7

8 SVM_STATEMENT_SUFFIXES = ("SVM", "TXT", "KTL")

9

10 SVM_FILE_HEADER_DATES = (("record_date", "record_time"),)

11

12 SVM_FILE_HEADER_TYPES = ("0",)

13

14 SVM_FILE_HEADER = (

15 ("statement_type", "9(1)", "P"),

16 ("record_date", "9(6)", "P"),

17 ("record_time", "9(4)", "P"),

18 ("institution_identifier", "X(2)", "P"),

19 ("service_identifier", "X(9)", "P"),

20 ("currency_identifier", "X(1)", "P"),

21 ("pad01", "X(67)", "P"),

22)

23

24 SVM_FILE_RECORD_TYPES = ("3", "5")

25

26 SVM_FILE_RECORD_DECIMALS = ("amount",)

27

28 SVM_FILE_RECORD_DATES = (

29 "record_date",

30 "paid_date",

31)

32

33 SVM_FILE_RECORD = (

34 ("record_type", "9(1)", "P"), # 3=viitesiirto, 5=suoraveloitus

35 ("account_number", "9(14)", "P"),

36 ("record_date", "9(6)", "P"),

37 ("paid_date", "9(6)", "P"),

38 ("archive_identifier", "X(16)", "P"),

39 ("remittance_info", "X(20)", "P"),

40 ("payer_name", "X(12)", "P"),

41 ("currency_identifier", "X(1)", "P"), # 1=eur

42 ("name_source", "X", "V"),

43 ("amount", "9(10)", "P"),

44 ("correction_identifier", "X", "V"), # 0=normal, 1=correction

45 ("delivery_method", "X", "P"), # A=asiakkaalta, K=konttorista, J=pankin jarjestelmasta

46 ("receipt_code", "X", "P"),

47)

48

49 SVM_FILE_SUMMARY_TYPES = ("9",)

50

51 SVM_FILE_SUMMARY_DECIMALS = (

52 "record_amount",

53 "correction_amount",

54)

55

56 SVM_FILE_SUMMARY = (

57 ("record_type", "9(1)", "P"), # 9

58 ("record_count", "9(6)", "P"),

59 ("record_amount", "9(11)", "P"),

60 ("correction_count", "9(6)", "P"),

61 ("correction_amount", "9(11)", "P"),

62 ("pad01", "X(5)", "P"),

63)

64

65

66 def parse_svm_batches_from_file(filename: str) -> list:

67 if parse_filename_suffix(filename).upper() not in SVM_STATEMENT_SUFFIXES:

68 raise ValidationError(

69 _('File {filename} has unrecognized ({suffixes}) suffix for file type "{file_type}"').format(

70 filename=filename, suffixes=", ".join(SVM_STATEMENT_SUFFIXES), file_type="saapuvat viitemaksut"

71 )

72 )

73 with open(filename, "rt", encoding="ISO-8859-1") as fp:

74 return parse_svm_batches(fp.read(), filename=basename(filename)) # type: ignore

75

76

77 def parse_svm_batches(content: str, filename: str) -> list:

78 lines = content.split("\n")

79 nlines = len(lines)

80 line_number = 1

81 tz = timezone("Europe/Helsinki")

82 batches = []

83 header: Optional[Dict[str, Union[int, str]]] = None

84 records: List[Dict[str, Union[int, str]]] = []

85 summary: Optional[Dict[str, Union[int, str]]] = None

86

87 while line_number <= nlines:

88 line = lines[line_number - 1]

89 if line.strip() == "":

90 line_number += 1

91 continue

92 record_type = line[:1]

93

94 if record_type in SVM_FILE_HEADER_TYPES:

95 if header:

96 batches.append(combine_svm_batch(header, records, summary))

97 header, records, summary = None, [], None

98 header = parse_records(lines[line_number - 1], SVM_FILE_HEADER, line_number=line_number)

99 convert_date_fields(header, SVM_FILE_HEADER_DATES, tz)

100 line_number += 1

101 elif record_type in SVM_FILE_RECORD_TYPES:

102 record = parse_records(line, SVM_FILE_RECORD, line_number=line_number)

103 convert_date_fields(record, SVM_FILE_RECORD_DATES, tz)

104 convert_decimal_fields(record, SVM_FILE_RECORD_DECIMALS)

105 line_number += 1

106 records.append(record)

107 elif record_type in SVM_FILE_SUMMARY_TYPES:

108 summary = parse_records(line, SVM_FILE_SUMMARY, line_number=line_number)

109 convert_decimal_fields(summary, SVM_FILE_SUMMARY_DECIMALS)

110 line_number += 1

111 else:

112 raise ValidationError(_("Unknown record type on {}({}): {}").format(filename, line_number, record_type))

113

114 batches.append(combine_svm_batch(header, records, summary))

115 return batches

116

117

118 def combine_svm_batch(

119 header: Optional[Dict[str, Any]], records: List[Dict[str, Union[int, str]]], summary: Optional[Dict[str, Any]]

120) -> Dict[str, Any]:

121 data = {"header": header, "records": records}

122 if summary is not None:

123 data["summary"] = summary

124 return data