Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PDF not attached for recurring invoices #39

Closed
cinemast opened this issue Feb 4, 2017 · 26 comments
Closed

PDF not attached for recurring invoices #39

cinemast opened this issue Feb 4, 2017 · 26 comments

Comments

@cinemast
Copy link
Contributor

@cinemast cinemast commented Feb 4, 2017

Hi!

I am facing an issue where the PDF is not attached to outgoing e-mails for recurring invoices.
If I resend it manually (even though it is already marked as sent) from the Invoices menu, the PDF gets attached.

I am using the latest self-hosted version with Docker. The local phatonjs setting is activated under E-Mail settings.

Looking at the error log revealed the following:

[2017-02-04 09:08:11] production.ERROR: PhantomJS - Failed to create pdf: Invalid URL provided: /view/zPjEACdpQmKIpoOiWt1b35bjUAZhFIJo?phantomjs=true {"context":"PHP","user_id":0,"account_id":0,"user_name":"","method":"GET","url":"http://localhost","user_agent":"","ip":"127.0.0.1","count":1} []
Could it be that the cron tries to access localhost which should actually be the web according to the example docker-compose file?

Update:
I just tried executing ./artisan ninja:send-invoices from the app container which gives the same result.

Can someone help me out here?

@cinemast

This comment has been minimized.

Copy link
Contributor Author

@cinemast cinemast commented Feb 4, 2017

@hillelcoren

This comment has been minimized.

Copy link
Member

@hillelcoren hillelcoren commented Feb 4, 2017

What value do you have for APP_URL in the .env file?

@cinemast

This comment has been minimized.

Copy link
Contributor Author

@cinemast cinemast commented Feb 4, 2017

http://<name_of_the_web_container> it is also reachable through ping from the cron container.

@hillelcoren

This comment has been minimized.

Copy link
Member

@hillelcoren hillelcoren commented Feb 4, 2017

In the other issue you wrote "That does remove the error from the log but the PDF is still not attached".

To clarify, with APP_URL set are you still seeing Failed to create pdf: Invalid URL provided: /view/zPjEACdpQmKIpoOiWt1b35bjUAZhFIJo?phantomjs=true

@cinemast

This comment has been minimized.

Copy link
Contributor Author

@cinemast cinemast commented Feb 4, 2017

No, the error message is gone with setting the APP_URL but the PDF is still not attached to the outgoing mail.

Thanks for your support.

@hillelcoren

This comment has been minimized.

Copy link
Member

@hillelcoren hillelcoren commented Feb 4, 2017

I'm not sure, I think you'll need to debug the code.

You can add dd($response->getContent()); at the end of app/Libraries/CurlUtils.php to see what's being returned by PhantomJS.

@cinemast

This comment has been minimized.

Copy link
Contributor Author

@cinemast cinemast commented Feb 5, 2017

It returns a lot of HTML code. I var_dumped the request and response:

