== Changelog ==

The four most recent releases are in readme.txt, which is what the plugin
directory displays. This file holds the whole history, newest first.

= 0.6.19 =
* A payment reminder offered a "pay online" link that refused the customer. The link was written into every reminder, but the page behind it only accepts an order awaiting payment: on an order on hold it landed her on "this order cannot be completed, please contact us". Chasing someone for money with a button that turns her away is worse than offering nothing. The link now appears only when the payment would actually be accepted, and the transfer details above remain the way to pay.
* The order screen pointed at its own answer. When a shop had typed an exchange rate by hand, the hint underneath read "this site already answers 0.85, fill this in only to override it" — while 0.85 sat in the box just above, put there by that same shop. The screen now asks what the site would answer if the field were empty, so the sentence is either "nothing here knows it, and here is why it matters" or a genuine rate coming from a multi-currency plugin.
* Every action the administration triggers answered a signed-out caller with a blank page. They are all registered for signed-in callers only, so a signed-out request matched no handler at all and WordPress ended on an error page with no error in it — a white box titled "WordPress > Error". Found while checking that a document URL refuses a stranger: it refused, and said nothing, which reads like a broken site rather than a locked door. All twenty-one now answer 403 with a sentence and a link to sign in, and the list is read from what is actually registered rather than written out by hand.
* Filtering a list sent the eye back to the top of the page. The table reloads without a page load, and what it scrolled to afterwards was the whole screen — so pressing Filter landed you on the banners above, with nothing to do with what you had just asked. Twice reported, on two screens. It now brings the RESULT into view, which sits above the filters and carries them along, and it does not move the page at all when that line is already visible.
* An identifier at a platform meant nothing outside the platform that issued it, and nothing recorded which one that was. Change provider — an ordinary event after September 2026, and one that also happens when a platform loses its registration — and every past document announced its number under a provider that had never heard of it, while the hourly sweep asked the NEW platform about the OLD one's reference and wrote the 404s into the trail as though the document had gone wrong. Seen on a real screen: two identifiers issued by one platform, announced under another. The issuing platform is now recorded beside the number, the panel names it, and nothing is asked of a platform that did not hand it over. Documents filed before this records nothing about their issuer, and are left exactly as they were rather than given an invented one.
* The person at a company appeared nowhere on her own invoice. As soon as a billing company was filled in, it took the customer name — which is right, the company is what owes — and the person vanished: not on the printed page, not in the XML, and the document had no field for her at all. EN 16931 has one, BT-56, the buyer contact point. She is now named on the page under the company, and written into the XML as DefinedTradeContact, at the one position the CII sequence allows. Validated against the official rules on a real document.
* The buyer's e-mail is on the printed page too. It already travelled in the XML as BT-49, the address the network routes by; on paper it is the one line that lets someone chase a payment or query a line without going back to the shop's records. Not repeated when the address IS the customer name.
* An order keyed in without a street left two empty lines in the middle of the address block. They are printed only when there is something to print.

* Creating an invoice by hand said nothing, either way. On success the button redirected with a flag nothing read: the document was written and the screen came back silent, so the only way to know the click had worked was to hunt for the panel and see it had changed. On refusal it sent another flag nothing read either — clicking "Create the invoice" on an order with no customer at all did nothing, said nothing, and left no way to learn why. Both now use the message bus the rest of that panel already used.
* The refusal on the order screen was written inside a closed drawer. The SIRET field lives in the billing block WooCommerce keeps folded until the pencil is clicked, so a company saved without a SIRET was blocked — correctly — and the explanation was printed where nobody could see it, with the focus and the scroll doing nothing at all on a hidden field. Reported as "the Update button does not work, and there is no message". The refusal now appears at the top of the screen, where the hand just clicked, and the billing block opens itself on the field to fill in.
* The documents list printed a dash where the invoice printed a name. An order carrying nothing but an e-mail address still produces an invoice headed "Billed to name@example.com", and the customer column showed nothing beside it. The list now names her through the same function the document uses, so the two cannot drift apart whatever is missing.

* A credit note never left the shop. Nothing listened for it: the invoice went onto the network and the document that UNDOES it stayed on the disk, so the buyer's software still held a debt that had been cancelled and the correction the tax network needs to see was never sent. Measured on a real preprod: an invoice deposited at 8.50 and its credit note written, filed and never queued. It now goes out on its own, with its own identifier at the platform — one status field cannot hold two documents — and the order panel shows where it stands, under the invoice.
* Saving the settings from a page opened before a platform existed erased that platform's credentials. The form posted the panel marker without the fields, and an absent field reads as empty: the client ID and the customer ID were blanked, the platform was silently reset to the rehearsal one, and only the secret survived because an empty password already meant "keep what is stored". The form now declares which platform blocks it carried, and a block it never showed can no longer be cleared by it. Clearing a field on purpose still clears it.
* An unrecognised platform became the rehearsal platform in silence. That is a shop's invoices quietly rerouted away from a real network. What is stored is kept instead, and the screen says why.
* What was measured about a platform now dies with the settings that made it true. A red "the platform refused the credentials" stayed on screen after the platform had been changed, and a green "the credentials work" was shown to someone who had tested nothing. Both are thrown away when a platform setting changes.

* The summary above the received invoices said "VAT 141.48" and "Total 1,294.37" — of what, over what? A figure without its unit is a figure an accountant cannot use. It now reads "47 invoices, deductible VAT 141.48 EUR, total incl. VAT 1,294.37 EUR", and says how many credit notes were deducted, because a total smaller than the invoices on screen otherwise reads as an arithmetic error.
* Deleting a received invoice asked its question in the browser's own grey box, which cannot be styled, cannot name the invoice, and looks like the alert of a site trying to trick you — on the one click that erases a legal document. The question is now asked in the page, names the invoice, and says the file goes with it. The link keeps working with no JavaScript at all.
* And it said nothing on the way back. The row vanished and the screen looked exactly as it would have if the click had missed. A confirmation now names the invoice that left.
* The first click on Save could do nothing. The sticky save bar carried no z-index and no background of its own, and wp-admin's own footer — absolutely positioned at the bottom of the page and later in the document — painted over it and took the click. The bar now owns its stacking context and its ground.

