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

1# pylint: disable=logging-format-interpolation,too-many-locals,too-many-branches 

2import base64 

3import logging 

4import os 

5import pytz 

6from django.core.management.base import CommandParser 

7from django.utils.timezone import now 

8from jutil.xml import xml_to_dict 

9from jbank.helpers import process_pain002_file_content, parse_start_and_end_date 

10from jbank.models import WsEdiConnection 

11from jbank.wsedi import wsedi_get, wsedi_execute 

12from jutil.command import SafeCommand 

13 

14 

15logger = logging.getLogger(__name__) 

16 

17 

18class Command(SafeCommand): 

19 help = """ 

20 Download Finnish bank files 

21 """ 

22 

23 def add_arguments(self, parser: CommandParser): 

24 parser.add_argument("path", type=str) 

25 parser.add_argument("--verbose", action="store_true") 

26 parser.add_argument("--overwrite", action="store_true") 

27 parser.add_argument("--file-type", type=str, help="E.g. TO, SVM, XP, NDCORPAYL, pain.002.001.03") 

28 parser.add_argument("--status", type=str, default="", help="E.g. DLD, NEW") 

29 parser.add_argument("--file-reference", type=str, help="Download single file based on file reference") 

30 parser.add_argument("--list-only", action="store_true") 

31 parser.add_argument("--process-pain002", action="store_true") 

32 parser.add_argument("--start-date", type=str) 

33 parser.add_argument("--end-date", type=str) 

34 parser.add_argument("--ws", type=int) 

35 

36 def do(self, *args, **options): # pylint: disable=too-many-statements 

37 ws = WsEdiConnection.objects.get(id=options["ws"]) if options["ws"] else None 

38 assert ws is None or isinstance(ws, WsEdiConnection) 

39 if ws and not ws.enabled: 

40 logger.info("WS connection %s not enabled, exiting", ws) 

41 return 

42 

43 start_date, end_date = parse_start_and_end_date(pytz.timezone("Europe/Helsinki"), **options) 

44 path = os.path.abspath(options["path"]) 

45 command = "DownloadFileList" 

46 time_now = now() 

47 file_reference = options["file_reference"] 

48 if file_reference: 

49 command = "DownloadFile" 

50 status = options["status"] 

51 file_type = options["file_type"] 

52 if command == "DownloadFileList" and not file_type: 

53 print("--file-type required (e.g. TO, SVM, XP, NDCORPAYL, pain.002.001.03)") 

54 return 

55 if ws: 

56 content = wsedi_execute( 

57 ws, 

58 command=command, 

59 file_type=file_type, 

60 status=status, 

61 start_date=start_date, 

62 end_date=end_date, 

63 file_reference=file_reference, 

64 verbose=options["verbose"], 

65 ) 

66 data = xml_to_dict(content, array_tags=["FileDescriptor"]) 

67 else: 

68 res = wsedi_get( 

69 command=command, 

70 file_type=file_type, 

71 status=status, 

72 file_reference=file_reference, 

73 verbose=options["verbose"], 

74 ) 

75 data = res.json() 

76 # "FileDescriptors": { 

77 # "FileDescriptor": [ 

78 # { 

79 # "FileReference": "535283541", 

80 # "TargetId": "NONE", 

81 # "UserFilename": "STOL001.FMV80KT2.WEBSER.PS", 

82 # "ParentFileReference": "1218", 

83 # "FileType": "TO", 

84 # "FileTimestamp": "2017-12-18T20:33:09.362+02:00", 

85 # "Status": "DLD", 

86 # "LastDownloadTimestamp": "2017-12-19T12:36:34.490+02:00", 

87 # "ForwardedTimestamp": "2017-12-18T20:33:09.362+02:00", 

88 # "Deletable": "false", 

89 # "CustomerNumber": "06720106", 

90 # "Modifier": "06720106", 

91 # "ModifiedTimestamp": "2017-12-19T12:36:34.490+02:00", 

92 # "SourceId": "A", 

93 # "Environment": "PRODUCTION" 

94 # }, 

95 # ... 

96 

97 if command == "DownloadFileList": 

98 if ( 

99 "FileDescriptors" in data 

100 and data["FileDescriptors"] is not None 

101 and "FileDescriptor" in data["FileDescriptors"] 

102 ): 

103 for fd in data["FileDescriptors"]["FileDescriptor"]: 

104 file_reference = fd["FileReference"] 

105 file_type = fd["FileType"] 

106 file_basename = file_reference + "." + file_type 

107 file_path = os.path.join(path, file_basename) 

108 if options["list_only"]: 

109 print( 

110 "{file_reference} ({file_type}/{status}): {user_filename} ({timestamp})".format( 

111 file_reference=file_reference, 

112 file_type=file_type, 

113 status=fd.get("Status"), 

114 user_filename=fd.get("UserFilename"), 

115 timestamp=fd.get("FileTimestamp"), 

116 ) 

117 ) 

118 continue 

119 if options["overwrite"] or not os.path.isfile(file_path): 

120 command = "DownloadFile" 

121 if ws: 

122 content = wsedi_execute( 

123 ws, 

124 command=command, 

125 file_type=file_type, 

126 status="", 

127 file_reference=file_reference, 

128 verbose=options["verbose"], 

129 ) 

130 file_data = xml_to_dict(content) 

131 else: 

132 res = wsedi_get( 

133 command=command, 

134 file_type=file_type, 

135 status="", 

136 file_reference=file_reference, 

137 verbose=options["verbose"], 

138 ) 

139 file_data = res.json() 

140 if "Content" not in file_data: 

141 logger.error("WS-EDI {} Content block missing: {}".format(command, file_data)) 

142 raise Exception("WS-EDI {} Content block missing".format(command)) 

143 bcontent = base64.b64decode(file_data["Content"]) 

144 with open(file_path, "wb") as fp: 

145 fp.write(bcontent) 

146 logger.info("Wrote file {}".format(file_path)) 

147 

148 # process selected files immediately 

149 if options["process_pain002"] and file_type in ["XP", "pain.002.001.03", "NDCORPAYL"]: 

150 process_pain002_file_content(bcontent, file_path, created=time_now) 

151 else: 

152 print("Skipping old file {}".format(file_path)) 

153 else: 

154 print("Empty file list downloaded") 

155 elif command == "DownloadFile": 

156 bcontent = base64.b64decode(data["Content"]) 

157 file_path = os.path.join(path, file_reference) 

158 if options["overwrite"] or not os.path.isfile(file_path): 

159 with open(file_path, "wb") as fp: 

160 fp.write(bcontent) 

161 logger.info("Wrote file {}".format(file_path)) 

162 else: 

163 print("Skipping old file {}".format(file_path))