/artisan ninja:send-invoices
2017-02-05 Running SendRecurringInvoices...
4 recurring invoice(s) found
Processing Invoice 15 - Should send NO
Processing Invoice 17 - Should send NO
Processing Invoice 19 - Should send NO
Processing Invoice 21 - Should send YES
Sending Invoice
object(JonnyW\PhantomJs\Http\Request)#1542 (10) {
  ["type":protected]=>
  NULL
  ["headers":protected]=>
  array(0) {
  }
  ["data":protected]=>
  array(0) {
  }
  ["url":protected]=>
  string(67) "http://crm-web/view/hF6gz61DQsL9G0MKLRFhqt1p204hoJhK?phantomjs=true"
  ["method":protected]=>
  string(3) "GET"
  ["timeout":protected]=>
  int(5000)
  ["delay":protected]=>
  int(0)
  ["viewportWidth":protected]=>
  int(0)
  ["viewportHeight":protected]=>
  int(0)
  ["bodyStyles":protected]=>
  array(0) {
  }
}
object(JonnyW\PhantomJs\Http\Response)#1693 (8) {
  ["headers"]=>
  array(9) {
    ["Server"]=>
    string(12) "nginx/1.10.2"
    ["Content-Type"]=>
    string(24) "text/html; charset=UTF-8"
    ["Transfer-Encoding"]=>
    string(7) "chunked"
    ["Connection"]=>
    string(10) "keep-alive"
    ["X-Powered-By"]=>
    string(10) "PHP/7.0.15"
    ["Cache-Control"]=>
    string(8) "no-cache"
    ["Date"]=>
    string(29) "Sun, 05 Feb 2017 07:54:04 GMT"
    ["Set-Cookie"]=>
    string(716) "XSRF-TOKEN=eyJpdiI6IlNhMStpaUJoZ25Ed0szV29uaWJxdUE9PSIsInZhbHVlIjoiM1wvamZKdjJIdkVUYmtBT2daNkpRMzN4eW0zbnNhUnA4M043SSs3UW9YZlVcL1ErZlpyanE0Tml2Q1dWSDNpdVh5S2p2RHNQZXplcVF3NkZQKzYrdUFkdz09IiwibWFjIjoiYjg0MGJhNmNiMzk1ZDg5NDRjYzMwMzgwMDBiMmRmZGRmY2Q3NDNiOTY2YWMyYzQ2OTk4YTFkNTE1NjM5ODMzMyJ9; expires=Sun, 05-Feb-2017 15:54:04 GMT; Max-Age=28800; path=/
ninja_session=eyJpdiI6IlA0WUY1WnNROWo2NjlWNThRelFKSGc9PSIsInZhbHVlIjoiNU1ZcTdjSnhLaGp0T1dIcUNYdTRLbDhwdXVDcG1lcmtrdFZiOHNHdmp0N3UyNEdLZ2JoRTN1RndFemZSSUtXMFR6UmhEYVN5MWZRV1hHK2JuS1F5VFE9PSIsIm1hYyI6IjNjMzMwM2FjNTI5NGRlODlmOGRmNDU1NDczNDRmYTA1MzlkYWJjODIxNWEyNDkxMmExODc4OWViYWNhMGVmYWEifQ%3D%3D; expires=Sun, 05-Feb-2017 15:54:04 GMT; Max-Age=28800; path=/; HttpOnly"
    ["Content-Encoding"]=>
    string(4) "gzip"
  }
  ["status"]=>
  int(200)
  ["content"]=>
  string(298797) "<head>
            <title>Kunden-Portal</title>
    
<!-- Source: https://github.com/invoiceninja/invoiceninja -->
<!-- Version: 3.0.3 -->

    <meta charset="utf-8">
    <meta property="og:site_name" content="Invoice Ninja">
    <meta property="og:url" content="http://crm-web">
    <meta property="og:title" content="Invoice Ninja">
    <meta property="og:image" content="http://crm-web/images/round_logo.png">
    <meta property="og:description" content="Simple, Intuitive Invoicing.">

    <!-- http://realfavicongenerator.net -->
    <link rel="apple-touch-icon" sizes="180x180" href="https://crm-web/apple-touch-icon.png">
    <link rel="icon" type="image/png" href="https://crm-web/favicon-32x32.png" sizes="32x32">
    <link rel="icon" type="image/png" href="https://crm-web/favicon-16x16.png" sizes="16x16">
    <link rel="manifest" href="https://crm-web/manifest.json">
    <link rel="mask-icon" href="https://crm-web/safari-pinned-tab.svg" color="#3bc65c">
    <link rel="shortcut icon" href="https://crm-web/favicon.ico">
    <meta name="apple-mobile-web-app-title" content="Invoice Ninja">
    <meta name="application-name" content="Invoice Ninja">
    <meta name="theme-color" content="#ffffff">........