= 0.6.18 =
* A credit note now says which invoice it corrects, and an invoice says which credit notes were raised against it. The number was always inside the file — BR-55 puts it there — and was read out of it nowhere. On the received-invoices screen that left a -172.80 line among a dozen others with nothing saying what it undid: a figure that reads as a mistake rather than as a correction. On documents issued the same gap ran the other way — a refunded invoice keeps the total it charged, because an issued invoice is a legal record and is never rewritten, and no line on the screen explained why the books disagreed. Both screens now carry the pair under the number, and clicking it brings the two documents side by side. The invoice PDF is untouched: the mention belongs to the screen, not to a document already issued.
* The pairing is built in one query for the whole table rather than by asking each invoice for its refunds, because that screen lists every document before paginating and a per-row lookup would cost one query per invoice in the shop.
* Received invoices filed before today are gone back over once, and the corrected number read back out of the files they kept. Measured on a real preprod: three credit notes named, none silent, no file unreadable.
* On Windows, no received invoice could be opened again. update_post_meta() runs its value through wp_unslash(), which eats the backslashes of a Windows path, so the stored path led nowhere and every file_exists() on it failed. Paths are normalised before they are stored. Nothing on a Linux host ever showed this, which is why it lived this long.
* FSYNC_Bills::all() built its own copy of a bill row instead of calling the one function that builds them, and had fallen two fields behind it. A caller got different keys depending on which door it came through. There is one shape now.

= 0.6.17 =
* A period could be declared and then quietly grow. A filed period keeps the figures it was filed with, which is right — they are the record of what was transmitted — but the orders underneath keep moving: an order created in the period and paid by transfer after the filing, one keyed in with an earlier date, one imported. The dashboard showed "Declared" with its receipt and looked settled while the money sat undeclared. Found on a real dashboard: August filed at 7,871.83, the same month recounted at 9,580.88 — fourteen sales and 335 EUR of VAT that nothing mentioned. The row now says so, with the count and the amounts. Nothing is re-filed: re-declaring a period is a tax decision, not one for code to take on a shop's behalf.
* Choosing a platform shows its fields at once. Until now the picker answered a choice with nothing until the page had been saved and reloaded — and a screen that answers a choice with silence is read as broken: you conclude the setting does not work, and never press save. Every platform's block is now written into the page, all but the chosen one hidden, and the picker reveals the right one on the spot. No request is made — the fields are three inputs and a round trip would be slower than the reveal — and with no JavaScript at all the chosen platform's block is still the only one on the page, which is where this started.
* A document given up on was told it would be retried. After five failures the queue lets go of an invoice — but the screen kept saying "it would go out on its own within five minutes", which was true for one more attempt and false for ever afterwards. A sentence that is right for five minutes is worse than one that is plainly wrong: the shop waits instead of acting. Giving up now takes the invoice out of the queue whoever was sending, and the panel says what has actually happened — abandoned after five attempts, out of the queue, and the button is the way to try again.
* A filing that FAILED was freezing its figures as though it had succeeded. The dashboard keeps a declared period exactly as it was transmitted, which is right — but it was doing the same for an attempt that never arrived anywhere, so the row showed the numbers of the failure while the orders underneath had moved on. Measured on a real dashboard: May displayed 66.50 over 2 sales, frozen from a filing that had been refused, while its orders came to 75.00 over 3 — and the shop was one click from filing, reading the wrong figure. Only a period actually transmitted settles now; everything else counts what is there.
* The drift figure is emptied by what makes it wrong, not by a clock. It is cached so the dashboard is not recounted on every load, and the cache expired on a timer — which meant a shop owner could look at the screen and read "2 sales arrived after this declaration" when the third had just arrived. She does not flush caches; she reads what is there and believes it. Saving an order, changing its status or recording a refund now empties the figure for that order period, so the next look is a fresh count and every other look is free.
* A month that sold only to businesses reads 0.00 and looks broken. It is correct — a business sale is declared by its own invoice travelling the network, and counting it here as well would declare it twice — but the row said nothing, and a shop that knows it sold in April concludes the plugin is at fault rather than that the reform counts differently. The row now says so where the doubt appears, and only when there is something to explain.
* The connection test said the key was accepted whatever the platform answered. Anything that was not a 401 or a 403 — a 404, a 500, a gateway error — came back as "the key is accepted", which asserts more than the answer carries. A 404 on the directory lookup means something useful and quite different: the key got through and the company is not registered yet, so nobody can address an invoice to it until the platform does that. The three cases are now told apart, and the result is repeated at the head of the platform panel, which is where the browser lands: the page returns on #platform, so a banner written above it leaves the screen before it can be read — reported from a real screen as "the message showed for two seconds", when nothing had moved but the page.
* A field that silently cut what you typed. The numbering prefix stops at fourteen characters so the whole number stays under the twenty some platforms accept — a kind limit, and a mute one: typing a fifteenth character made it vanish, the screen said "Settings saved", and the only reasonable conclusion was that no rule existed. The limit is now written under the field, with its reason.

= 0.6.16 =
* The same rule, for an order keyed in by hand. Recording a company in the administration without its SIRET went through in silence, and the invoice was queued for a network that had no way to deliver it. The order screen now refuses to save before the form is posted — beside the field, with the company named — because the person who can still fix it is the one looking at the screen, not a reader of a note at the bottom of a page she has already left. The server keeps the rule too: a check in a browser is a courtesy, never a guarantee.
* The Conformité screen takes the width of the screen. The old cap left half a large monitor empty beside a table that had to wrap. The explanation stays two columns with one paragraph in each — not a single text flowing from the foot of one to the head of the other, which reads as one long passage cut in half — and each column now takes half the card rather than a fixed 476px: 818px at a window of 1920, 498px at 1280, side by side at both, and the table of periods sits 59px higher than it did. No horizontal overflow at either width.
* The order screen checks the number as well as its presence. A SIRET whose check digit is wrong was refused by the server, which meant learning about it after the page had reloaded, from a note at the bottom. The browser now runs the same arithmetic before the form is posted — La Poste exception included, because the two implementations have to agree on every number or the guard would let through what the server then refuses.
* An order keyed in by hand kept its lines untaxed, and nothing said so. WooCommerce does not work the tax out on a line added in the administration until Recalculate is pressed; the order is then saved with no VAT, and the invoice faithfully prints "0 %" — which is a claim that the supply is zero-rated, not an admission that nobody worked it out. Twenty percent that would never be declared. The document is left alone, because a document records what happened rather than what was meant, and the shop is warned at the top of the order screen while the order can still be corrected. Domestic sales only: a sale to another member state and an export are lawfully at zero, and warning about those would teach the shop to ignore the warning that matters.

