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

2import logging 

3import os 

4import traceback 

5from django.core.management.base import CommandParser 

6from jbank.models import ( 

7 Payout, 

8 PAYOUT_ERROR, 

9 PAYOUT_WAITING_PROCESSING, 

10 PayoutStatus, 

11 PAYOUT_WAITING_UPLOAD, 

12 WsEdiConnection, 

13) 

14from jbank.sepa import ( 

15 Pain001, 

16 PAIN001_REMITTANCE_INFO_MSG, 

17 PAIN001_REMITTANCE_INFO_OCR_ISO, 

18 PAIN001_REMITTANCE_INFO_OCR, 

19) 

20from jutil.command import SafeCommand 

21 

22 

23logger = logging.getLogger(__name__) 

24 

25 

26class Command(SafeCommand): 

27 help = """ 

28 Generates pain.001.001.03 compatible SEPA payment files from pending Payout objects. 

29 By default generates files of Payouts in WAITING_PROCESSING state. 

30 """ 

31 

32 def add_arguments(self, parser: CommandParser): 

33 parser.add_argument("dir", type=str) 

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

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

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

37 parser.add_argument("--suffix", type=str, default="XL") 

38 parser.add_argument("--xml-declaration", action="store_true") 

39 

40 def do(self, *args, **options): 

41 target_dir = options["dir"] 

42 if options["verbose"]: 

43 logger.info("Writing pain.001 files to {}".format(target_dir)) 

44 

45 payouts = Payout.objects.all() 

46 if options["payout"]: 

47 payouts = Payout.objects.filter(id=options["payout"]) 

48 else: 

49 payouts = payouts.filter(state=PAYOUT_WAITING_PROCESSING) 

50 if options["ws"]: 

51 ws = WsEdiConnection.objects.get(id=options["ws"]) 

52 assert isinstance(ws, WsEdiConnection) 

53 if ws and not ws.enabled: 

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

55 return 

56 payouts = payouts.filter(connection=ws) 

57 

58 for p in list(payouts): 

59 assert isinstance(p, Payout) 

60 try: 

61 if options["verbose"]: 

62 print(p) 

63 

64 if not p.msg_id: 

65 p.generate_msg_id() 

66 if not p.file_name: 

67 p.file_name = p.msg_id + "." + options["suffix"] 

68 p.save(update_fields=["file_name"]) 

69 

70 pain001 = Pain001( 

71 p.msg_id, 

72 p.payer.name, 

73 p.payer.account_number, 

74 p.payer.bic, 

75 p.payer.org_id, 

76 p.payer.address_lines, 

77 p.payer.country_code, 

78 ) 

79 if options["xml_declaration"]: 

80 pain001.xml_declaration = options["xml_declaration"] 

81 if p.messages: 

82 remittance_info = p.messages 

83 remittance_info_type = PAIN001_REMITTANCE_INFO_MSG 

84 else: 

85 remittance_info = p.reference 

86 remittance_info_type = ( 

87 PAIN001_REMITTANCE_INFO_OCR_ISO if remittance_info[:2] == "RF" else PAIN001_REMITTANCE_INFO_OCR 

88 ) 

89 pain001.add_payment( 

90 p.msg_id, 

91 p.recipient.name, 

92 p.recipient.account_number, 

93 p.recipient.bic, 

94 p.amount, 

95 remittance_info, 

96 remittance_info_type, 

97 p.due_date, 

98 ) 

99 

100 p.full_path = full_path = os.path.join(target_dir, p.file_name) 

101 if options["verbose"]: 

102 print(p, "written to", full_path) 

103 pain001.render_to_file(full_path) 

104 logger.info("{} generated".format(full_path)) 

105 p.state = PAYOUT_WAITING_UPLOAD 

106 p.save(update_fields=["full_path", "state"]) 

107 

108 PayoutStatus.objects.create( 

109 payout=p, file_name=p.file_name, msg_id=p.msg_id, status_reason="File generation OK" 

110 ) 

111 except Exception as e: 

112 short_err = "File generation failed: " + str(e) 

113 long_err = "File generation failed ({}): ".format(p.file_name) + traceback.format_exc() 

114 logger.error(long_err) 

115 p.state = PAYOUT_ERROR 

116 p.save(update_fields=["state"]) 

117 PayoutStatus.objects.create( 

118 payout=p, 

119 group_status=PAYOUT_ERROR, 

120 file_name=p.file_name, 

121 msg_id=p.msg_id, 

122 status_reason=short_err[:255], 

123 )