blob: 2cdb88edfc777f244f8098de44d39161d9cdbd50 [file] [log] [blame]
arseniy.sorokinbdf2def2023-10-05 00:05:32 +02001package pl.hackerspace.service;
2
3import jakarta.servlet.http.HttpServletResponse;
4import lombok.RequiredArgsConstructor;
5import lombok.extern.slf4j.Slf4j;
6import org.springframework.core.io.ByteArrayResource;
7import org.springframework.core.io.InputStreamResource;
8import org.springframework.core.io.Resource;
9import org.springframework.http.ContentDisposition;
10import org.springframework.http.HttpHeaders;
11import org.springframework.http.MediaType;
12import org.springframework.http.ResponseEntity;
13import org.springframework.stereotype.Service;
14import org.springframework.transaction.annotation.Transactional;
15import org.springframework.util.StreamUtils;
16import pl.hackerspace.domain.Client;
17import pl.hackerspace.domain.Invoice;
18import pl.hackerspace.dto.CustomInvoiceDataDto;
19import pl.hackerspace.dto.InvoiceGenerationDto;
20import pl.hackerspace.repository.ClientRepository;
21import pl.hackerspace.repository.InvoiceRepository;
22
23import java.io.BufferedInputStream;
24import java.io.ByteArrayInputStream;
25import java.io.IOException;
26import java.io.InputStream;
27import java.nio.charset.StandardCharsets;
28import java.time.LocalDate;
29import java.time.LocalDateTime;
30import java.time.format.DateTimeFormatter;
31import java.util.List;
32import java.util.zip.ZipEntry;
33import java.util.zip.ZipOutputStream;
34
35import static pl.hackerspace.service.TemplateService.withTemplate;
36
37@Slf4j
38@Service
39@RequiredArgsConstructor
40public class InvoiceService {
41
42 private final ClientRepository clientRepository;
43
44 private final InvoiceRepository invoiceRepository;
45
46 @Transactional
47 public ResponseEntity<Resource> generateNewInvoice(InvoiceGenerationDto generationRequest) throws IOException {
48 Client client = clientRepository.findById(generationRequest.getNip()).orElseThrow(() -> new RuntimeException("Not found"));
49 return withTemplate(template -> {
50 byte[] invoice;
51 if (!client.isSubscriber() || generationRequest.getCustomInvoiceData() != null) {
52 invoice = createPdfInvoice(client, template, null, generationRequest.getCustomInvoiceData());
53 } else {
54 invoice = getOrCreateSubscriptionPdfInvoice(template, client, generationRequest.getMonthOfInvoice());
55 }
56 return ResponseEntity.ok()
57 .headers(getHttpHeaders(client.getName() + " " + generationRequest.getMonthOfInvoice()))
58 .contentLength(-1)
59 .contentType(MediaType.APPLICATION_PDF)
60 .body(new ByteArrayResource(invoice));
61 });
62 }
63
64
65 @Transactional
66 public void generateInvoicesForAllSubscribers(HttpServletResponse response, String monthOfInvoice) throws IOException {
67 setHeaders(response, "application/zip", LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE) + ".zip");
68 List<Client> subscribers = clientRepository.findBySubscriberTrue();
69 withTemplate(template -> {
70 try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
71 for (Client client : subscribers) {
72 try (InputStream inputStream = new ByteArrayInputStream(
73 getOrCreateSubscriptionPdfInvoice(template, client, monthOfInvoice))) {
74 zipOutputStream.putNextEntry(new ZipEntry(getPdfFilename(client.getName() + " "
75 + monthOfInvoice)));
76 StreamUtils.copy(inputStream, zipOutputStream);
77 zipOutputStream.flush();
78 }
79 }
80 } catch (IOException e) {
81 throw new RuntimeException(e);
82 }
83 return null;
84 });
85 }
86
87 private byte[] getOrCreateSubscriptionPdfInvoice(String template, Client client, final String monthOfInvoice) {
88 byte[] invoice = client.getInvoiceForSubscriptionMonth(monthOfInvoice);
89 if (invoice == null) {
90 invoice = createPdfInvoice(client, template, monthOfInvoice, null);
91 }
92 return invoice;
93 }
94
95 private static void setHeaders(HttpServletResponse response, String contentType, String filename) {
96 response.setContentType(contentType);
97 response.setHeader(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.attachment()
98 .filename(filename, StandardCharsets.UTF_8)
99 .build()
100 .toString());
101 }
102
103 private byte[] createPdfInvoice(Client client, String template, String monthOfSubscription,
104 CustomInvoiceDataDto customInvoiceData) {
105 LocalDateTime creationDate = LocalDateTime.now();
106 Invoice newInvoice = createNewInvoice(client, creationDate, monthOfSubscription);
107 byte[] bytes = TemplateService.convertHtmlToPdf(template, client, creationDate,
108 newInvoice.getInvoiceTitle(), monthOfSubscription, customInvoiceData);
109 newInvoice.setPdfContent(bytes);
110 save(newInvoice);
111 return bytes;
112 }
113
114 private static HttpHeaders getHttpHeaders(final String filename) {
115 HttpHeaders headers = new HttpHeaders();
116 headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);
117 headers.add(HttpHeaders.CONTENT_TYPE, "application/octet-stream");
118 headers.add(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=" + getPdfFilename(filename));
119 return headers;
120 }
121
122 private static String getPdfFilename(String filename) {
123 return filename + ".pdf";
124 }
125
126 public Invoice createNewInvoice(Client client, final LocalDateTime creationDate, String monthOfSubscription) {
127 long nextInvoiceId = invoiceRepository.getMaxId() + 1;
128 return Invoice.builder().id(nextInvoiceId)
129 .invoiceTitle("FV" + nextInvoiceId)
130 .creationDate(creationDate)
131 .monthOfSubscription(monthOfSubscription)
132 .client(client)
133 .build();
134 }
135
136 public void save(Invoice newInvoice) {
137 invoiceRepository.save(newInvoice);
138 }
139
140 public List<Invoice> findAll() {
141 return invoiceRepository.findAll();
142 }
143}