....
</body>"
  ["contentType"]=>
  string(24) "text/html; charset=UTF-8"
  ["url"]=>
  string(67) "http://crm-web/view/hF6gz61DQsL9G0MKLRFhqt1p204hoJhK?phantomjs=true"
  ["redirectURL"]=>
  NULL
  ["time"]=>
  string(24) "2017-02-05T07:54:04.321Z"
  ["console"]=>
  array(5) {
    [0]=>
    array(2) {
      ["message"]=>
      string(38) "ReferenceError: Can't find variable: $"
      ["trace"]=>
      array(1) {
        [0]=>
        string(102) " -> http://crm-web/view/hF6gz61DQsL9G0MKLRFhqt1p204hoJhK?phantomjs=true: 103 (in function global code)"
      }
    }
    [1]=>
    array(2) {
      ["message"]=>
      string(38) "ReferenceError: Can't find variable: $"
      ["trace"]=>
      array(1) {
        [0]=>
        string(102) " -> http://crm-web/view/hF6gz61DQsL9G0MKLRFhqt1p204hoJhK?phantomjs=true: 284 (in function global code)"
      }
    }
    [2]=>
    array(2) {
      ["message"]=>
      string(38) "ReferenceError: Can't find variable: $"
      ["trace"]=>
      array(1) {
        [0]=>
        string(102) " -> http://crm-web/view/hF6gz61DQsL9G0MKLRFhqt1p204hoJhK?phantomjs=true: 370 (in function global code)"
      }
    }
    [3]=>
    array(2) {
      ["message"]=>
      string(38) "ReferenceError: Can't find variable: $"
      ["trace"]=>
      array(1) {
        [0]=>
        string(102) " -> http://crm-web/view/hF6gz61DQsL9G0MKLRFhqt1p204hoJhK?phantomjs=true: 413 (in function global code)"
      }
    }
    [4]=>
    array(2) {
      ["message"]=>
      string(38) "ReferenceError: Can't find variable: $"
      ["trace"]=>
      array(1) {
        [0]=>
        string(102) " -> http://crm-web/view/hF6gz61DQsL9G0MKLRFhqt1p204hoJhK?phantomjs=true: 668 (in function global code)"
      }
    }
  }
}
0 due recurring invoice instance(s) found
Done
@hillelcoren

This comment has been minimized.

Copy link
Member

@hillelcoren hillelcoren commented Feb 5, 2017

This link looks incorrect: http://crm-web/view/hF6gz61DQsL9G0MKLRFhqt1p204hoJhK?phantomjs=true

Does it work in your browser?

@cinemast

This comment has been minimized.

Copy link
Contributor Author

@cinemast cinemast commented Feb 12, 2017

The link works, yes. This is the name of the proxy container running the webserver.
Could you please try to reproduce this issue?

@hillelcoren

This comment has been minimized.

Copy link
Member

@hillelcoren hillelcoren commented Feb 13, 2017

I'm not seeing this problem, I think the next step would be trying to test the link manually using PhantomJS.

@lalop

This comment has been minimized.

Copy link
Member

@lalop lalop commented Feb 13, 2017

This link works from the container ?

@cinemast

This comment has been minimized.

Copy link
Contributor Author

@cinemast cinemast commented Feb 14, 2017

Yes, it does. Could this be related to invoiceninja/invoiceninja#1284?

@hillelcoren

This comment has been minimized.

Copy link
Member

@hillelcoren hillelcoren commented Feb 22, 2017

Are you requiring a password for the contact to access the portal?

We recently added a PHANTOMJS_SECRET option to the .env file, setting it will enable the app to bypass the contact password check.

@cinemast

This comment has been minimized.

Copy link
Contributor Author

@cinemast cinemast commented Feb 25, 2017

I figured out the problem. It is not about the phantomjs_secret.

Our instance is not public reachable, therefore we rely on the built-in phanotmjs implementation.
We have a tls-proxy in front of it with a self-signed CA.

PhatomJS then silently (without any error message) fails to create the PDF. It was rather hard to debug, so hopefully this issue might still be of help to other people using InvoiceNinja behind a self-signed TLS proxy.

Thank you for your support.

@cinemast cinemast closed this Feb 25, 2017
@cinemast

This comment has been minimized.

Copy link
Contributor Author

@cinemast cinemast commented Feb 25, 2017

In case anybody else needs to fix this, you have to add your CA into the trust-store of your docker host (copy it into /usr/local/share/ca-certificates for debian based distos).

