{"id":26940534,"url":"https://github.com/joanroig/cloud-invoicing","last_synced_at":"2025-06-14T15:02:20.931Z","repository":{"id":37925457,"uuid":"468522397","full_name":"joanroig/cloud-invoicing","owner":"joanroig","description":"📝 Create German PDF invoices in the cloud from a Google Sheets document.","archived":false,"fork":false,"pushed_at":"2025-04-10T12:16:05.000Z","size":1721,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-14T15:01:43.247Z","etag":null,"topics":["accounting","deutsch","deutschland","gcp","germany","google","google-app-engine","google-apps-script","google-cloud-platform","google-sheets","invoice","kleinunternehmer","nodejs","pdf-generation","rechnung"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joanroig.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-10T21:55:34.000Z","updated_at":"2025-04-09T22:33:57.000Z","dependencies_parsed_at":"2024-01-15T05:43:51.689Z","dependency_job_id":"6c6d30f9-98fb-4b17-bfa7-a24db7e43b9e","html_url":"https://github.com/joanroig/cloud-invoicing","commit_stats":{"total_commits":58,"total_committers":4,"mean_commits":14.5,"dds":0.2586206896551724,"last_synced_commit":"d67e9fe8d74f56156b6a90a74db0783415912491"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/joanroig/cloud-invoicing","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joanroig%2Fcloud-invoicing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joanroig%2Fcloud-invoicing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joanroig%2Fcloud-invoicing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joanroig%2Fcloud-invoicing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joanroig","download_url":"https://codeload.github.com/joanroig/cloud-invoicing/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joanroig%2Fcloud-invoicing/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259835073,"owners_count":22918969,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["accounting","deutsch","deutschland","gcp","germany","google","google-app-engine","google-apps-script","google-cloud-platform","google-sheets","invoice","kleinunternehmer","nodejs","pdf-generation","rechnung"],"created_at":"2025-04-02T15:18:56.063Z","updated_at":"2025-06-14T15:02:20.852Z","avatar_url":"https://github.com/joanroig.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eCloud Invoicing\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/logo.png\" alt=\"logo\" width=\"340px\"/\u003e\n  \u003cbr\u003e\n  \u003ci\u003eNode.js project to create German PDF invoices from a Google Sheets document.\u003cbr\u003eDeployable to Google App Engine and automatable using Apps Script.\u003c/i\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    See the \u003ca href=\"examples/\"\u003e\u003cstrong\u003einvoice examples\u003c/strong\u003e\u003c/a\u003e, and start your own \u003ca href=\"https://docs.google.com/spreadsheets/d/1JRJ3KQetNAAPzsJat-JH7iIzc3OGumWQyFL5MZfm5UU/copy\"\u003e\u003cstrong\u003eaccounting spreadsheet\u003c/strong\u003e\u003c/a\u003e.\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ci\u003eRelated project: \u003ca href=\"https://github.com/joanroig/cloud-reports\"\u003e\u003cstrong\u003eCloud Reports for PayPal\u003c/strong\u003e\u003c/a\u003e\u003c/i\u003e\n\u003c/p\u003e\n\u003chr\u003e\n\n## Features\n\n- Track customers, products and orders in a spreadsheet\n- Verify order data and generate invoice dates and numbers\n- Export invoices in PDF format (only in German language)\n- Include VAT notices for Kleinunternehmer or reverse-charge procedures\n\n### Integrations\n\n- Upload invoices to Google Drive\n- Run in Google Cloud Platform for a fully automated solution\n\n### What is not implemented\n\n- VAT calculation\n- Invoice translations\n- Other invoice formats\n\n\u003e :warning: **Disclaimer: _I am not a tax or financial advisor, and as stated in the [license](LICENSE), I am by no means responsible for the use of this software._** _Please note that this was made for my own needs and may not fit your use case._\n\n---\n\n## Requirements\n\nYou will need Node.js \u003e16 installed in your environment.\n\n### Node\n\n- #### Node installation on Windows\n\n  Go to the [official Node.js website](https://nodejs.org/) and download the installer.\n  Be sure to have `git` available in your PATH, `npm` might need it (you can find git [here](https://git-scm.com/)).\n\n- #### Node installation on Ubuntu\n\n  Install nodejs and npm with apt install, just run the following commands:\n\n      $ sudo apt install nodejs\n      $ sudo apt install npm\n\n- #### Other Operating Systems\n  You can find more information about the installation on the [official Node.js website](https://nodejs.org/) and the [official NPM website](https://npmjs.org/).\n\nIf the installation was successful, you should be able to run the following commands:\n\n    $ node --version\n    v18.12.1\n\n    $ npm --version\n    8.19.2\n\n## Prepare the project folder\n\nDownload the project and install its dependencies:\n\n    $ git clone https://github.com/joanroig/cloud-invoicing\n    $ cd cloud-invoicing\n    $ npm install\n\n# Configuration\n\nCreate a `.env` file in the root directory based on the provided `.env.example`, then you will need to:\n\n- Create a Google Cloud project, activate the Google Sheets API, and create a service account as explained in [this guide](https://theoephraim.github.io/node-google-spreadsheet/#/getting-started/authentication).\n- Put the `private_key` and `client_email` values from the JSON of the service account you obtained in the previous step in the `.env` file.\n- [Do a copy](https://docs.google.com/spreadsheets/d/1JRJ3KQetNAAPzsJat-JH7iIzc3OGumWQyFL5MZfm5UU/copy) of the provided Google Sheets template.\n- Share the spreadsheet with the email of your service account (this allows the service account to access your spreadsheet). To do this, go to your copy of the template and press the share button, then enter the service account email and send the invitation.\n- Put the spreadsheet ID from the URL of your Google Sheets document into the `spreadsheet_id` of the `.env` file, the ID should look similar to this: `1JRJ3KQetNAAPzsJat-JH7iIzc3OGumWQyFL5MZfm5UU`\n\n### Automatic upload to Drive\n\n- Create a folder in Drive and share the folder with the email of your service account.\n- Put the folder ID from the URL of your Drive folder into the `drive_folder_id` of the `.env` file.\n\n_Note: You can disable the upload of invoices by setting the property `upload-to-drive` to `false` in `config/default.json`._\n\n## Running the project manually\n\nAdd some data in the spreadsheet and activate the checkboxes of the `Run` column in the `Orders` tab for each invoice you want to generate.\n\nThen, run the following command and check the console output and the out folder for checking your results:\n\n    $ npm start:once\n\n## Run the production server locally\n\nThe project can run as a server to execute the invoice generation on demand. You can test it locally by executing the following commands, and then access http://localhost:8080 in your browser every time you want to trigger the generation:\n\n    $ npm build\n    $ npm start\n\n# Google Cloud Platform (GCP) integration\n\nAfter verifying locally that everything works, you may want to automate the invoice generation in the cloud.\n\n\u003e :warning: **Developing and running the project on GCP did not exceed my account's free quotas, but please note that you must enable billing at your own risk. You can configure a Cloud Function to prevent unwanted billings by following the [official documentation](https://cloud.google.com/billing/docs/how-to/notify) or this [video](https://www.youtube.com/watch?v=KiTg8RPpGG4).**\n\n## Introduction\n\nWe need to have a Google Cloud project to upload the server to App Engine, then create an Apps Script, secure the communication between Apps Script and App Engine, and finally trigger the invoice generation from the spreadsheet.\n\n### GCP architecture overview\n\nTo provide a better understanding of all actors, the process flow looks like this:\n\n1. The user uses `Google Sheets` to trigger `Apps Script`\n2. `Apps Script` sends an HTTP GET request to `App Engine` which verifies the user via `IAP`\n3. `App Engine` starts the invoice generation, which uses a `Service Account` to:\n   1. Read, verify and update `Google Sheets` data\n   2. Upload invoices to `Google Drive`\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/diagram.png\" alt=\"logo\" width=\"500px\"/\u003e\n  \u003cbr\u003e\n  \u003ci\u003eSimplified GCP architecture diagram\u003c/i\u003e\n\u003c/p\u003e\n\n### APIs overview\n\nFollowing the guide will require to enable multiple Google Cloud APIs. You will be asked to enable them when needed via CLI or via the Google Cloud website:\n\n- Cloud Logging API\n- Cloud Build API\n- Google Sheets API\n- Google Drive API\n- Cloud Identity-Aware Proxy API\n\nExtra APIs used to prevent unwanted billings:\n\n- Cloud Billing API\n- Cloud Pub/Sub API\n- Cloud Functions API\n\n## Google App Engine setup\n\nThe App Engine is where the production server will be deployed and where the invoices will be generated. It will be your own secure cloud environment by protecting the access with IAP (Identity-Aware Proxy).\n\n- [Enable billing](https://console.cloud.google.com/billing) for your Google Cloud project.\n- [Install the Google Cloud CLI](https://cloud.google.com/sdk/docs/install-sdk), run `gcloud init` in the project root folder and connect it to your project.\n- Update the `project_id` of the `.env` file with the Project ID of your Google Cloud project (get it [here](https://console.cloud.google.com/home/dashboard)).\n- Run the command `npm gcloud:deploy` in the root directory to upload the Node.js project. The build folder will be built and then deployed, if you execute the command `gcloud app deploy` remember to build the project before.\n- [Enable IAP](https://console.cloud.google.com/security/iap) for the project (create OAuth consent screen if asked) and toggle IAP for your App Engine app. Then select the App Engine app row and add the Gmail you would like to use to access the Google Sheets document by pressing the \"Add Principal\" button. Assign the role `IAP-secured Web App User`. Repeat this step for every IAP-allowed user you need.\n\nNow try to access the server URL (shown in the [App Engine Dashboard](https://console.cloud.google.com/appengine), it ends with `.appspot.com`), login with the Gmail used in the previous step, and you should be able to access the deployed server.\n\nThe invoice generation will be triggered every time an IAP-allowed user does an HTTP GET request to the server URL. In the next steps, you will configure the trigger from Google Sheets.\n\n## Apps Script setup\n\nAn Apps Script of a Google Sheets document acts like a plugin that extends its functionality.\n\nFor the purpose of this project, the script will be responsible for sending requests to the App Engine server on behalf of an allowed user, which is needed to go through IAP.\n\n- Open your spreadsheet, in the menu open `Extensions \u003e Apps Script`\n- Go to the settings of the Apps Script and toggle the `Show \"appsscript.json\" manifest file in editor` checkbox.\n- Also in settings, assign the Project Number of the Google Cloud project (get it [here](https://console.cloud.google.com/home/dashboard)).\n- Go to [credentials](https://console.cloud.google.com/apis/credentials) and create a new OAuth 2.0 Client ID of type `Web application`. You will need to provide a redirect URL with the format `https://script.google.com/macros/d/{SCRIPT_ID}/usercallback`, where SCRIPT_ID is the ID provided in the Apps Script settings. More information [here](https://github.com/googleworkspace/apps-script-oauth2#redirect-uri).\n- Copy the `appsscript.json` and the `Code.gs` file from the examples/Apps Script folder in the Apps Script files.\n- Edit the `Code.gs` file to add your own credentials:\n  - Use the Client ID and Client Secret for the values of `CLIENT_ID` and `CLIENT_SECRET` respectively.\n  - Use the Client ID of the `IAP-App-Engine-app` (find it in [credentials](https://console.cloud.google.com/apis/credentials) under the OAuth 2.0 Client IDs) for the value of `IAP_CLIENT_ID`.\n  - The `IAP_URL` is the server URL that ends with `.appspot.com`.\n\n## Running in the cloud\n\nNow you should be able to find a menu called `Generate Invoices` in your spreadsheet (refresh the page if not). Click the `Run now` option.\n\nOn the first run you will need to login with your gmail and enable the access and check the Apps Script executions for details (you should find an URL to enable the access in the execution log).\n\n### Debugging\n\nSomething is not working? Then check the latest run logs on Google App Engine by running the following command:\n\n    $ npm run gcloud:logs\n\nRemember that you can always redeploy by running:\n\n    $ npm run gcloud:deploy\n\n\u003e :warning: **The provided deploy script always replaces the same version on App Engine to prevent exceeding the Cloud Storage free thresholds. This is managed by adding `--version=staging` in the deploy command. If you did some deploys without the flag, you can remove old versions of your project [here](https://console.cloud.google.com/appengine/versions).**\n\n# Development and modifications\n\nYou can fork and further extend the project to adapt it to your needs.\n\nThe [model](src/app/models/sheets.model.ts) of the Node.js application is bounded to the headers of the provided Google Sheets template. Remember to modify the model enums if you change any header in the spreadsheet.\n\n# Known issues\n\n### **Exceeded soft memory limit of 256 MB after servicing X requests total**\n\nIssue that appeared when launching the invoice generation after deploying the complete source code of the project. It is solved by pre-building the project and uploading only the necessary files specified in `.gcloudignore`. More information [here](https://medium.com/@daavidaviid/how-to-solve-the-issue-exceeded-soft-memory-limit-in-app-engine-with-node-js-c48ecc46ba1e).\n\n### **403 error on Google Sheets connection**\n\nThis may happen if you did not activate the Google Sheets API, if you did not share the spreadsheet document with your service account, or if you did not introduce the proper data in the `.env` file. Look carefully if you copied the `private_key` value with comma in the end because this will make it invalid.\n\n# Credits\n\n_All trademarks, logos and brand names are the property of their respective owners._\n\n- App Scripts to IAP from: https://github.com/googleworkspace/apps-script-oauth2/blob/master/samples/CloudIdentityAwareProxy.gs\n- pdfmake template based on: https://gist.github.com/maxkostinevich/c26bfb09450341ad37c1bd6c2cc51bb2\n- Logger based on: https://gist.github.com/euikook/d72a40b3864856af57a6dcbec9d97007\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoanroig%2Fcloud-invoicing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoanroig%2Fcloud-invoicing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoanroig%2Fcloud-invoicing/lists"}