invoiceninja / dockerfiles

Docker files for Invoice Ninja
https://hub.docker.com/r/invoiceninja/invoiceninja
GNU General Public License v2.0
420 stars 268 forks source link

PDF creation loads forever #255

Closed axldd closed 3 years ago

axldd commented 3 years ago

When trying to generate the PDF view of an invoice, it won't show up and show the loading wheel spinning forever. If I check the "delivery note" box, the delivery note PDF shows up immediately.

I am running the Dockerfile v5.0.44 via docker-compose and did a migration from 4.5.27 after the initial setup. The container is accessed through an Apache reverse proxy which handles SSL.

The logs at docker/app/storage/logs/laravel.log show no output.

Edit: It should be "reverse" proxy, not "remote". It was late...

turbo124 commented 3 years ago

This sounds like a DNS resolution issue for the chrome PDF generator.

If you are running this locally (ie not on a public facing DNS resolvable address) then you will see failures unless you use a .test domain

axldd commented 3 years ago

The DNS name is resolvable from both inside and outside my network. It does though resolve to the HTTP reverse proxy, not the Docker host. Also I'm a bit confused because the delivery notes are being generated as expected. Can I find logs for the PDF generator at any point?

turbo124 commented 3 years ago

from inside the container, can you try curl http://your.url.com

axldd commented 3 years ago

From the app container this gives me HTML output:


<html data-report-errors="0">
<head>
    <!-- Source: https://github.com/invoiceninja/invoiceninja -->
    <!-- Version: 5.0.44 -->
  <meta charset="UTF-8">
  <title>Invoice Ninja</title>
  <meta name="google-signin-client_id" content="">
  <link rel="manifest" href="manifest.json?v=5.0.44">
</head>
<body style="background-color:#888888;">

  <style>

    /* fix for blurry fonts 
    flt-glass-pane {
        image-rendering: pixelated;
    }
    */

    /* https://projects.lukehaas.me/css-loaders/ */
    .loader,
    .loader:before,
    .loader:after {
      border-radius: 50%;
      width: 2.5em;
      height: 2.5em;
      -webkit-animation-fill-mode: both;
      animation-fill-mode: both;
      -webkit-animation: load7 1.8s infinite ease-in-out;
      animation: load7 1.8s infinite ease-in-out;
    }
    .loader {
      color: #ffffff;
      font-size: 10px;
      margin: 80px auto;
      position: relative;
      text-indent: -9999em;
      -webkit-transform: translateZ(0);
      -ms-transform: translateZ(0);
      transform: translateZ(0);
      -webkit-animation-delay: -0.40s;
      animation-delay: -0.40s;
    }
    .loader:before,
    .loader:after {
      content: '';
      position: absolute;
      top: 0;
    }
    .loader:before {
      left: -3.5em;
      -webkit-animation-delay: -0.80s;
      animation-delay: -0.80s;
    }
    .loader:after {
      left: 3.5em;
    }
    @-webkit-keyframes load7 {
      0%,
      80%,
      100% {
        box-shadow: 0 2.5em 0 -1.3em;
      }
      40% {
        box-shadow: 0 2.5em 0 0;
      }
    }
    @keyframes  load7 {
      0%,
      80%,
      100% {
        box-shadow: 0 2.5em 0 -1.3em;
      }
      40% {
        box-shadow: 0 2.5em 0 0;
      }
    }

  </style>

  <script>

    if ('serviceWorker' in navigator) {
      window.addEventListener('load', function () {
        navigator.serviceWorker.register('flutter_service_worker.js?v=5.0.44');
      });
    }

    document.addEventListener('DOMContentLoaded', function(event) {
      document.getElementById('loader').style.display = 'none';
    });

    function invokeServiceWorkerUpdateFlow() {
      // you have a better UI here, reloading is not a great user experince here.
      const confirmed = confirm('New version of the app is available. Refresh now');
      if (confirmed) {
        window.location.reload();
      }
    }
    async function handleServiceWorker() {
      if ('serviceWorker' in navigator) {
        // get the ServiceWorkerRegistration instance
        const registration = await navigator.serviceWorker.getRegistration();
        // (it is also returned from navigator.serviceWorker.register() function)

        if (registration) {
          // detect Service Worker update available and wait for it to become installed
          registration.addEventListener('updatefound', () => {
            if (registration.installing) {
              // wait until the new Service worker is actually installed (ready to take over)
              registration.installing.addEventListener('statechange', () => {
                if (registration.waiting) {
                  // if there's an existing controller (previous Service Worker), show the prompt
                  if (navigator.serviceWorker.controller) {
                    invokeServiceWorkerUpdateFlow(registration);
                  } else {
                    // otherwise it's the first install, nothing to do
                    console.log('Service Worker initialized for the first time');
                  }
                }
              });
            }
          });

          let refreshing = false;

          // detect controller change and refresh the page
          navigator.serviceWorker.addEventListener('controllerchange', () => {
            if (!refreshing) {
              window.location.reload();
              refreshing = true;
            }
          });
        }
      }
    }

    handleServiceWorker();

  </script>

  <script defer src="main.dart.js?v=5.0.44" type="application/javascript"></script>

  <center style="padding-top: 150px" id="loader">
    <div class="loader"></div>
  </center>