The app and cron container, must mount the trust-store under /usr/local/share/ca-certificates directory then invoke update-ca-certificates --fresh command from the entrypoint.sh.

@glassbase

This comment has been minimized.

Copy link

@glassbase glassbase commented Mar 16, 2018

Hi,

Although this issue is closed, I wanted to post a comment here in hopes that it may help others with this issue.

I had my url set as http://myurl.com in my env file, yet I had my Invoice Ninja portal behind Lets Encrypt+nginx docker and the attachments were not attaching. I could download them fine.

All I had to do was set my url to https:// in env and the attachments attached. Seems weird since I have a http to https redirect in my nginx config, but anyways.

Cheers

@lalop

This comment has been minimized.

Copy link
Member

@lalop lalop commented Mar 16, 2018

THank you for your feedback.
That's interesting, maybe phantomjs dosen't follow redirection...

@nbyloff

This comment has been minimized.

Copy link

@nbyloff nbyloff commented May 15, 2018

I am stuck on this issue as well. I am also using docker with jwilder/nginx-proxy

What I have noticed is it hangs when doing wget:

root@018abd818a8b:~# wget https://ap.domain.com
--2018-05-15 21:38:32--  https://ap.domain.com/
Resolving ap.domain.com (ap.domain.com)... 11.22.33.44
Connecting to ap.domain.com (ap.domain.com)|11.22.33.44|:443... ^C
root@018abd818a8b:~# 

The IP address it resolves to ap.domain.com is correct. What it looks like I need to do is tell phantomjs to specifically use my internal docker container URL, which is http://web. That seems to resolve correctly.

Can I set a phantomjs only URL config with invoice ninja?

@nbyloff

This comment has been minimized.

Copy link

@nbyloff nbyloff commented May 15, 2018

I will add, I have tried both

http://web   #docker host name for internal nginx that works from the app container
https://ap.domain.com  # public DNS name

when I test using phantomjs resources/test.pjs with the http://web URL, I get contents returned. When using the https URL, it timesout.

So I figured setting this in my .env file would work

APP_URL="http://web"

But the /test_headless still fails. This is what is in the app log file:

ninja-proxy    | [15-May-2018 22:10:07] WARNING: [pool www] child 10 said into stderr: "[2018-05-15 22:10:07] production.ERROR: PhantomJS - Invalid response http://web/view/bk2bxfxuju7bd777zbxusrd5g6q5peg2?phantomjs=true&phantomjs_secret=:   {"context":"PHP","user_id":1,"account_id":1,"user_name":"Nathan Byloff","method":"GET","user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36","locale":"en","ip":"172.18.0.2","count":1,"is_console":"no","is_api":"no","db_server":"mysql","url":"test_headless"} []"
@hillelcoren

This comment has been minimized.

Copy link
Member

@hillelcoren hillelcoren commented May 16, 2018

Maybe you need to set a value for PHANTOMJS_SECRET in the .env file?

http://docs.invoiceninja.com/en/latest/configure.html#troubleshooting

@nbyloff

This comment has been minimized.

Copy link

@nbyloff nbyloff commented May 16, 2018

It appears the problem is with routing in the docker network; it doesn't like going out to the internet and back. Using the invoiceninja/dockerfiles docker-compose.yml example, I added the jwilder/nginx-proxy library. In my app container, I edited the host file to point to the nginx-proxy internal docker IP address. Let's say docker inspect told me the IP was 172.20.0.3

docker exec -it app /bin/bash
apt-get update
apt-get install -y vim
vi /etc/hosts

# add this entry and save /etc/hosts file
172.20.0.3 ap.domain.com

Then when I tried the "Attach PDF with local PhantomJS", it worked immediately. So the question is, how do I dynamically create that entry? I tried it like this, but it didn't work:

  nginx-proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./volumes/web/certs:/etc/nginx/certs:ro
    networks:
      default:
        aliases:
          - ap.domain.com
  app:
    image: invoiceninja/invoiceninja
    links:
      - db:mysql
    env_file: .env
    volumes:
      - ./volumes/app/storage:/var/www/app/storage
      - ./volumes/app/logo:/var/www/app/public/logo
    environment:
      - TRUSTED_PROXIES=['*']