= 0.6.15 =
* A company name is not an identity, and the checkout now says so before it takes the order. An order carrying "Épicerie du Pont" and nothing else was treated as a business sale and queued for the network, while its XML went out with no buyer identifier at all — no SIREN, no VAT number, nothing a platform can route by. It would have come back refused days later, worded by the platform, to a shop with no idea what to change. Give a company name and the checkout now asks for the SIRET that goes with it, or the VAT number when the business is outside France. Both checkouts refuse it, the classic one and the block one — the block checkout needed a rule of its own, because it validates one field at a time and this one is about two.

= 0.6.14 =
* An invoice could state less money than the customer had paid. A shop that ticks the franchise en base (article 293 B) while WooCommerce still holds a tax rate charges VAT at the checkout — and the invoice, reading the setting rather than the sale, printed "TVA non applicable" and the amount without it. Found on a real order: 57.60 EUR taken, an invoice reading 48.00 EUR, an "already paid 48.00" line that was simply untrue, and both documents in the same email. The setting is a claim about the seller; the money that changed hands is a fact, and an invoice records the fact. A sale that carried VAT is now invoiced with its VAT whatever the setting says, and the order is told once, in its notes, that its two settings disagree so the shop can fix the cause.

= 0.6.13 =
* A settings tab turned square the moment it was clicked, and round again once something else was. wp-admin sets `border-radius: 2px` on every focused link it can reach, and that selector outranks a class of ours, so the tab lost its corners for as long as it held focus. The same trap had been met on the compliance tiles and fixed there; the tab strip never got the same treatment. Its ring is also drawn with a shadow now, and only for keyboard travel — a ring left on the panel you just clicked reads as a mistake.

= 0.6.12 =
* A saved secret was erased by a save that did not re-post it. The settings screen prints every secret as an empty password field — a page that re-printed a token would leave it in the browser history and in anyone's view source — so any save of that panel posts it back empty, and the code has to read that as "keep it". Four of the five keys did. The token of "My approved platform" trimmed the empty string and wrote it: the shop lost what transmits its invoices by saving an unrelated field beside it, and the screen looked exactly the same afterwards. The rule is now checked for every key the screen treats as a secret, so the next connector is covered without anyone remembering to.
* The archive shipped 736 KB of alphabetical-index data for a library that draws invoices, a leftover script that served and deleted files named in the query string with no check of any kind, and the debugging helpers of a dependency. None of the three is reachable from the plugin. Everything that remains states that it is not a page on its own.

= 0.6.11 =
* The VAT rate on a line was divided back out of the amounts instead of being read from the tax table. A line of 4.56 taxed at 20% carries 0.912 of VAT, which WooCommerce stores as 0.91 — and 0.91 / 4.56 is 19.96%. The invoice printed a rate that exists in no French tax table, wrote it into the XML, and because the VAT breakdown groups by rate, one category became two: "20%" and "19.96%", each with its own base. The document disagreed with itself. The rate WooCommerce actually applied is now read from its own tax table.

= 0.6.10 =
* The "orders without an invoice" reminder no longer stretches across the screen to hold one sentence. Closed it hugs its text; opened it takes the width its list needs.
* "Who files" now stops the period filing too, not only the daily one. The guard had been put on the daily path alone — and the period path is the one nearly every platform actually uses, so the setting stopped the half almost nobody runs.

= 0.6.9 =
* Several sales channels under one SIREN. E-reporting is filed for a company, not for a shop: a merchant selling from a till and from here files once for the two. Two settings now say so out loud — whether this shop files at all, and what name it files under. Switch the filing off and your invoices keep being transmitted; only the declaration stops. That is the honest answer for a merchant whose till software or accountant already declares.
* Switched off, a day is refused **and left open**. Recording it as done would have been the expensive mistake: switched back on later, every day passed in the meantime would have been skipped in silence, and a missing transmission costs €500.
* The channel name was hard coded to "woocommerce" in one of the platform connectors, under a comment explaining that it existed to prevent exactly the collision it caused — two WooCommerce shops under one SIREN filed under the same name, and one day of sales replaced another.
* A name typed with capitals, spaces and accents is folded rather than refused: "Ma Boutique Été" becomes "ma-boutique-ete".
* The test suite failed every other run for no reason. Its two products drew random SKUs between 1000 and 9999 and a new product was created each time; after several hundred runs the collision was a matter of when, not if, and WooCommerce answers a duplicate SKU with an uncaught exception. Fixed SKUs, product reused. A suite that fails at random teaches you to ignore its failures.

= 0.6.8 =
* Looking at an invoice no longer saves it. The document number and a new "Preview" action open the PDF in its own tab; the old action keeps the download and is now called "Download", which is what it always did. Checking twenty documents used to leave twenty files in the downloads folder.
* "Rebuild" from a row of the documents list rebuilt the file and then dropped you on the order screen. It now returns where you came from, filter and page included, with its own message. The way back travels in the link rather than in the browser's Referer header, which referrer policies and privacy extensions strip.
* The payment due date is printed on every invoice, paid or not. Article L441-9 of the Code de commerce lists it among the mentions an invoice must carry and makes no exception for one already settled — but it was shown only when money was still owed, which is never on a shop paid at the checkout. The XML carried it all along: the printed page was the half that stayed silent.
* The customer and payment blocks are no longer boxed. The border was drawn around each line rather than around the block, and a frame around a customer's name earns its place on no invoice.
* French typography on the printed document: a no-break space before every colon. "Échéance : 23 septembre 2026", not "Échéance:". The separator is translated rather than typed, so English keeps its own rule.

