{"id":356733,"date":"2026-09-17T10:27:49","date_gmt":"2026-09-17T10:27:49","guid":{"rendered":"https:\/\/fr.wordpress.org\/plugins\/erp-x-business-management\/"},"modified":"2026-09-17T10:27:25","modified_gmt":"2026-09-17T10:27:25","slug":"ams-studio-erp-invoicing-accounting","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/ams-studio-erp-invoicing-accounting\/","author":23552304,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.5.25","stable_tag":"0.5.25","tested":"7.1.1","requires":"6.4","requires_php":"8.1","requires_plugins":null,"header_name":"AMS Studio ERP \u2014 Invoicing & Accounting","header_author":"Anthony SGRO","header_description":"ERP pour WordPress : clients, catalogue, devis, factures et facturation \u00e9lectronique, sur votre propre serveur.","assets_banners_color":"f7f7f6","last_updated":"2026-09-17 10:27:25","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/www.ams-studio.lu\/","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":32,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.5.25":{"tag":"0.5.25","author":"anthonysgro","date":"2026-09-17 10:27:25","revision":3700080}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3700131,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3700131,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3700131,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3700131,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.5.25"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3700131,"resolution":"1","location":"assets","locale":"","width":1544,"height":965},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3700131,"resolution":"2","location":"assets","locale":"","width":1544,"height":965},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3700131,"resolution":"3","location":"assets","locale":"","width":1544,"height":965},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3700131,"resolution":"4","location":"assets","locale":"","width":1544,"height":965},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3700131,"resolution":"5","location":"assets","locale":"","width":1544,"height":965},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3700131,"resolution":"6","location":"assets","locale":"","width":1544,"height":965}},"screenshots":{"1":"Dashboard: monthly revenue, pending invoices and active customers.","2":"Quotes, from draft to online signature.","3":"Customer invoices, with what is paid and what remains due.","4":"Customers, with their addresses and contacts.","5":"The catalogue: products and services, prices and margins.","6":"Settings: company details, numbering, VAT and appearance."}},"plugin_section":[],"plugin_tags":[1150,12827,226218,26218,354],"plugin_category":[58],"plugin_contributors":[281260],"plugin_business_model":[],"class_list":["post-356733","plugin","type-plugin","status-publish","hentry","plugin_tags-crm","plugin_tags-erp","plugin_tags-factur-x","plugin_tags-invoicing","plugin_tags-quotes","plugin_category-user-management","plugin_contributors-anthonysgro","plugin_committers-anthonysgro"],"banners":{"banner":"https:\/\/ps.w.org\/ams-studio-erp-invoicing-accounting\/assets\/banner-772x250.png?rev=3700131","banner_2x":"https:\/\/ps.w.org\/ams-studio-erp-invoicing-accounting\/assets\/banner-1544x500.png?rev=3700131","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/ams-studio-erp-invoicing-accounting\/assets\/icon-128x128.png?rev=3700131","icon_2x":"https:\/\/ps.w.org\/ams-studio-erp-invoicing-accounting\/assets\/icon-256x256.png?rev=3700131","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/ams-studio-erp-invoicing-accounting\/assets\/screenshot-1.png?rev=3700131","caption":"Dashboard: monthly revenue, pending invoices and active customers."},{"src":"https:\/\/ps.w.org\/ams-studio-erp-invoicing-accounting\/assets\/screenshot-2.png?rev=3700131","caption":"Quotes, from draft to online signature."},{"src":"https:\/\/ps.w.org\/ams-studio-erp-invoicing-accounting\/assets\/screenshot-3.png?rev=3700131","caption":"Customer invoices, with what is paid and what remains due."},{"src":"https:\/\/ps.w.org\/ams-studio-erp-invoicing-accounting\/assets\/screenshot-4.png?rev=3700131","caption":"Customers, with their addresses and contacts."},{"src":"https:\/\/ps.w.org\/ams-studio-erp-invoicing-accounting\/assets\/screenshot-5.png?rev=3700131","caption":"The catalogue: products and services, prices and margins."},{"src":"https:\/\/ps.w.org\/ams-studio-erp-invoicing-accounting\/assets\/screenshot-6.png?rev=3700131","caption":"Settings: company details, numbering, VAT and appearance."}],"raw_content":"<!--section=description-->\n<p>AMS Studio ERP turns WordPress into the back office of a small company. Quotes, invoices,\npurchase orders, stock, deals, documents, treasury and accounting all live in your\nown database, on your own server. There is no service to subscribe to and no second\npassword to remember.<\/p>\n\n<p><strong>The document chain<\/strong><\/p>\n\n<p>Nothing is retyped from one step to the next. A quote becomes an invoice, the invoice\ncalls for its payment, the payment produces its ledger entry, and every document keeps\nthe link back to the one it came from.<\/p>\n\n<ul>\n<li>Quotes sent by email with their PDF, then signed online by the customer<\/li>\n<li>Invoices numbered in a continuous, chronological series<\/li>\n<li>Payments entered by hand or matched to an imported bank statement<\/li>\n<li>Ledger entries posted to the right journal and financial year<\/li>\n<\/ul>\n\n<p><strong>What holds up under audit<\/strong><\/p>\n\n<p>These rules live in the engine, and the plugin refuses whatever breaks them.<\/p>\n\n<ul>\n<li>Numbering stays continuous: a prefix already in use cannot change, and a reopened\ndocument keeps its number<\/li>\n<li>An approved document is sealed by a fingerprint over its amounts, its party and its\nnumber; a mistake is corrected by a credit note, never by editing<\/li>\n<li>VAT is broken down by rate, as the law requires on the document itself<\/li>\n<li>Factur-X (PDF\/A-3) and Peppol BIS Billing 3.0; a non-compliant invoice refuses to go\nout, in print, by email and on the public page<\/li>\n<li>Attachments are encrypted with AES-256-GCM, outside the public media library<\/li>\n<li>Exact decimal arithmetic throughout, never floating point<\/li>\n<\/ul>\n\n<p><strong>What this plugin does<\/strong><\/p>\n\n<ul>\n<li>Customers: records, addresses, contacts, categories<\/li>\n<li>Catalogue: products and services, purchase and sale prices, margins, VAT rates<\/li>\n<li>Quotes: drafted, sent by email with their PDF, signed online by the customer<\/li>\n<li>Customer invoices and credit notes: continuous numbering, deposits, payment terms,\nwhat is paid and what remains due<\/li>\n<li>Factur-X (PDF\/A-3) and Peppol BIS Billing 3.0 on every invoice<\/li>\n<li>Encrypted attachments, exact decimal arithmetic, an audit trail on every document<\/li>\n<\/ul>\n\n<p><strong>What it does not do<\/strong><\/p>\n\n<p>Purchasing, stock, deals, treasury, accounting, the document library and the\nWooCommerce bridge are <strong>not part of this plugin<\/strong>. They come with AMS Studio Pro, a\nseparate add-on installed alongside it and distributed from https:\/\/www.ams-studio.lu\/<\/p>\n\n<p>Nothing here is capped, time-limited or waiting for a key: what you install is\ncomplete. The modules above are simply not in this package \u2014 the menu shows them so\nyou know they exist, and says where to get them.<\/p>\n\n<p><strong>Languages<\/strong><\/p>\n\n<p>French and English. The plugin follows your site's language, or its own if you ask it to \u2014\nan English site can run a French ERP.<\/p>\n\n<h3>Third-party libraries<\/h3>\n\n<p>Producing an invoice as a PDF needs an HTML-to-PDF engine, and WordPress core\nhas none. Four libraries are bundled, unmodified except where noted, each with\nits own licence file in its directory \u2014 all GPL-compatible:<\/p>\n\n<ul>\n<li>dompdf\/dompdf 3.1.6 \u2014 LGPL-2.1 \u2014 https:\/\/github.com\/dompdf\/dompdf<\/li>\n<li>masterminds\/html5 \u2014 MIT \u2014 https:\/\/github.com\/Masterminds\/html5-php<\/li>\n<li>sabberworm\/php-css-parser \u2014 MIT \u2014 https:\/\/github.com\/MyIntervals\/PHP-CSS-Parser<\/li>\n<li>php-font-lib \u2014 LGPL-2.1 \u2014 https:\/\/github.com\/dompdf\/php-font-lib<\/li>\n<\/ul>\n\n<p>They are bundled rather than pulled by Composer because the plugin must install\nfrom the WordPress admin, on shared hosting, with no command line. Their\nnamespaces are prefixed under <code>AMSBM\\Vendor\\<\/code> with PHP-Scoper, so that two\nplugins bundling dompdf in different versions cannot break each other; the\nprefixing is reproducible with <code>bin\/scoper.sh<\/code>. Every other deviation from the\nupstream code is marked in place and listed in <code>lib\/pdf\/ECARTS.md<\/code>: a direct-access guard on the two files that carry code\noutside a class, embedding a Factur-X XML attachment into a PDF\/A-3 file which\ndompdf does not support upstream, heredoc blocks rewritten as concatenation,\nand the removal of SVG rendering.<\/p>\n\n<p>dompdf's fifth dependency, php-svg-lib, is deliberately <strong>not<\/strong> bundled. It\nexists only to draw SVG images inside a PDF, and drawing one means parsing XML\nthat a site user supplied. The plugin does not need it \u2014 logos are PNG, JPEG,\nGIF or WebP, and an SVG is refused at upload \u2014 so the smaller attack surface is\nworth more than the feature. The three places where dompdf reached for it are\nneutralised in place, and an SVG is simply not a recognised image type any\nmore.<\/p>\n\n<p>One more deviation is replayed automatically rather than by hand: in\nphp-font-lib, <code>glyf::toHTML()<\/code> \u2014 a font-debugging method that builds an HTML\npage with inline scripts \u2014 is emptied. Neither dompdf nor the plugin calls it.\n    bin\/pdf-patches.php applies that change after every copy of the libraries\n(<code>bin\/vendor-pdf.sh<\/code>) and again after prefixing (<code>bin\/scoper.sh<\/code>), and the\npackage build (<code>build-zip.sh<\/code>) refuses to proceed if it is missing.<\/p>\n\n<h3>Compiled admin interface<\/h3>\n\n<p>The admin interface is a React\/TypeScript application, compiled with Vite. The\ncompiled, minified bundle is in <code>app\/build\/<\/code>; its <strong>unminified sources ship with\nthe plugin<\/strong>, in <code>app\/src\/<\/code>, along with everything needed to rebuild it:\n    app\/package.json, <code>app\/package-lock.json<\/code>, <code>app\/tsconfig.json<\/code>,\n    app\/tsconfig.node.json, <code>app\/vite.config.ts<\/code>, <code>app\/tailwind.config.js<\/code> and\n    app\/postcss.config.js.<\/p>\n\n<p>The same sources are publicly available at https:\/\/github.com\/SanMat11\/wp-erpx<\/p>\n\n<p>To rebuild the bundle \u2014 Node.js 18 or 20 and later, verified with Node.js 22:<\/p>\n\n<pre><code>cd app &amp;&amp; npm ci &amp;&amp; npm run build\n\nnpm ci installs the exact dependency versions recorded in\napp\/package-lock.json. `npm run build` type-checks the sources with TypeScript\n<\/code><\/pre>\n\n<p>5.9, then builds them with Vite 5.4 into <code>app\/build\/<\/code>. The file\n    app\/build\/morceaux\/vendor-[hash].js is the npm dependencies listed in\n    app\/package.json \u2014 React, Ant Design and the others \u2014 bundled together by\nVite; each package's name and exact version are in <code>app\/package-lock.json<\/code>.<\/p>\n\n<p>Vite writes the entry point as <code>amsbm-app-[hash].js<\/code> and <code>amsbm-app-[hash].css<\/code>,\nwith the code split into chunks under <code>app\/build\/morceaux\/<\/code>. The hash in the\nfilename is the version: a new build produces a new name, so a cached file is\nnever a stale one. <code>app\/build\/manifeste.json<\/code> records the current pair, and the\nplugin reads it rather than guessing.<\/p>\n\n<p>Nothing about the plugin requires npm at runtime. The bundle is committed and\nshipped because the target audience installs from the WordPress admin, on shared\nhosting, with no command line.<\/p>\n\n<h3>External services<\/h3>\n\n<p><strong>VIES \u2014 EU VAT number validation<\/strong> (European Commission)<\/p>\n\n<p>Used only when you click \"check\" beside an EU VAT number, to confirm that the number\nexists. What is sent: the country code and the VAT number, in the request URL. Nothing\nelse \u2014 no company name, no site address, no identifier.\nService: https:\/\/ec.europa.eu\/taxation_customs\/vies\/\nTerms and privacy: https:\/\/ec.europa.eu\/taxation_customs\/vies\/#\/help<\/p>\n\n<p><strong>Stripe \u2014 card payment of your invoices<\/strong> (Stripe, Inc.)<\/p>\n\n<p>Used only if you enter your own Stripe API keys in the settings. It lets a customer of\nyours pay a shared invoice by card. What is sent, when your customer clicks \"pay\": the\namount, the currency, the invoice reference and the return address. The plugin never\nsends your customer list or your documents.\nService: https:\/\/stripe.com\/\nTerms: https:\/\/stripe.com\/legal\/ssa\nPrivacy: https:\/\/stripe.com\/privacy<\/p>\n\n<p><strong>AMS Studio licence server<\/strong> (AMS Studio, Luxembourg)<\/p>\n\n<p>Only reached if you click \"Upgrade to Pro\" in the application header. That button is a\nlink: your browser opens it, the plugin itself opens no connection and sends nothing on\nits own. What travels in that link: an installation identifier drawn at random on your\nsite, a one-way hash of a secret drawn with it, your site address and your admin email\naddress \u2014 so that the licence you buy is tied to this site and fills itself in when you\ninstall the paid package, with nothing to copy by hand. The hash cannot be reversed, and\nthe secret itself never appears in the link.\nNothing is sent if you never click the button, and nothing is sent on a schedule.\nService: https:\/\/licences.ams-studio.lu\/\nTerms and privacy: https:\/\/www.ams-studio.lu\/<\/p>\n\n<p>The plugin contacts nothing else. No telemetry, no update server, no licence check.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate the plugin as usual.<\/li>\n<li>Open AMS ERP in the admin menu and fill in your company details.<\/li>\n<li>Optionally install the demo data set to look around before entering your own.<\/li>\n<\/ol>\n\n<p>No command line is required, and no account anywhere: the plugin ships its own\nautoloader and its own PDF engine. Two optional features do contact an outside\nservice when you use them \u2014 see \"External services\" below.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"is%20my%20data%20sent%20anywhere%3F\"><h3>Is my data sent anywhere?<\/h3><\/dt>\n<dd><p>Your business data stays put. Documents, customers, articles and ledger entries live\nin your own database and are never sent anywhere.<\/p>\n\n<p>Two features do reach outside, and only when you ask them to:<\/p>\n\n<ul>\n<li><strong>VAT number validation.<\/strong> When you click \"check\" next to an EU VAT number, that\nnumber and its country code are sent to VIES, the European Commission's service.\nNothing else. If you never click, nothing is ever sent.<\/li>\n<li><strong>Card payment of an invoice.<\/strong> If \u2014 and only if \u2014 you enter your own Stripe keys,\nyour customer can pay a shared invoice by card. Stripe then receives the amount, the\ncurrency and the invoice reference, at the moment your customer clicks \"pay\".<\/li>\n<\/ul>\n\n<p>Both are documented in full under \"External services\" below.<\/p><\/dd>\n<dt id=\"is%20my%20data%20deleted%20when%20i%20uninstall%3F\"><h3>Is my data deleted when I uninstall?<\/h3><\/dt>\n<dd><p>No. Dropping the tables requires adding <code>define( 'AMSBM_REMOVE_ALL_DATA', true );<\/code> to\nyour <code>wp-config.php<\/code>. Accounting retention obligations \u2014 six years in France, up to ten\nelsewhere in Europe \u2014 outlast the lifetime of any plugin.<\/p><\/dd>\n<dt id=\"does%20it%20need%20innodb%3F\"><h3>Does it need InnoDB?<\/h3><\/dt>\n<dd><p>Yes. Without a transactional engine, operations cannot be made atomic. The built-in\nhealth check reports it.<\/p><\/dd>\n<dt id=\"are%20any%20features%20locked%20or%20limited%3F\"><h3>Are any features locked or limited?<\/h3><\/dt>\n<dd><p>No. Every feature in this package works, with no cap on the number of customers,\nquotes, invoices or articles, and no trial period.<\/p>\n\n<p>Some modules \u2014 purchasing, stock, deals, treasury, accounting, the document library\nand the WooCommerce bridge \u2014 are not in this package at all. They ship with a separate\nadd-on. The menu lists them so you know they exist; they are not disabled code waiting\nfor a key.<\/p><\/dd>\n<dt id=\"do%20i%20need%20composer%20or%20npm%20to%20install%20this%3F\"><h3>Do I need Composer or npm to install this?<\/h3><\/dt>\n<dd><p>No. The plugin ships its own autoloader, its own PDF engine and its compiled\nadmin interface. <code>composer.json<\/code> and the JavaScript sources are included so that\nthe build is reproducible and the dependencies are auditable, not because\nanything has to be run.<\/p><\/dd>\n<dt id=\"what%20happens%20to%20my%20data%20if%20i%20deactivate%20the%20plugin%3F\"><h3>What happens to my data if I deactivate the plugin?<\/h3><\/dt>\n<dd><p>Nothing. Deactivating stops the code from running; the tables, the documents and\nthe ledger stay exactly as they are, and reactivating picks up where you left\noff.<\/p><\/dd>\n<dt id=\"which%20chart%20of%20accounts%20is%20supported%3F\"><h3>Which chart of accounts is supported?<\/h3><\/dt>\n<dd><p>The French plan comptable g\u00e9n\u00e9ral and the Luxembourg plan comptable normalis\u00e9 2020.\nAccounts, journals and financial years are all editable.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.5.25<\/h4>\n\n<ul>\n<li>On a site without the stock, WooCommerce or accounting modules, the admin\ninterface no longer requests routes that do not exist there: the dashboard\nonly asks for stock alerts when stock is installed, the VAT settings only list\naccounting accounts when accounting is, and the Warehouses and Store settings\ntabs only appear when their module does.<\/li>\n<li>Demo data no longer writes purchase orders and supplier invoices on a site\nthat has no purchasing module.<\/li>\n<\/ul>\n\n<h4>0.5.24<\/h4>\n\n<ul>\n<li>Plugin Check reports nothing left in the plugin's own code. The hook fired when\nthe installation fingerprint is renewed is now fired by its literal, prefixed\nname. The one call it discourages, <code>load_plugin_textdomain()<\/code>, says why it\nstays: the plugin ships its own English catalogue, which WordPress only finds\nthrough that call.<\/li>\n<\/ul>\n\n<h4>0.5.23<\/h4>\n\n<ul>\n<li>The print page of a document is no longer echoed as one string. Its template\nis included directly in the response, and escapes every value at the exact\nplace where it is output.<\/li>\n<li>No inline JavaScript left: the print button, the confirmation before a status\nchange, the setup fields to copy and the \"copy backup codes\" button now use a\nscript enqueued with <code>wp_enqueue_script()<\/code>, or printed with\n  wp_print_inline_script_tag() on the standalone print page. The \"copy backup\ncodes\" button, which copied nothing, now copies.<\/li>\n<li>PDF downloads, accounting exports and stored attachments are sent with\n  X-Content-Type-Options: nosniff.<\/li>\n<li>Bundled php-font-lib: a font-debugging method that built HTML with inline\nscripts, and that nothing calls, is emptied \u2014 see \"Third-party libraries\".<\/li>\n<\/ul>\n\n<h4>0.5.22<\/h4>\n\n<ul>\n<li>The sources of the admin interface shipped in <code>app\/src\/<\/code> can be rebuilt from\nthe plugin package alone again. A screen that is not part of this package was\nimported unconditionally, so <code>npm run build<\/code> stopped on a missing file; it is\nnow loaded only where its file exists.<\/li>\n<li>The same sources are published at https:\/\/github.com\/SanMat11\/wp-erpx, and the\nreadme gives the Node.js version, the exact command and where the output goes.<\/li>\n<\/ul>\n\n<h4>0.5.21<\/h4>\n\n<ul>\n<li><strong>English is translated again.<\/strong> The English catalogue was deleted during the\n0.5.7 rename and never rebuilt: since then every string written by the server\n\u2014 API refusals shown on screen, e-mails, PDFs, meta boxes \u2014 came out in French\non English sites, while the interface itself switched. All 971 strings the\ncode asks for are now translated and shipped as\n  languages\/ams-studio-erp-invoicing-accounting-en_US.mo.<\/li>\n<li><strong>A quote could not be accepted in English.<\/strong> The wording a customer copies\nout to accept a quote was compared against the French <code>bon pour accord<\/code>, while\nthe refusal message told English customers to type \"Agreed and accepted\". They\ntyped exactly what was asked and were turned away. The expected wording now\nfollows the language of the site, and French stays accepted so agreements\ngiven before a language change remain valid.<\/li>\n<li>Four screen strings still quoted the French wording inside English sentences,\nand two were left in French outright. The screen, the refusal message and the\ncheck now say the same thing.<\/li>\n<\/ul>\n\n<h4>0.5.20<\/h4>\n\n<ul>\n<li>The text domain is now <code>ams-studio-erp-invoicing-accounting<\/code>, matching the\nslug registered on WordPress.org. It was <code>ams-studio-business-management<\/code> on\n1155 i18n calls, which prevented the plugin from being translated through\ntranslate.wordpress.org. The PHP prefix <code>amsbm_<\/code>, the option, table, post\ntype and REST namespace names are unchanged, as is the main file name.<\/li>\n<li>Internal: the translation catalogue built by <code>bin\/i18n\/<\/code> was named\n  amsbm-.po, which matched no text domain \u2014 WordPress would never\nhave loaded it. It now carries the domain, as the format requires.<\/li>\n<\/ul>\n\n<h4>0.5.19<\/h4>\n\n<ul>\n<li>Internal: the Peppol reader no longer emits a PHP warning when an incoming\ninvoice omits optional elements \u2014 payment terms, legal entity, trading name\nor tax scheme. Absent elements read back as an empty string, as intended.<\/li>\n<li>Internal: the test asserting that every document type is reachable by a role\nperformed no assertion at all: it returned on the first role covering\neverything. It now checks the business roles, and was seen to fail when a\ndocument type is unwired from them.<\/li>\n<\/ul>\n\n<h4>0.5.18<\/h4>\n\n<ul>\n<li>Internal: the bundled PDF libraries \u2014 dompdf, php-font-lib, masterminds\/html5\nand sabberworm\/php-css-parser \u2014 now live under the <code>AMSBM\\Vendor\\<\/code> namespace,\nprefixed with PHP-Scoper. Two plugins bundling dompdf in different versions\ncan no longer break each other. A document renders byte-for-byte as before.<\/li>\n<\/ul>\n\n<h4>0.5.17<\/h4>\n\n<ul>\n<li>Internal: the document editor's article catalogue no longer writes its\n   tag by hand. It goes through <code>wp_print_inline_script_tag()<\/code>, which\ncarries the page's Content-Security-Policy nonce where there is one. It stays\na JSON data block, not executable code. Nothing changes on screen.<\/li>\n<\/ul>\n\n<h4>0.5.16<\/h4>\n\n<ul>\n<li>Security: SVG rendering has been removed from the PDF engine, and the\nphp-svg-lib library with it. Drawing an SVG meant parsing user-supplied XML\ninside the printing chain, for a format the plugin never needed: logos are\nPNG, JPEG, GIF or WebP. An SVG is now refused when the logo is uploaded, and\nrefused again before it reaches the PDF. Documents without an SVG render\nbyte-for-byte as before.<\/li>\n<\/ul>\n\n<h4>0.5.15<\/h4>\n\n<ul>\n<li>Internal: every SQL query now goes through <code>wpdb::prepare()<\/code>, with no exception.\nTable and column names are bound with the <code>%i<\/code> placeholder instead of being\ninterpolated into the query string, and the plugin's own table names are checked\nagainst a hard-coded list before any query is built. Nothing changes on screen:\nthe 132 read routes return byte-for-byte identical answers.<\/li>\n<\/ul>\n\n<h4>0.5.14<\/h4>\n\n<ul>\n<li>Internal: the public quote and invoice page no longer writes its script tags by hand.\nThey go through the WordPress loader, which now also carries the page's\nContent-Security-Policy nonce. Nothing changes on screen.<\/li>\n<\/ul>\n\n<h4>0.5.13<\/h4>\n\n<ul>\n<li>Internal: four blocks in the bundled PDF libraries were rewritten from heredoc to\nstring concatenation, so that the whole package passes the directory's automated\ncheck. The generated PDFs are byte-for-byte identical. Every deviation from the\nupstream libraries is now listed in <code>lib\/pdf\/ECARTS.md<\/code>.<\/li>\n<\/ul>\n\n<h4>0.5.12<\/h4>\n\n<ul>\n<li>The \"Upgrade to Pro\" link in the header now offers to subscribe, in so many words:\nthe dialog it opens says \"Subscribe\" instead of \"Learn more\" and states the price \u2014\nthe same one the website quotes. It no longer names an empty module when it was not\nopened from a particular screen.<\/li>\n<\/ul>\n\n<h4>0.5.11<\/h4>\n\n<ul>\n<li>Internal: this package now refuses any update whose archive does not come from where\nit says it does. Nothing changes for you here \u2014 the free edition is updated by\nWordPress.org as it should be.<\/li>\n<\/ul>\n\n<h4>0.5.10<\/h4>\n\n<ul>\n<li>Removing the demo dataset and installing it again left you with no customers and no\nproducts at all \u2014 while reporting it had created twenty. Removing deleted the\nWordPress posts but not the plugin's own rows, and the next install reused a post id\nthat pointed at nothing.<\/li>\n<li>A company named \"Roussel &amp; Fils\" read \"Roussel &amp; Fils\" in the demo dataset.<\/li>\n<li>An IBAN broke into six stacked pieces in the treasury list, and an IBAN entered with\nspaces was regrouped wrongly. A cash account shows a dash instead of an empty box.<\/li>\n<\/ul>\n\n<h4>0.5.9<\/h4>\n\n<ul>\n<li>This installation now has an identity of its own \u2014 an identifier drawn at random on\nyour site, and a secret drawn with it. Nothing is sent anywhere: they exist so that a\nlicence bought later belongs to this site and fills itself in, instead of being copied\nby hand. See \"External services\" for the one moment anything leaves, and what it is.<\/li>\n<li>The activate button no longer sits flush against the licence field.<\/li>\n<\/ul>\n\n<h4>0.5.8<\/h4>\n\n<ul>\n<li>Screens that spoke French on an English site. The public invoice page a customer\nopens to pay, the goods receipt screen and the online payment settings carried their\nwording inside the code instead of in the catalogues: 87 sentences that no\ntranslation could reach. They are now in both catalogues, English included.<\/li>\n<li>The subscription screen showed its translation keys instead of its labels \u2014 its\nwhole set of 80 keys was in neither catalogue. It also named the four licence states\nit had never been given a word for, starting with a site that simply has no key.<\/li>\n<\/ul>\n\n<h4>0.5.7<\/h4>\n\n<ul>\n<li>This package now contains exactly what it runs. Purchasing, stock, deals, treasury,\naccounting, the document library and the WooCommerce bridge moved to a separate\nadd-on \u2014 their code is no longer shipped here. Nothing is capped or locked: what is\npresent works, in full.<\/li>\n<li>New name. The plugin was called ERP-X; it is now AMS Studio ERP.\nEverything it declares was renamed with it \u2014 options, tables, custom post types,\ncapabilities, hooks and the REST namespace. Nothing carries over from the old\nnames, so this version is an installation, not an upgrade.<\/li>\n<li>Nothing in this package is capped, time-limited or tied to a key. What is here\nis installed and open; what is not here is not shipped at all.<\/li>\n<li>Electronic invoicing follows. Factur-X (PDF\/A-3) and Peppol BIS Billing 3.0\nused to be conditional; they now apply to every invoice, which is what a legal\nobligation ought to be.<\/li>\n<li>The plugin no longer looks anywhere but here for its updates.<\/li>\n<\/ul>\n\n<h4>0.5.6<\/h4>\n\n<ul>\n<li>A document the WooCommerce bridge found wrong now says so before you click. The\nbridge marks it, approval refuses it \u2014 but nothing showed the reason, so the refusal\narrived out of nowhere.<\/li>\n<li>The supplier invoice screens stop offering what the server will refuse: five write\nactions in the list, and approving a credit note, are now hidden from roles that do\nnot have the right \u2014 and the reason is stated, with who to ask.<\/li>\n<li>A supplier credit note table headed two different columns \"Amount excl. VAT\".<\/li>\n<li>The credit note route names the capability it needs instead of relying on the global\nwrite right.<\/li>\n<\/ul>\n\n<h4>0.5.5<\/h4>\n\n<ul>\n<li>The plugin's own header is translated at last. Its name and description were in no\ncatalogue, so an English site read the description in French on its plugins screen \u2014\nthe one place never reread. The extractor now covers the header, as xgettext does.<\/li>\n<li>One header dropped: the plugin address and the author address may not be the same,\nand the site at ams-studio.lu presents the plugin.<\/li>\n<\/ul>\n\n<h4>0.5.4<\/h4>\n\n<ul>\n<li>Every PHP file the plugin ships now refuses a direct HTTP call. On shared hosting\nwp-content is often served without going through WordPress, and a file reached that\nway ran outside it \u2014 printing the server's absolute path in the fatal error that\nfollowed. A test counts them all and fails on the next file shipped without a guard.<\/li>\n<li>The two-factor QR script goes through the WordPress script queue.<\/li>\n<li>Repository compliance: exemptions declared for the directory's own database sniff,\nwhich is stricter than the WordPress coding standard, and one core function dropped\nin favour of a plain expression.<\/li>\n<\/ul>\n\n<h4>0.5.3<\/h4>\n\n<ul>\n<li>The plugin is named ERP-X throughout, with a new mark drawn in one place and used on\nthe admin menu, the sidebar and the sign-in screen.<\/li>\n<\/ul>\n\n<h4>0.5.2<\/h4>\n\n<ul>\n<li>fail2ban on the API, installation blocking, and an allow list on the administration.<\/li>\n<\/ul>\n\n<h4>0.5.1<\/h4>\n\n<ul>\n<li>Sealing: an invoice or credit note the WooCommerce bridge found wrong can no longer be\napproved by any path.<\/li>\n<li>Electronic invoicing: a non-compliant invoice no longer goes out by email or on the\npublic page either.<\/li>\n<li>Purchasing: only what has been received is invoiced; invoicing ahead must be asked for.<\/li>\n<\/ul>\n\n<h4>0.5.0<\/h4>\n\n<ul>\n<li>Two-factor authentication and the per-module permission matrix.<\/li>\n<\/ul>\n\n<h4>0.2.0<\/h4>\n\n<ul>\n<li>The sales cycle end to end: items, parties, quotes, invoices.<\/li>\n<li>Multi-rate VAT rounded per rate at the foot of the document.<\/li>\n<li>Quote to invoice transformation, with a line-by-line trace.<\/li>\n<\/ul>\n\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>Exact decimal arithmetic, with no silent overflow.<\/li>\n<li>Numbering by atomic UPDATE, refusing documents backdated below the last period used.<\/li>\n<li>Migration lock through a MySQL GET_LOCK, genuinely atomic.<\/li>\n<\/ul>","raw_excerpt":"An ERP inside WordPress: manage customers, products, quotes and invoices on your own server, with no external service.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/356733","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=356733"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/anthonysgro"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=356733"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=356733"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=356733"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=356733"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=356733"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=356733"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}