Coverage for jbank/management/commands/make_pain001.py: 0%

66 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-27 13:36 +0700

1# pylint: disable=logging-format-interpolation 

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): # pylint: disable=too-many-branches 

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.order_by("id").distinct()): 

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 = PAIN001_REMITTANCE_INFO_OCR_ISO if remittance_info[:2] == "RF" else PAIN001_REMITTANCE_INFO_OCR 

87 pain001.add_payment( 

88 p.msg_id, 

89 p.recipient.name, 

90 p.recipient.account_number, 

91 p.recipient.bic, 

92 p.amount, 

93 remittance_info, 

94 remittance_info_type, 

95 p.due_date, 

96 ) 

97 

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

99 if options["verbose"]: 

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

101 pain001.render_to_file(full_path) 

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

103 p.state = PAYOUT_WAITING_UPLOAD 

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

105 

106 PayoutStatus.objects.create(payout=p, file_name=p.file_name, msg_id=p.msg_id, status_reason="File generation OK") 

107 except Exception as e: 

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

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

110 logger.error(long_err) 

111 p.state = PAYOUT_ERROR 

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

113 PayoutStatus.objects.create( 

114 payout=p, 

115 group_status=PAYOUT_ERROR, 

116 file_name=p.file_name, 

117 msg_id=p.msg_id, 

118 status_reason=short_err[:255], 

119 )