= 0.6.7 =
* Nothing you can see changed, and that is the point: this release is what the WordPress.org guidelines ask for. The licence check now lives inside the block that is cut from the free archive, so the free version carries no licence machinery at all — not dormant, absent. Every caller asks whether the function exists before calling it, and the build refuses to produce the free archive if the question ever comes back, naming the file and the line.
* Eight outputs that were marked "trust me, this is hard coded" now escape for real. The nav icons go through wp_kses with an explicit list of shapes; the document stylesheet and the shop's footer line print instead of being returned and echoed; two form controls are written as a branch instead of a conditional the escaping check could not follow. Same screens, same PDFs — 342 checks say so — but a reviewer can now verify what was previously only asserted.
* Tested up to WordPress 7.1.
* The build could refuse to produce the free archive on a fresh clone. Git ships core.autocrlf on Windows, so the file came out with carriage returns and the marker the build looks for was anchored on a bare newline: it found nothing and stopped. It stopped safely, but for a reason that had nothing to do with the code, and on the day the archive was due.

= 0.6.6 =
* The block checkout refused an order with no SIRET in WooCommerce's own words — "Please provide a valid siret", built from the field id — while the classic checkout had always said "Please give your SIRET number." The field now carries its own message, so both checkouts speak the same French.
* An e-reporting figure can be checked again. The count of consumer sales links to the orders it is made of, and the list is restricted to orders with no SIRET over the same period: the number and the list agree. The link was removed once because it opened the whole month, business orders included, and contradicted the figure it hung off; it comes back only with the filter that makes it true. A quarterly period still shows plain text, because WooCommerce filters its list on a month and three months cannot be one address.
* Settings rows stack below 900px. The label column is a fixed 252px and the control took what was left, which on a narrow window was nothing: measured at 800px, the explanation column collapsed to 0px, wrapped one character per line, and turned a three-line card into a 2352px column.

= 0.6.5 =
* A shop could lose its very first month from the e-reporting card, and a period that never appears can never be declared. The list of periods walked back a month at a time keeping its day of the month, and stopped as soon as it passed the oldest order timestamp: a first order on the 29th, read on the 23rd, put the cursor on the 23rd of that month — before the order — and the month was dropped, sales and all. It now walks back to the first instant of that month.

= 0.6.4 =
* The "completed orders with no invoice" warning counted refunds. Refunds share the orders table, carry the status completed, and have no invoice number, so each one was reported as a missing invoice — telling a shop it was out of compliance when it was not, and naming rows that opened on "the order type does not match". A refund is corrected by a credit note, which it already has. A warning nobody can trust is a warning nobody reads.

= 0.6.3 =
* Received invoices lost their supplier name, accepted the same document twice, and handed both faults to the accountant. Filing an invoice under a supplier wrote the supplier id into the very meta key that held the supplier NAME read from the invoice. Three things broke at once: the Supplier column showed a bare number, the CSV export carried that number, and the duplicate check — which matches on supplier plus number — looked for a name where only a number was left, so the same invoice could be imported again and again. A debt counted twice is a debt paid twice. The two facts are different, so they now have two keys, and a one-time pass puts back the names from the record titles.

= 0.6.2 =
* An invoice sent by hand was deposited twice. "Send it now" handed the document to the platform but left it in the queue: only the cron loop removed what the cron itself had sent. Five minutes later the same invoice was filed a second time, and the identifier the platform returned overwrote the first — so the audit trail no longer pointed at the deposit the customer had been told about. On a rehearsal platform that is a harmless duplicate; on a real one it is the same invoice filed twice on the tax network. Removal from the queue now happens inside send(), so it covers every sender rather than one of them.

= 0.6.1 =
* The platform card sits above the mailbox one: the platform is the channel the reform defines, the mailbox is the fallback, and reading them the other way round teaches the wrong order.
* Both now count in words that agree. "2 documents proposés, 1 factures enregistrées" was two counts sharing one plural form, which no language can satisfy; each half carries its own.

= 0.6.0 =
* Supplier invoices can now be collected from your approved platform, which is the channel the reform actually defines. From 1 September 2026 a supplier's platform hands the document to yours, and yours holds it until you collect it; the mailbox we also read is the fallback for suppliers who will keep attaching a PDF to an email for years. Both end on the same screen.
* Collecting and acknowledging are two steps, never one. A document is stored first and only then declared taken, because a platform does not offer the same one twice — and anything we could not read is LEFT on the platform, where it can still be looked at, rather than quietly consumed.

= 0.5.8 =
* Fixed, and it changed the face of a legal document: an invoice re-dated itself every time its file was rebuilt. The date printed on it, the date in its XML and the due date counted from it were all taken from the day the file was written rather than the day the invoice was issued — so an invoice from July, rebuilt in September, came out dated September with a due date a month away, while the customer held a copy saying otherwise. It was found in a payment reminder that said fourteen days past due beside an attachment claiming it fell due next month. A document has one date, fixed the moment its number is spent. Credit notes take the date of the refund they record, and a delivery note keeps the day it was first printed, as it keeps its number.

= 0.5.7 =
* The move into the protected folder no longer writes a warning to the error log for a folder it deliberately left alone. It asked to remove each emptied folder and let the failure happen; a log full of warnings from a migration that worked is a log nobody reads the day something is really wrong.

= 0.5.6 =
* Received invoices are now matched to the suppliers you keep in Supplier Purchase Orders, when you have it. What each has invoiced over the past year, which invoices came from someone you have no record of — asked once and remembered — and which of your suppliers have never sent you an electronic invoice at all. From 1 September 2026 they have to, so that last list is the one worth a phone call.
* It does not claim to reconcile an invoice against a purchase order. Supplier keeps no purchase orders: its buy list is worked out from your orders each time you open it, and it carries quantities, not amounts. Comparing against a document that does not exist would be worse than saying so.

