arseniy.sorokin | bdf2def | 2023-10-05 00:05:32 +0200 | [diff] [blame] | 1 | package pl.hackerspace.service; |
| 2 | |
| 3 | import jakarta.servlet.http.HttpServletResponse; |
| 4 | import lombok.RequiredArgsConstructor; |
| 5 | import lombok.extern.slf4j.Slf4j; |
| 6 | import org.springframework.core.io.ByteArrayResource; |
| 7 | import org.springframework.core.io.InputStreamResource; |
| 8 | import org.springframework.core.io.Resource; |
| 9 | import org.springframework.http.ContentDisposition; |
| 10 | import org.springframework.http.HttpHeaders; |
| 11 | import org.springframework.http.MediaType; |
| 12 | import org.springframework.http.ResponseEntity; |
| 13 | import org.springframework.stereotype.Service; |
| 14 | import org.springframework.transaction.annotation.Transactional; |
| 15 | import org.springframework.util.StreamUtils; |
| 16 | import pl.hackerspace.domain.Client; |
| 17 | import pl.hackerspace.domain.Invoice; |
| 18 | import pl.hackerspace.dto.CustomInvoiceDataDto; |
| 19 | import pl.hackerspace.dto.InvoiceGenerationDto; |
| 20 | import pl.hackerspace.repository.ClientRepository; |
| 21 | import pl.hackerspace.repository.InvoiceRepository; |
| 22 | |
| 23 | import java.io.BufferedInputStream; |
| 24 | import java.io.ByteArrayInputStream; |
| 25 | import java.io.IOException; |
| 26 | import java.io.InputStream; |
| 27 | import java.nio.charset.StandardCharsets; |
| 28 | import java.time.LocalDate; |
| 29 | import java.time.LocalDateTime; |
| 30 | import java.time.format.DateTimeFormatter; |
| 31 | import java.util.List; |
| 32 | import java.util.zip.ZipEntry; |
| 33 | import java.util.zip.ZipOutputStream; |
| 34 | |
| 35 | import static pl.hackerspace.service.TemplateService.withTemplate; |
| 36 | |
| 37 | @Slf4j |
| 38 | @Service |
| 39 | @RequiredArgsConstructor |
| 40 | public 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 | } |