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
« 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
23logger = logging.getLogger(__name__)
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 """
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")
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))
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)
58 for p in list(payouts.order_by("id").distinct()):
59 assert isinstance(p, Payout)
60 try:
61 if options["verbose"]:
62 print(p)
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"])
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 )
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"])
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 )