= 0.5.5 =
* A stored password, key or token can now be erased. An empty box has always meant "keep what is stored", which is right — the screen never prints a secret back, so it cannot post one back either. But it left no way at all to REMOVE one: a shop that changed provider, or pasted a key into the wrong field, kept the old secret in its database for ever with nothing on any screen able to touch it. There is a Forget it link beside each one.

= 0.5.4 =
* A mailbox that cannot be reached now says why in words. PHP answers a wrong server name with "php_network_getaddresses: getaddrinfo for x failed", which is true, unreadable, and says nothing about what to do; the four failures a shop actually meets — a name that does not exist, a closed port, a firewall, a bad certificate — each get a sentence.

= 0.5.3 =
* Supplier invoices can now arrive on their own. Point the plugin at a mailbox and it reads the unread messages every hour, files the PDF and XML attachments as received invoices, and marks the message read. It never deletes anything, never moves anything, and never opens a message twice.
* Written without the imap extension, which most shared hosting does not have and PHP itself is dropping: the protocol is spoken directly over an encrypted socket, and the certificate is verified. The MIME reader is ours too — it undoes base64 and quoted-printable, reads a file name sent encoded ("facture février.pdf" arrives as gibberish otherwise), and ignores signatures and logos without calling them errors.
* The mailbox settings live on the received-invoices screen, beside the invoices they fetch, rather than three menus away.

= 0.5.2 =
* Fixed in the reminders list before anyone saw it: an order nobody had chased showed a stray 0 in the reminders column. An order meta that was never written comes back as an empty string, and casting that to an array gives one empty element — which counts as one.

= 0.5.1 =
* Payment reminders. An invoice is not the end of a sale, it is the start of a debt, and the plugin used to forget about it the moment it was issued. A reminder now goes out on the days you choose, counted from the due date, with the invoice attached — once per delay, never to someone who has paid, never on an order worth nothing, and never at all until you switch it on.
* A list of what is owed, which is worth reading whether or not you switch reminders on: every invoice past its due date, who owes it, how late, what has already been sent, and the total at the bottom. Each line has a button to write today.
* The reminder is a real WooCommerce email, so it wears your shop's header, footer and colours, appears in WooCommerce > Emails where you can read it, and can be overridden by a theme like any other.

= 0.5.0 =
* Selling abroad now produces the right invoice. Until this release every sale was treated as a French one selling to France: an export to the United States and a supply to a company in Belgium both came out with French VAT categories and no mention of why nothing was charged. Four cases are now told apart — the franchise en base, the intra-Community supply with its reverse charge, the export outside the union, and a consumer in another member state under the One Stop Shop — each with the VAT category EN 16931 expects, the exemption reason its rules require, and the sentence French law asks for on the paper.
* What is charged decides. A line carrying VAT is a taxed line whatever the destination, so a shop whose tax settings charge VAT on an export cannot end up with a document whose category says exempt and whose totals say otherwise.
* Invoices in another currency state their VAT in euros as well. That is BT-111, and without it EN 16931 rejects the document — so every sale in dollars or pounds was invalid. The rate is never invented: it is read from a filter, from the meta the usual multi-currency plugins leave behind, or typed on the order itself, and found nowhere the plugin says so instead of putting a made-up figure on a tax document.
* E-reporting counts sales abroad apart. A sale to a consumer in another member state is taxed there and declared to another administration; adding it to the French figures overstated what was owed in France by exactly that amount.

= 0.4.45 =
* The rehearsal platform no longer answers "23 document(s)". A count the code already knows can agree with its own sentence.

= 0.4.44 =
* Fixed, and it stopped transmission dead for anyone who followed our own advice: credentials kept in wp-config.php made the plugin declare the platform unconfigured. Every connector already read the constants — each with its own private copy of that code — while the check that decides whether the queue may run asked the database, found it empty, and refused to send anything. So the screen showed the fields filled in and locked, and the invoices waited for ever. The constants are now read in one place, which the check uses too.
* The generic connector reads them as well. It was the only one whose endpoint and token could not be kept out of the database, and it is the one most shops will use.

= 0.4.43 =
* An order that completed before its billing details were filled in now says so. Once the details are there nothing is standing in the way any more — and the panel went silent, leaving "no invoice yet" with no next step, which is exactly what the reason line exists to prevent. It now says that an invoice is not made again on its own, and points at the button.

= 0.4.42 =
* Security, and this one matters on any shop that has been running a while: the documents issued BEFORE 0.4.23 were never moved into the protected folder. That release put new invoices behind a per-site secret and left the old ones exactly where they were — at /wp-content/uploads/factureflux/<order>/<number>.pdf, a URL made of two sequences anyone can count through, carrying a customer's name, her full address, her SIRET and what she paid. On nginx the .htaccess beside them does nothing. They are moved on the first admin page load after this update, and their stored locations follow. Nothing is copied, nothing is overwritten, and two documents that would collide both keep their file.

= 0.4.41 =
* An empty table under a filter no longer claims the shop is empty. Searching for a name that matches nothing answered "nothing received yet" and "no invoice yet" — and someone holding two hundred documents and a mistyped search believes the screen, not the search. Both screens now say the filter found nothing, and how to clear it.

= 0.4.40 =
* Fixed: two French messages never agreed in the plural. Dropping three invoices on the received-invoices screen answered "3 facture lue et enregistrée". The plural was written as a second, separate entry in the translation file, where the format wants one entry carrying both forms — so the second was never read.

= 0.4.39 =
* Fixed: an XML invoice could never be received. Every one of them was turned away as "neither a PDF nor an XML file" — on a screen whose own file picker offers .xml, and while several approved platforms deliver the XML alone. The check was asking WordPress which file types the MEDIA LIBRARY accepts, and .xml is not among them. These files never went near the media library. Nothing is loosened: the content must still hold a real Factur-X invoice, or it is refused on that.

