Hide keyboard shortcuts

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

1from os.path import basename 

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

3from django.core.exceptions import ValidationError 

4from django.utils.translation import gettext as _ 

5from pytz import timezone 

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

7 

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

9 

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

11 

12SVM_FILE_HEADER_TYPES = ("0",) 

13 

14SVM_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 

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

25 

26SVM_FILE_RECORD_DECIMALS = ("amount",) 

27 

28SVM_FILE_RECORD_DATES = ( 

29 "record_date", 

30 "paid_date", 

31) 

32 

33SVM_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 

49SVM_FILE_SUMMARY_TYPES = ("9",) 

50 

51SVM_FILE_SUMMARY_DECIMALS = ( 

52 "record_amount", 

53 "correction_amount", 

54) 

55 

56SVM_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 

66def 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 

77def 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 

118def 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