</body>```
turbo124 commented 3 years ago

Also I'm a bit confused because the delivery notes are being generated as expected. Can I find logs for the PDF generator at any point?

storage/logs/laravel.log will give more info.

axldd commented 3 years ago

Unfortunately, there are no logs about the PDF creation at this location..

turbo124 commented 3 years ago

ok, can you please add this to your .env file

LOG_PDF_HTML=true

and then run

php artisan optimize

this will output the contents of the HTML prior to PDF generation

axldd commented 3 years ago

Thanks for the answer! I added the line to .env and ran the command. When I try to generate a PDF invoice, there is still no output. The configuration itself seems to work, when I tick the box for a delivery note it immediately shows the HTML of the document (just pasting the first line here):

[2021-01-09 10:45:06] production.INFO: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">

I have the same behaviour when trying to creat an offer or credit.

turbo124 commented 3 years ago

@axldd

I'm not sure, one thing to check is to see is the PDF is actually generating. you should see PDFS in

The directory

/public/storage/{hash}/{hash}/invoices

This will help us work out where the failure is happening.

axldd commented 3 years ago

Here, the delivery notes show up:

# ls docker/app/public/storage/o7c0cpc2jafthb6ykowgccbd2ewl6p7z/*/invoices
docker/app/public/storage/o7c0cpc2jafthb6ykowgccbd2ewl6p7z/Ew91GQrsXc3JwbTg4BuvMlaoGN4jKt0SDLdhgT2b/invoices:
'0196_Gel'$'\303\266''scht.pdf'   999999999999999_delivery_note.pdf   R0199_delivery_note.pdf

docker/app/public/storage/o7c0cpc2jafthb6ykowgccbd2ewl6p7z/IkVj1mj2BtwQtZRygtg8pWExiQTz4isRhuI5n4GS/invoices:
0194_delivery_note.pdf

docker/app/public/storage/o7c0cpc2jafthb6ykowgccbd2ewl6p7z/NIa7P2DtpP9lsE9W2HiEIpi3k4R2RzGErOtwelLO/invoices:
0200_delivery_note.pdf

The strange looking file is actually an invoice which I have deleted at the very beginning of my tests so at some point it seems like it was able to generate them. The acutal name of the file is "0196_Gelöscht.pdf", Gelöscht means deleted. I don't know if it is related to my error though. Thanks again for your effort to help me!

turbo124 commented 3 years ago

Hi @axldd

Just to confirm, you can consistently produce delivery notes, but not invoice pdfs

axldd commented 3 years ago

Exactly! Only delivery notes work, invoices, credits or offers don't.

turbo124 commented 3 years ago

@beganovich any thoughts on this? I wonder if it is the filename that is causing the failure? @axldd is it simple enough to try a different localization.

axldd commented 3 years ago

I have tried to change currency format and language, it did not change the behaviour. I also tried to generate an invoice with the "untitled company" that was initially created before my import from v4 but unfortunately still no PDF generation for invoices.

szamengo commented 3 years ago

I have the same behaviour! Delivery notes works but not invoices... I have .test url

beganovich commented 3 years ago

Hey there, thanks for reporting this I'll have to check this & will let you know here in the thread asap. Thanks!

turbo124 commented 3 years ago

I can recreate this issue if the APP_URL set in the env file is incorrect

image

axldd commented 3 years ago

@turbo124 Thanks for the hint with the network tab of the browsers developer console! When I am trying to generate the PDF, I can see a "blocked" log entry:

Blocked loading mixed active content “http://my.tld/client/invoice/g56qyj8zusxqgjgy8yutdd8apfzrcwjc/download_pdf”

It is trying to access my domain through http even though I have APP_URL=https://my.tld in my .env file. Still, if I copy and paste the link directly into the browser, I finally get to see my invoice (but not in the design I have chosen in the options)...

I don't have https enabled on the Docker host itself. It is running http mapped to a custom port and the proxy to which the domain name resolves handles the SSL part, maybe this is a useful information.

beganovich commented 3 years ago

@turbo124 so issue isn't with pdfs itself, but loading them?

turbo124 commented 3 years ago

@axldd I think you may be referencing the incorrect app_url, you'll want to ensure the correct APP_URL is set in the env file in the same directory as the docker-compose.yml file rather than the one in the volume.

@beganovich it is both as chrome also wont resolve the address also. I'm sure this is a APP_URL issue.

szamengo commented 3 years ago

Dear David, nice it works!

The only issue, for me, is the logo link .... it links to http://in5.test//storage/KYLswtTayCoiupogVG3Q0Hm5AJgcbwGxPb6T4rPuNBnKfu8OKVYL7qsAYOoRLjbH/E8Bt6znzcXjwwuNpFnK62Tx5b9g3p932a6TZkmua.png

instead of http://in5.test:8003/storage/KYLswtTayCoiupogVG3Q0Hm5AJgcbwGxPb6T4rPuNBnKfu8OKVYL7qsAYOoRLjbH/E8Bt6znzcXjwwuNpFnK62Tx5b9g3p932a6TZkmua.png

Thank you Silvia

turbo124 commented 3 years ago

right, you may need to reupload the logo as the url is saved to the settings and doesn't autoupdate.

szamengo commented 3 years ago

Dear David,

super! Very great job, it works also in email sending!

Thank you very much! Silvia

beganovich commented 3 years ago

Hey @axldd can you please check if the solution David provided works for you, so we can close this issue? Thanks!

axldd commented 3 years ago

Unfortunately I can't confirm. My APP_URL is correctly set in the env file in the directory with the docker-compose.yaml and it does also show up in the .env file in the app container. May it be some issue with my reverse proxy?

turbo124 commented 3 years ago

@axldd most likely an issue with the reverse proxy

I am wondering if you need to setup TRUSTED_PROXIES in the .env file? https://github.com/invoiceninja/dockerfiles/issues/14

beganovich commented 3 years ago

I had a same issue & the following worked for me:

If this still doesn't work for you please check #14 and please check the Network tab of your browser. It will tell you at least status code of loading the resource.

axldd commented 3 years ago

Thanks again for all your guys' effort to help! I have one general question about the usage of the docker file, sorry if it should be obvious: When I am supposed to change the .env, shall I do it in the env file in the directory where the docker-compose.yaml lives on the host or inside the container itself? Anyhow, I have tried to set REQUIRE_HTTPS=true and TRUSTED_PROXIES=<proxy-ip> both ways, but the outcome remains the same :( The browsers network tab still shows Blocked loading mixed active content “http://<my.tld>/client/invoice/g56qyj8zusxqgjgy8yutdd8apfzrcwjc/download_pdf” I don't know why it tries to access the site via http because the URL is set to https in both the .env file inside the conainter as well as the env file on the host.

beganovich commented 3 years ago

For Docker users, they should use env file (https://github.com/invoiceninja/dockerfiles/blob/master/env).

After any change of env variable, it is required to run:

docker-compose exec app php artisan optimize

Please try that & let us know!

axldd commented 3 years ago

Thanks for the clarification. I added

REQUIRE_HTTPS=true
TRUSTED_PROXIES=<proxy-ip>

to the env file and ran php artisan optimize inside the app container. It still gives me the Blocked loading mixed active content error.

Edit: I have also tried it with another browser (Chromium), it also shows an error message.

beganovich commented 3 years ago

Sorry to repeat myself, but what's value of APP_URL?

hillelcoren commented 3 years ago

Just to add... this post has a few tips for dealing with a proxy

https://forum.invoiceninja.com/t/selfhosting-setup-failing/5651/2

axldd commented 3 years ago

Sorry to repeat myself, but what's value of APP_URL?

It is set to "https://my.tld".

turbo124 commented 3 years ago

@axldd not sure what else to suggest honestly. I'm not that strong at debugging a reverse proxy setup.

hillelcoren commented 3 years ago

Did you have a chance to review the link I posted?

Some possible solutions to try are:

axldd commented 3 years ago

Thank you for the hints! I did set TRUSTED_PROXIES to '*' but it did not help. Unfortunately I am using Apache and not NGINX as a reverse proxy but I will try to find the equivalent settings in Apache, apply them and keep you posted :)

turbo124 commented 3 years ago

@axldd if you have a breakthrough please update us here.

morbidpete84 commented 3 years ago

Thank you for the hints! I did set TRUSTED_PROXIES to '*' but it did not help. Unfortunately I am using Apache and not NGINX as a reverse proxy but I will try to find the equivalent settings in Apache, apply them and keep you posted :)

I had the same issue and came across this post. Wanted to update to say that adding the dockers invoiceninja network subnet to the trusted proxy fixed it for me along with the form submission issue I had when approving a quote in the portal.