= 0.4.38 =
* Fixed, and every delivery note ever printed was wrong: the quantity column said 0. The template asked each line for "quantity" where every line in this plugin is built with "qty", so it read nothing and printed none. A delivery note exists to say what is in the parcel and how many of each; without the quantity it says nothing at all.

= 0.4.37 =
* Fixed: the footer line printed on your documents could not hold a second line. The setting was saved keeping its line breaks and printed keeping them, its own hint said so — and the field on screen was a single line, where a line break cannot be typed. Three parts of the plugin agreed on something the fourth made impossible.

= 0.4.36 =
* The platform panel now answers the question the picker raises. Five names, none of which most shops recognise, out of 138 approved platforms: the screen says which case is yours — public sector, a platform your accountant already gave you, or nothing yet — before asking you to choose.
* The generic connector comes first among the real platforms and is named for what it is: my approved platform, any REST API. Two brands listed ahead of it read as "those two, or nothing", which is the opposite of what the plugin does.
* The in-plugin help no longer sells transmission as paid. It was saying so to people who now have it.

= 0.4.35 =
* Chorus Pro is now in the FREE version, and so is the machinery behind it: the queue, the lifecycle statuses, the trail on each order, and the rehearsal platform. Selling to the public sector has required electronic invoicing for years, so a shop invoicing a town hall is already out of compliance — and making it wait for a licence to stop being so was the wrong side of the line. Pro keeps what 2027 makes necessary: the connector for any approved platform, e-reporting and the compliance dashboard.
* The description now leads with receiving invoices, which is the deadline that arrives first: 1 September 2026, for every French business, whatever its size. It was buried under issuing, which most shops are not required to do until a year later.

= 0.4.34 =
* Removed two Pro features from the description that were never built: a live check of SIREN and VAT numbers against the official registries, and an FEC export. Neither exists in the code — there is not a single network call outside the platform connectors. Selling an absent feature is worse than any defect: a defect is a mistake, this would have been a statement. The in-plugin help said the same thing to someone who had already paid.
* The remaining Pro lines now say what the code does: e-reporting filed WITH the date and the receipt the platform hands back, and a dashboard that says which documents are stuck and why.

= 0.4.33 =
* Fixed, and this is the one that mattered: a perfectly valid Factur-X file from a supplier was refused about one time in four, and accepted on the next upload. The reader trimmed trailing carriage returns and line feeds off each compressed stream before unpacking it — and those are ordinary bytes in compressed data. When the invoice payload happened to end in one, cutting it corrupted the stream and the invoice inside was declared not to exist. A file refused once and accepted next time is worse than one always refused, because nobody believes it.

= 0.4.32 =
* A period that failed to file now says WHY, under its state. The reason was recorded with the attempt and shown nowhere, so the row announced a failed tax filing and left the shop to remember what it had been trying at the time.
* And a refusal is no longer shown in the same blue box as a success. At a glance the two read alike, and this one says a tax filing did not happen.

= 0.4.31 =
* The two paragraphs of explanation on the compliance dashboard now sit side by side on a wide screen, instead of forming one narrow column with an empty half beside it. Each keeps a readable measure, and they stack again below 1100 pixels.

= 0.4.30 =
* Fixed, and this one reached the declaration itself: the VAT rates an e-reporting period announces were split by rounding. The rate was worked out by dividing each line VAT by its net, so a single 20 % came back as 19,98 / 20,00 / 20,05 and one month declared ELEVEN different rates. The rate is now read from the tax line WooCommerce actually applied. Totals are unchanged; only the grouping is right.
* Each period now shows how it splits across VAT rates, which is the shape the declaration takes, and says plainly that sales to businesses are not counted there.
* Removed: the order count no longer links to the month is orders. It announced 609 consumer sales and opened a list of 757, business ones among them, because WooCommerce cannot filter its list on carrying no SIRET. A link that contradicts the number it hangs off is worse than no link.

= 0.4.29 =
* Fixed: the message shown when a send fails ran two sentences together, with no full stop between what the platform said and what to do about it.

= 0.4.28 =
* When a platform answers with something other than an answer, the message now says so. Stripping the tags out of an error page left a shop reading "The platform answered 405: Example Domainbody{background:#eee" — the code buried in the page stylesheet. A web page arriving where an API answer was expected usually means the address points at a website, and saying that is more useful than quoting it.

= 0.4.27 =
* Fixed: with transmission on and no platform configured, invoices queued for ever in silence while the dashboard said "nothing is stuck, every document either travelled or is on its way". Nothing was travelling and nothing ever would. Both the dashboard and the order now say what the document is waiting for.
* Every connector was put through the answers a platform gives on a bad day — a refused key, an outage, an HTML error page from a proxy, an empty body, a timeout — and none of them mistakes a failure for a success, invents a status, or leaves a message a shop cannot read. bin/connectors.php does that on demand.

= 0.4.26 =
* Fixed: the buttons in the order panel were cut off. That column is about 300 pixels wide and WordPress gives buttons one unbreakable line, so "Ask the platform for news" ran past the edge — and a label cut in half is a button nobody is sure of. They now wrap, grow to fit, and span the column.

= 0.4.25 =
* A filed period now shows WHEN it was filed and the receipt the platform gave back. A filing is a legal act and the time of it is the proof it happened; it had been recorded since the first version and displayed nowhere.
* Each figure now says how many orders make it up, as a link to those orders. What gets DECLARED is totals and never a customer or an invoice number — that is what e-reporting is, and sending identities would be a breach rather than a service. But a shop still has to be able to check its own figure.

= 0.4.24 =
* Received invoices now have a size limit per file and a ceiling on the folder, and the screen says how much room they take up. Nothing bounded them before: on shared hosting the disk quota is the whole account, so filling it does not break the plugin, it breaks the site.
* Fixed: deleting a received invoice left its file on the disk. The check compared the path against a written-out folder name, which stopped matching when the folder moved and never matched on Windows at all. A stored file that is never deleted is the disk filling up in slow motion.
* Invoice numbers were put under real concurrency — twenty-four invoices issued at once from separate processes, three runs — and every document got its own. bin/race.php now does that on demand.