@nbyloff

This comment has been minimized.

Copy link

@nbyloff nbyloff commented May 16, 2018

Correction for future users. I had modified my .env so much, I forgot APP_URL=http://web. When I changed it to APP_URL=https://ap.domain.com, it worked.

The key to get it to work with HTTPS and proxy is the aliases so it resolves the container IP instead of the public IP

@hillelcoren

This comment has been minimized.

Copy link
Member

@hillelcoren hillelcoren commented May 16, 2018

Glad to hear you got it working, thanks for sharing the solution!

@lalop

This comment has been minimized.

Copy link
Member

@lalop lalop commented May 17, 2018

hey @nbyloff I don't understand, what was https://ap.domain.com ?

@nbyloff

This comment has been minimized.

Copy link

@nbyloff nbyloff commented May 17, 2018

@lalop my mistake. Apparently when removing the real domain during my troubleshooting I changed ap.domain.com to invoice.domain.com half way through. Updated my comments earlier to make it clear.

Here's my complete docker-compose.yml. I use a custom rolled letsencrypt container since I want to validate an SSL cert before making any DNS changes but there is a letsencrypt container that works explicitly with jwilder/nginx-proxy. Setting up this docker-compose example with default HTTPS would be worthwhile.

version: '2'

services:
  db:
    image: mysql:5
    container_name: db-proxy
    env_file: .env
    restart: always
    volumes:
      - data-volume:/var/lib/mysql
    networks:
      - nginx-proxy

  nginx-proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./volumes/web/certs:/etc/nginx/certs:ro
      - ./volumes/web/dhparam:/etc/nginx/dhparam:rw
    networks:
      nginx-proxy:
        aliases:
          - ap.domain.com

  ssl-certs:
    image: nbyloff/dehydrated
    container_name: certs-proxy
    volumes:
      - ./volumes/web/certs:/letsencrypt/certs:rw
      - /var/run/docker.sock:/var/run/docker.sock:ro
    volumes_from:
      - nginx-proxy
    networks:
      - nginx-proxy

  app:
    image: invoiceninja/invoiceninja
    container_name: ninja-proxy
    links:
      - db:mysql
    env_file: .env
    volumes:
      - ./volumes/app/storage:/var/www/app/storage
      - ./volumes/app/logo:/var/www/app/public/logo
    networks:
      - nginx-proxy

  web:
    image: nginx:1
    container_name: web-proxy
    volumes:
      - ./volumes/web/nginx.conf:/etc/nginx/nginx.conf:ro
    links:
      - app
    volumes_from:
      - app
    ports:
      - 8082:80
    environment:
      VIRTUAL_HOST: ap.domain.com
    networks:
      - nginx-proxy

  backup:
    image: schickling/mysql-backup-s3
    container_name: backup-proxy
    links:
      - db:mysql
    networks:
      - nginx-proxy
    environment:
      S3_ACCESS_KEY_ID: <SOME_ID>
      S3_SECRET_ACCESS_KEY: <SOME_KEY>
      S3_BUCKET: <SOME_BUCKET>
      S3_PREFIX: <SOME_PREFIX>
      S3_REGION: us-east-1
      MYSQL_USER: root
      MYSQL_PASSWORD: pwd
      MYSQL_HOST: db
      SCHEDULE: "@daily"

  cron:
    image: invoiceninja/invoiceninja
    container_name: cron-proxy
    links:
      - db:mysql
    env_file: .env
    volumes_from:
      - app
    networks:
      - nginx-proxy
    entrypoint: |
      bash -c 'bash -s <<EOF
      trap "break;exit" SIGHUP SIGINT SIGTERM
      sleep 300s
      while /bin/true; do
        ./artisan ninja:send-invoices
        ./artisan ninja:send-reminders
        sleep 1h
      done
      EOF'

networks:
  nginx-proxy:

volumes:
  data-volume:
@lalop

This comment has been minimized.

Copy link
Member

@lalop lalop commented May 17, 2018

Good to hear, thank you for your feedback

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants
You can’t perform that action at this time.