23
23
use Civi \Funding \FundingAttachmentManagerInterface ;
24
24
use Civi \Funding \PayoutProcess \DrawdownManager ;
25
25
use CRM_Funding_ExtensionUtil as E ;
26
+ use setasign \Fpdi \Fpdi ;
26
27
use Symfony \Component \HttpFoundation \BinaryFileResponse ;
28
+ use Symfony \Component \HttpFoundation \HeaderUtils ;
27
29
use Symfony \Component \HttpFoundation \Request ;
28
30
use Symfony \Component \HttpFoundation \Response ;
29
31
use Symfony \Component \HttpFoundation \ResponseHeaderBag ;
30
32
use Symfony \Component \HttpKernel \Exception \AccessDeniedHttpException ;
31
33
use Symfony \Component \HttpKernel \Exception \BadRequestHttpException ;
32
34
use Symfony \Component \HttpKernel \Exception \NotFoundHttpException ;
35
+ use Tomsgu \PdfMerger \PdfCollection ;
36
+ use Tomsgu \PdfMerger \PdfFile ;
37
+ use Tomsgu \PdfMerger \PdfMerger ;
33
38
34
39
final class DrawdownDocumentDownloadController implements PageControllerInterface {
35
40
@@ -47,6 +52,19 @@ public function __construct(FundingAttachmentManagerInterface $attachmentManager
47
52
* @throws \CRM_Core_Exception
48
53
*/
49
54
public function handle (Request $ request ): Response {
55
+ if ($ request ->query ->has ('drawdownIds ' )) {
56
+ $ drawdownIds = (string ) $ request ->query ->get ('drawdownIds ' );
57
+
58
+ if (preg_match ('/^[1-9][0-9]*(,[1-9][0-9]*)*$/ ' , $ drawdownIds ) !== 1 ) {
59
+ throw new BadRequestHttpException ('Invalid drawdown IDs ' );
60
+ }
61
+
62
+ $ drawdownIds = array_map (fn (string $ id ) => (int ) $ id , explode (', ' , $ drawdownIds ));
63
+ /** @phpstan-var list<int> $drawdownIds */
64
+
65
+ return $ this ->downloadMultiple ($ drawdownIds );
66
+ }
67
+
50
68
$ drawdownId = $ request ->query ->get ('drawdownId ' );
51
69
52
70
if (!is_numeric ($ drawdownId )) {
@@ -92,4 +110,46 @@ private function download(int $drawdownId): Response {
92
110
->setMaxAge (300 );
93
111
}
94
112
113
+ /**
114
+ * @phpstan-param list<int> $drawdownIds
115
+ *
116
+ * @throws \CRM_Core_Exception
117
+ * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
118
+ * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
119
+ */
120
+ private function downloadMultiple (array $ drawdownIds ): Response {
121
+ $ pdfCollection = new PdfCollection ();
122
+ foreach ($ drawdownIds as $ drawdownId ) {
123
+ $ drawdown = $ this ->drawdownManager ->get ($ drawdownId );
124
+ if (NULL === $ drawdown ) {
125
+ throw new AccessDeniedHttpException ();
126
+ }
127
+
128
+ $ attachment = $ this ->attachmentManager ->getLastByFileType (
129
+ 'civicrm_funding_drawdown ' ,
130
+ $ drawdownId ,
131
+ $ drawdown ->getAmount () < 0 ? FileTypeNames::PAYBACK_CLAIM : FileTypeNames::PAYMENT_INSTRUCTION ,
132
+ );
133
+
134
+ if (NULL === $ attachment ) {
135
+ throw new NotFoundHttpException ("Drawdown document (ID: $ drawdownId) does not exist " );
136
+ }
137
+
138
+ $ pdfCollection ->addPdf ($ attachment ->getPath ());
139
+ }
140
+
141
+ $ filename = E::ts ('payment-instructions ' ) . '.pdf ' ;
142
+ $ headers = [
143
+ 'Content-Type ' => 'application/pdf ' ,
144
+ 'Content-Disposition ' => HeaderUtils::makeDisposition (HeaderUtils::DISPOSITION_INLINE , $ filename ),
145
+ ];
146
+
147
+ $ merger = new PdfMerger (new Fpdi ());
148
+ return (new Response (
149
+ $ merger ->merge ($ pdfCollection , $ filename , PdfMerger::MODE_STRING , PdfFile::ORIENTATION_AUTO_DETECT ),
150
+ 200 ,
151
+ $ headers
152
+ ))->setMaxAge (300 );
153
+ }
154
+
95
155
}
0 commit comments