= 0.4.23 =
* Security: invoices are no longer reachable by typing their address. They were stored under /wp-content/uploads/factureflux/<order>/<number>.pdf and protected by an .htaccess — a file Apache reads and nginx ignores. On nginx, every invoice sat at a URL made of two sequences anyone can count through, carrying a customer name, a full address, a SIRET and an amount. The folder now carries a secret drawn once per site, which holds on any server, and keeps the .htaccess plus a web.config for those that honour them. Invoices received from suppliers move there too.
* Security: reading a supplier Factur-X file no longer unpacks without a limit. A kilobyte of compressed data can expand into gigabytes, and these bytes arrive by email from a stranger.
* Security: the export of received invoices no longer hands a spreadsheet a formula to run. Every value in it was written by whoever sent the invoice, and a cell beginning with = is executed by Excel, not displayed.

= 0.4.22 =
* The Invoice and Credit note badges are now links: click one and the list shows only that kind. So is the transmission state beside it. Reaching for a dropdown to narrow by a word already under the cursor is a step nobody should have to take — and both keep the filter you already had, so the month you were looking at does not vanish.
* Fixed: two different things in this plugin were called fsync-missing, and the later rule in the stylesheet was quietly repainting the new warning banner.

= 0.4.21 =
* A button to ask your platform for news about one document, instead of waiting for the hourly sweep. Same reasoning as sending by hand: the schedule is right for a shop and useless to someone who has just sent something and wants to know whether it arrived.
* Our buttons are round on every screen now, and stay round when clicked. They were styled for the documents screen alone, so the compliance dashboard kept the square ones — and the order panel, sitting in a WooCommerce meta box outside our own wrapper, could not read the design values at all.

= 0.4.20 =
* Every count on the compliance dashboard now opens the documents behind it. "Two paid" is worth nothing without "which two".
* The documents screen gained a Transmission column showing the state and the identifier your platform handed back. The screen could already be filtered by that state without ever showing one, and the identifier — the only thing to quote in a support message — appeared nowhere at all.
* Periods are written as months, not codes: August 2026 above, 2026-08 underneath for when a filing needs the code. A period not yet declared now shows what your orders add up to so far, instead of a dash.

= 0.4.19 =
* Buttons now say what they did. Sending an invoice by hand, or setting an order aside, went through a redirect that discarded everything they printed — so pressing one and landing on a page that looks identical was indistinguishable from pressing one that does nothing. The message names the new state, the identifier the platform gave back, and where to follow it; a failure names the reason.

= 0.4.18 =
* Fixed: an order note could come out half in one language and half in another. The refusal was worded before the shop language was applied and the sentence around it after, so a site in English read by a French administrator produced a note whose first half was English. One record, one language.
* Translations are now loaded from both places WordPress looks, instead of only the first one found. A file downloaded for an earlier version knows nothing of the sentences added since, and would have left every new one untranslated.

= 0.4.17 =
* Fixed: the business fields on the order screen were switched off along with the ones at checkout. Asking every customer for a SIRET and being able to record one on an order taken by telephone are two different decisions, and a shop that declined the first was left with no way to do the second at all.
* Fixed: those fields relied on a WooCommerce helper that is not loaded on every screen, which would have taken the order screen down rather than merely hiding them.

= 0.4.16 =
* The SIRET, VAT number and order reference can now be typed on the order screen. They were shown there and never editable, so an order taken over the phone, imported, or carrying a SIRET the customer mistyped could not be put right — on the very fields that decide whether an invoice travels on the tax network. They are checked exactly as the checkout checks them, and a value that does not check out is refused with the reason recorded in the order history.

= 0.4.15 =
* A "Send it now" button on an invoice waiting to go out. The queue drains every five minutes, which is right for a shop and wrong for a person standing in front of the screen — and it also gives a way past a document that used up its retries.
* The missing-invoice warning is amber rather than red. It is something to attend to, not something that has gone wrong; red belongs to a rejected transmission, and using it for both made both mean less.

= 0.4.14 =
* The missing-invoice warning folds away, and remembers that you folded it. The count stays on the folded line: it can take no room, but it must not become invisible while the gap is real.
* Any order can be set aside — a test, a sale that will never be invoiced — and stops being counted. It is a decision about the ORDER, not about the screen, so it holds for everyone, shows on the order itself, and can be undone there.
* The count is now thrown away whenever an order is saved, instead of standing for up to five minutes. A warning that lags is a warning people stop believing.

= 0.4.13 =
* The documents screen now warns when completed orders have no invoice, and names them. The screen lists documents that exist, which is exactly why the ones that do not exist were invisible on it — and a missing invoice is the one thing here nobody should discover during an audit.
* The order panel says WHY there is no invoice yet, instead of only that there is none. "No invoice yet" on an order completed last week is a statement nobody can act on.

= 0.4.12 =
* When an invoice cannot be produced automatically, the order now carries a note saying so and why. Nobody is watching at the moment an order completes, and the refusal went nowhere: a shop could find out weeks later that an invoice it believed existed never did.

= 0.4.11 =
* Fixed: an invoice sent to your platform could carry English legal mentions while the PDF kept on disk carried French ones. One invoice number, two different documents, and the one an auditor reads is not the one your customer received. Transmission now rebuilds the document in the shop language, exactly as the PDF was written.
* Fixed: a supplier Factur-X file could be refused as "not a Factur-X" and accepted on the next upload. Reading the attachment out of the PDF relied on a regular expression whose success depended on what the compressed bytes happened to be. It now walks the file directly.

= 0.4.10 =
* Fixed: an order with no customer name produced an invoice with an empty buyer name. EN 16931 rule BR-07 requires one, and French law requires an invoice to say who it is for. Every field the name could be in is now tried — billing company, billing name, shipping name, the customer account, then the email address. An order naming nobody at all is refused with an explanation, and the refusal spends no invoice number: the series has to stay gap-free.
* Fixed: a shop whose language the plugin is not translated into still got translated documents. The reader was French, the shop was English, and the English source strings never came back.
* Fixed: after rendering a document, the administration could stay in the shop language for the rest of the page. Switching a locale WordPress has no language pack for reports failure even though the strings did change, and the restore was hanging off that report.

