{"id":386164,"date":"2026-11-04T14:54:31","date_gmt":"2026-11-04T14:54:31","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/heave-invoice-sync-for-pennylane\/"},"modified":"2026-11-04T14:54:17","modified_gmt":"2026-11-04T14:54:17","slug":"heave-invoice-manager-for-pennylane","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/heave-invoice-manager-for-pennylane\/","author":23172098,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.1","stable_tag":"1.0.1","tested":"7.1.4","requires":"6.6","requires_php":"8.1","requires_plugins":null,"header_name":"Heave Invoice Manager for Pennylane","header_author":"Heave","header_description":"Connects WooCommerce to Pennylane: customers download their invoices from \u201cMy account\u201d, invoices are matched to orders automatically, and VAT or payment anomalies are detected.","assets_banners_color":"","last_updated":"2026-11-04 14:54:17","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/heave.studio\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":38,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.1":{"tag":"1.0.1","author":"heave","date":"2026-11-04 14:54:17","revision":3784185}},"upgrade_notice":[],"ratings":[],"assets_icons":[],"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.1"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[2526,12480,261792,19126,286],"plugin_category":[45],"plugin_contributors":[290696],"plugin_business_model":[],"class_list":["post-386164","plugin","type-plugin","status-publish","hentry","plugin_tags-accounting","plugin_tags-invoice","plugin_tags-pennylane","plugin_tags-vat","plugin_tags-woocommerce","plugin_category-ecommerce","plugin_contributors-heave","plugin_committers-heave"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/s.w.org\/plugins\/geopattern-icon\/heave-invoice-manager-for-pennylane.svg","icon_2x":false,"generated":true},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Heave Invoice Manager for Pennylane links your WooCommerce store to <a href=\"https:\/\/www.pennylane.com\/\">Pennylane<\/a>, the French accounting and invoicing platform.<\/p>\n\n<p><strong>For your customers<\/strong><\/p>\n\n<ul>\n<li>A \u201cDownload my invoice\u201d button in \u201cMy account\u201d, on every order whose invoice exists in Pennylane.<\/li>\n<li>Optional WooCommerce email that sends the PDF invoice as an attachment as soon as it is available (also works for guest orders).<\/li>\n<\/ul>\n\n<p><strong>For you<\/strong><\/p>\n\n<ul>\n<li><strong>Automatic matching<\/strong> \u2014 every 20 minutes, new Pennylane invoices are linked to their WooCommerce order through the invoice external reference.<\/li>\n<li><strong>Dashboard<\/strong> \u2014 for any period: which orders have an invoice, which are still drafts, which are missing, which are paid. Link, create a missing invoice as a draft, or finalize drafts of paid orders, one by one or in batch.<\/li>\n<li><strong>Draft finalization<\/strong> \u2014 by hand with a confirmation, or automatically once the order is paid. Drafts dated before the last finalized invoice are moved to today's date, as Pennylane requires chronological numbering. Recording payments stays a manual step in Pennylane.<\/li>\n<li><strong>VAT checks<\/strong> \u2014 finds domestic orders charged without VAT, lines without VAT, wrong VAT rates, intra-EU exemptions without a VAT number, and gaps between WooCommerce, Pennylane and the money actually collected by your payment gateway (Stripe fees taken into account). Filter and export to CSV for your accountant. Optional real-time alert on new orders.<\/li>\n<li><strong>Built for safety<\/strong> \u2014 the PDF is served through a gated proxy (the Pennylane link is never exposed), finalizing or creating invoices is reserved to shop managers and always confirmed, and every API error is logged.<\/li>\n<\/ul>\n\n<p><strong>Requirements<\/strong><\/p>\n\n<ul>\n<li>WooCommerce 8.0 or later (compatible with HPOS and the Cart &amp; Checkout blocks).<\/li>\n<li>A Pennylane account and an API token (Pennylane &gt; Settings &gt; Connectivity &gt; Developers).<\/li>\n<li>Your Pennylane invoices must carry the WooCommerce order number as external reference \u2014 this is what most WooCommerce \u2192 Pennylane invoicing integrations do.<\/li>\n<\/ul>\n\n<p>This plugin is developed by Heave. It is not affiliated with, nor endorsed by, Pennylane. \u201cPennylane\u201d is a trademark of its respective owner and is used here only to describe compatibility.<\/p>\n\n<h3>External services<\/h3>\n\n<p>This plugin connects to the <strong>Pennylane API<\/strong> (<code>https:\/\/app.pennylane.com\/api\/external\/v2<\/code>), operated by Pennylane SAS, to read and manage the customer invoices of your Pennylane account. It is the core purpose of the plugin: nothing is sent before you enter an API token.<\/p>\n\n<p>What is sent, and when:<\/p>\n\n<ul>\n<li><strong>Every 20 minutes (background sync), on the dashboard and on the order screen<\/strong>: requests to list and read customer invoices, filtered by date or by order number (external reference). Only your API token and these filters are sent.<\/li>\n<li><strong>When you finalize a draft<\/strong> (button, or the optional automatic finalization): the invoice ID, and when needed the new invoice date.<\/li>\n<li><strong>When you create a missing invoice<\/strong> (button, always confirmed): the order number, date and amounts, the order lines (product names, quantities, prices, VAT rates, shipping and fees), and the customer's name, company, email address and billing address \u2014 used to find or create the customer in Pennylane.<\/li>\n<li><p><strong>When an invoice PDF is needed<\/strong> (customer download, invoice email): the PDF is downloaded from the secure link returned by the Pennylane API, then cached on your server.<\/p><\/li>\n<li><p>Pennylane terms of service: https:\/\/www.pennylane.com\/fr\/conditions-generales<\/p><\/li>\n<li>Pennylane privacy policy: https:\/\/www.pennylane.com\/fr\/legal\/privacy<\/li>\n<\/ul>\n\n<p>The plugin does not send any data to its author and does not track usage.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate WooCommerce.<\/li>\n<li>Install this plugin from the Plugins screen and activate it.<\/li>\n<li>Go to <strong>WooCommerce &gt; Pennylane &gt; Settings<\/strong> and paste your Pennylane API token. For better security you can define it in <code>wp-config.php<\/code> instead: <code>define( 'PENNYLANE_SYNC_API_TOKEN', 'your-token' );<\/code><\/li>\n<li>Check the <strong>order number meta key<\/strong> with the matching diagnostic (Sync &amp; tools tab): it must hold the number used as external reference in Pennylane.<\/li>\n<li>Optional: enable the \u201cPennylane invoice\u201d email in <strong>WooCommerce &gt; Settings &gt; Emails<\/strong>.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"which%20api%20permissions%20does%20the%20token%20need%3F\"><h3>Which API permissions does the token need?<\/h3><\/dt>\n<dd><p>Read access to customer invoices and customers is enough to display invoices. Write access to customer invoices is needed to finalize or create invoices, and write access to customers to create a customer that does not exist yet in Pennylane.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20record%20payments%20in%20pennylane%3F\"><h3>Does the plugin record payments in Pennylane?<\/h3><\/dt>\n<dd><p>No. Recording a payment (reconciliation with the bank) stays a manual step in Pennylane. The plugin only finalizes drafts and, on request, creates missing invoices as drafts.<\/p><\/dd>\n<dt id=\"why%20was%20my%20draft%20re-dated%20when%20finalized%3F\"><h3>Why was my draft re-dated when finalized?<\/h3><\/dt>\n<dd><p>Pennylane numbers invoices chronologically and refuses to finalize an invoice dated before the last finalized one. A draft is issued the day it is finalized, so an older date is moved to today. The order note keeps track of the change.<\/p><\/dd>\n<dt id=\"can%20customers%20download%20invoices%20for%20guest%20orders%3F\"><h3>Can customers download invoices for guest orders?<\/h3><\/dt>\n<dd><p>The download button requires an account. For guest orders, enable the \u201cPennylane invoice\u201d email: the PDF is sent as an attachment.<\/p><\/dd>\n<dt id=\"where%20are%20the%20pdfs%20stored%3F\"><h3>Where are the PDFs stored?<\/h3><\/dt>\n<dd><p>In <code>wp-content\/uploads\/pennylane-invoices\/<\/code>, under random file names, protected by an <code>.htaccess<\/code> file on Apache. On Nginx, add a rule denying access to this folder. The cache is purged after the number of days set in the settings; Pennylane remains the source of truth.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Security: an invoice is linked to an order only when it is finalized, not cancelled, not a credit note, and carries the order's exact reference. A reference shared by several orders links nothing.<\/li>\n<li>Security: a link is removed when the invoice is cancelled, deleted or moved to another order in Pennylane (checked on refresh, range runs, downloads and manual emails). The order note tells why.<\/li>\n<li>Security: the cached PDF is tied to its invoice, so a replaced invoice is never served or emailed again.<\/li>\n<li>Security: creating a draft no longer reuses a Pennylane customer found only by email: the name must match too.<\/li>\n<li>Security: the VAT CSV export neutralizes formulas anywhere in a text cell.<\/li>\n<li>Fix: deleting a refund no longer causes a fatal error.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>First public release.<\/li>\n<\/ul>","raw_excerpt":"Connect WooCommerce to Pennylane: invoices in \u201cMy account\u201d, automatic order matching, draft finalization and VAT checks.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/386164","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=386164"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/heave"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=386164"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=386164"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=386164"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=386164"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=386164"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=386164"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}