= 0.4.9 =
* Fixed, properly this time: a site in French (Canada) still showed English. The first attempt filtered the locale WordPress asks for, which reads well and does nothing — nearly every string is translated on demand through a function that never applies that filter. The translation file is now loaded by name, under the locale the site actually asked for.

= 0.4.8 =
* Fixed: your documents are written in the language of the SHOP, not the language of whoever is logged in. WordPress speaks to each administrator in her own language, which is right for a screen and wrong for an invoice — an owner who had set her own profile to English was issuing English invoices, with the compulsory French legal mentions translated away.
* Fixed: a site in French (Canada), French (Belgium) or French (Switzerland) showed the plugin in English. WordPress connects no regional variant to another, so the nearest translation of the same language is now used. This applies to every language the plugin is ever translated into, not only French.
* Transmission is now shown on the order itself. The compliance dashboard answers how your documents are doing; the order panel answers whether THIS invoice went out — its state, its identifier at the platform, and the whole trail, newest first. It also says plainly when an invoice will never leave, and why.
* The banner shown to shops outside France now carries the plugin's own styling and a readable width, instead of a bare notice running the full width of the screen.

= 0.4.7 =
* Your bank details. A new IBAN field, with its check digits verified as you save it, and an optional BIC. It is printed on the invoice in groups of four, the way a bank prints it.
* Fixed: an invoice issued before payment was refused by the standard. It announced payment by transfer without naming the account to transfer to, which rule CII-SR-470 of EN 16931 rejects — and which no customer could have paid from either. Fill in your IBAN and such invoices become valid; leave it empty and they no longer claim a transfer that cannot be made.
* Fixed: on a credit note covering several VAT rates, the rate on each line was labelled in English on a French site.

= 0.4.6 =
* Fixed: a refund entered as an amount alone credited the whole sum as untaxed, so the VAT went back to the customer without being reclaimed. It is now spread across the rates of the order it corrects, to the centime.
* Delivery notes. The sheet that goes in the parcel, printed on demand from any order, in its own short series. It carries no XML and no VAT: a delivery note is not a small invoice, and reprinting one changes nothing anyone can be audited on.
* Received invoices. From 1 September 2026 every French business must be able to RECEIVE electronic invoices, a year before the smaller ones have to issue any. Drop the Factur-X files your suppliers send you on the new screen: the number, the supplier, the dates and the amounts are read out of the file itself and kept, with a CSV export for your accountant. PDF or XML, several at once, and the same invoice twice is refused.
* An accent colour and a footer line on your documents. Bounded on purpose: an invoice is a PDF/A-3 archival file with rules about colours and fonts, and a free template would let you produce something beautiful that a platform then refuses.
* Fixed: the seller address was built from two places at once, our field for the street and the WooCommerce shop address for the town.

= 0.3.0 =
* A returning business customer no longer retypes her SIRET and VAT number on every order. They are kept on her account and filled in for her, on both checkouts. The order reference is deliberately not remembered: it differs every time, and prefilling last month's would put a wrong reference on an invoice.
* The invoice now carries your logo, chosen from the media library.
* Every field in the plugin is now checked before it is saved, free and Pro alike: whole numbers stay whole numbers, endpoints must be complete https addresses, numbering prefixes may only hold characters a file name and an XML field can both carry, and the Chorus Pro technical account must actually be a login and a password. A value that does not check out is refused and the stored one kept, with a message naming the field and the reason.
* Help bubbles on every setting, not only on your business details.
* The admin menu now carries the plugin's own mark instead of a generic dashicon.

= 0.2.0 =
* Your SIREN, SIRET and VAT number are now checked before they are saved. Typing a letter used to empty the field silently and still report success — a nine-digit number gone, with nothing said. A value that does not check out is now refused, the stored one is kept, and you are told which field and why.
* A help bubble on every field in Your business, explaining what the field is for and what a wrong value costs.
* The fields now carry a maximum length, so a fifteenth digit is refused as you type rather than after saving.
* Fixed: the outside-France banner sat glued to the card below it, and wrapped at half width on the settings screen.
* Fixed: the search box on the documents screen swallowed every spare pixel.

= 0.1.8 =
* The late payment rate is now tidied on save. It is printed verbatim as a legal mention, so "10", "10%" and "10 %" all became different sentences — and "10" alone read as "10 per year", which says nothing. A number is normalised; wording such as three times the statutory interest rate is left exactly as written.

= 0.1.7 =
* Added bin/seed.php, which fills a test shop with the awkward cases: two VAT rates in one order, a zero total, a name with an apostrophe, an order left unfinished on purpose, a full refund and two partial ones.

= 0.1.6 =
* Fixed: a byte order mark had crept into the main file, so activation reported "3 characters of unexpected output". The build script now refuses any file carrying one.

= 0.1.5 =
* Fixed: the platform panel and every connector message were still in English on a French site — 31 strings, including what the connection test answers back.

= 0.1.3 =
* A Help panel worth opening: the reform in plain words, a ten-question FAQ, documentation and support, and what Pro adds.
* The search field moved inside the filter card, so the screen has one white banner instead of three floating bars.
* Fixed: the pagination arrows folded into a block whenever the bar was tight.
* Fixed: the new filter labels were shown in English on a French site.

= 0.1.2 =
* A real filter bar on the documents screen: document type, named periods or a date range, whether the file is still on disk, and — in Pro — the transmission state. What is being filtered is shown as removable chips, and the filters now survive paging and bulk actions.
* Fixed: the documents screen was missing the class that carries the design, so its rounded corners and hairlines had nothing to resolve to.
* Fixed: dropdowns had lost the arrow that says they are dropdowns.

= 0.1.1 =
* The documents list now wears the same design as the rest of the plugin: rounded card, calm rows, house controls, instead of WordPress's default table chrome.

= 0.1.0 =
* First release: Factur-X invoices and credit notes, French legal mentions, B2B checkout fields, email attachments, documents screen with ZIP export.

