=== Factulit VeriFactu ===
Contributors: factulit
Tags: verifactu, invoices, woocommerce, aeat, spain
Requires at least: 6.1
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 2.1.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Connect WooCommerce to Factulit: VeriFactu invoicing, AEAT submission and a chained billing record, without leaving your store.

== Description ==

Factulit VeriFactu connects your WooCommerce store to [Factulit](https://factulit.es), a Spanish VeriFactu invoicing service. It turns your WooCommerce orders into VeriFactu-compliant invoices and billing records, and takes care of the technical requirements of the Spanish anti-fraud regulation (Reglamento VERI*FACTU) on your behalf.

**What the plugin does**

* Sends your WooCommerce orders, customers and order-status catalog to your Factulit account, where invoices and billing records are generated.
* Every billing record is chained by hash to the previous one, as required by the VERI*FACTU regulation, and submitted to the Spanish Tax Agency (AEAT).
* Refunds are tracked: a full or partial WooCommerce refund is matched to its corresponding billing record on the Factulit side, with per-line detail.
* Pending items are queued locally and retried automatically if a sync attempt fails, so a temporary network or API issue does not lose data.
* Declares compatibility with WooCommerce High-Performance Order Storage (HPOS / custom order tables).
* A dedicated admin screen shows connection status, pending progress and a manual "Sync now" action.

**Who it is for**

Spanish WooCommerce stores that need to comply with the VERI*FACTU regulation: businesses issuing invoices for their online sales that want the billing-record generation, hash chaining and AEAT submission handled by a dedicated service instead of building it in-house.

**An account with Factulit is required**

This plugin is a client for the Factulit service. Without a Factulit account and a valid API key, the plugin will not generate invoices or send anything to AEAT; it only prepares and queues data locally. Sign-up is open and guided: you create an account, connect your store, configure your invoicing series and confirm the certificate/authorization details, then explicitly activate invoicing. Factulit has a Free plan at no cost for up to 50 invoices per month, and paid plans for higher volume; current plans and limits are published at https://factulit.es/precios.

= External services =

This plugin relies on the external, third-party service **Factulit** (https://factulit.es) to generate invoices, billing records and AEAT submissions. This is a SaaS product with a free tier and paid plans (see https://factulit.es/precios). By installing and configuring this plugin you agree to be bound by the Factulit Terms and Conditions and Privacy Policy.

The plugin communicates only with the two fixed Factulit API endpoints: `https://api.sandbox-factulit.es/api` for Demo and `https://api.factulit.es/api` for Production. The active endpoint is part of the server-issued, versioned connection binding; it changes atomically together with the binding generation and the environment-specific API credential. The settings screen never accepts an arbitrary API URL, and a queued row always keeps the endpoint and binding under which it was created. Moving from Demo to Production uses this same installed plugin and never redirects old Demo rows to Production. It sends:

* **Customer data**, when a customer record is synced: first name, last name, email, phone, tax ID (NIF/NIE/CIF), address, postal code and city.
* **Order data**, when an order is synced: the order and its line items, needed to generate the corresponding invoice.
* **Order-status catalog data**: the list of WooCommerce order statuses used in your store, so their fiscal classification (which statuses trigger an invoice, a cancellation or a refund) can be configured on the Factulit side.
* **Connection and version data**, at most once every 12 hours: the installed plugin version, the WooCommerce/CMS version, the store's site URL, the URL of this store's sync (cron) endpoint and the bearer token that protects that endpoint. The version data is used to tell you when a newer plugin version is available. The endpoint URL and its token are what allow Factulit to call your store back to run a sync; without them the service cannot reach your store. That token is generated by the plugin, is specific to your store, and can be rotated at any time from the plugin's settings screen, which invalidates the previous one.

This data exchange is required for the plugin to function: it is how your store's orders become VeriFactu invoices and billing records. No data is sent to Factulit before you configure a valid API key.

Terms and Conditions: https://factulit.es/condiciones-de-contratacion
Privacy Policy: https://factulit.es/politica-de-privacidad

== Installation ==

1. Install and activate WooCommerce if it is not already active.
2. Install the plugin through the WordPress plugins screen, or upload the plugin files to `/wp-content/plugins/factulit-verifactu/`.
3. Activate Factulit VeriFactu through the "Plugins" screen.
4. Go to the "Factulit VeriFactu" menu and enter your Factulit API key. If you do not have a Factulit account yet, sign up at https://factulit.es.
5. Configure the fiscal classification of your order statuses from your Factulit account (which statuses generate an invoice, a cancellation or a refund).
6. Use "Sync now" for an initial manual sync. From then on, Factulit triggers the synchronisation of your store automatically while the connection is active — you do not need to set up any server cron.

== Frequently Asked Questions ==

= How does synchronisation work? Do I need to set up a cron job? =

Synchronisation works without one, but scheduling it is strongly recommended. There are three channels:

* **Automatic (recommended).** While your connection is active, Factulit itself calls your store's protected sync endpoint every few minutes and processes any pending orders, customers and statuses. Nothing to set up. Its one weakness is that it comes from the outside: a server firewall, Cloudflare or a hosting configuration change can block it, sometimes months after you connected.
* **Your store's cron task.** A scheduled task on your own hosting calling the same endpoint. It is the only route that does not depend on anyone letting Factulit in, which is why the plugin screen keeps a red card until it detects a real run from it. The plugin gives you the full URL, token included, ready to paste into wget or curl.
* **Manual.** The "Sync now" button opens a live progress view and sends pending data in batches. Useful for the first load after connecting, or to verify a change right away. It complements the other two, it does not replace them.

The plugin screen shows one card per channel with the date of its last successful run, so you can confirm at a glance which ones are actually working.

= Do I need a Factulit account to use this plugin? =

Yes. The plugin only prepares and queues WooCommerce data locally; invoices, billing records and AEAT submissions are generated by the Factulit service, which requires an account and a valid API key.

= Is Factulit free? =

Factulit has a Free plan at no cost for up to 50 invoices per month, and paid plans for higher volume. Current plans and limits are published at https://factulit.es/precios.

= What data does the plugin send to Factulit? =

Customer data needed to issue an invoice (name, email, phone, tax ID, address, postal code, city), order data, your store's order-status catalog, and, at most once every 12 hours, connection and version data: installed plugin version, WooCommerce/CMS version, site URL, the sync endpoint URL and the bearer token protecting it. See the "External services" section above for the full disclosure.

= Does this plugin work without WooCommerce? =

No. Factulit VeriFactu requires WooCommerce to be installed and active; it reads WooCommerce orders, customers and order statuses.

= Is it compatible with WooCommerce High-Performance Order Storage (HPOS)? =

Yes. The plugin explicitly declares compatibility with the `custom_order_tables` feature, and it is tested with HPOS both enabled and disabled.

= Does it support the block-based WooCommerce checkout (Cart & Checkout blocks)? =

Block-based checkout support is not yet verified. The plugin has not been specifically tested against the Cart and Checkout blocks; if you use the block-based checkout, please report any issue through the support forum.

= Which WordPress, PHP and WooCommerce versions is it tested with? =

It is tested on WordPress 6.8 through 7.1, PHP 8.1 through 8.4, and WooCommerce 10.0 through 11.0.1, with High-Performance Order Storage both enabled and disabled.

= In which languages is the plugin available? =

The plugin is written in English and ships a full Spanish (es_ES) translation, so a store running WordPress in Spanish sees the whole admin screen in Spanish.

= Where does the plugin write its log? =

In `wp-content/uploads/factulit-sync-logs/`, in a file whose name includes a random suffix generated for your site. API keys and bearer tokens are redacted before anything is written.

= When does VeriFactu become mandatory for my business? =

The VERI*FACTU regulation sets two dates: 1 January 2027 for taxpayers subject to Corporate Income Tax, and 1 July 2027 for the rest of the obligated parties. There is no single date that applies to "all businesses".

= What happens if I stop using Factulit? =

You can deactivate and delete the plugin at any time from the Plugins screen. Deactivating the plugin does not delete your local sync history table; this is kept for traceability. Your Factulit account and any invoices already issued are managed separately, from your Factulit account.

== Screenshots ==

1. Settings screen: connection status, API key field, and the fiscal-classification notice pointing to the Factulit panel.
2. Sync screen: synchronisation health, exact order progress, the three sync channels, the "Sync now" action and recovery actions when needed.
3. Update notice: the inline admin notice shown when a newer plugin version is available, with release notes.
4. Cron block: the read-only cron endpoint URL and the "Rotate cron token" action.

== Changelog ==

= 2.1.0 =
* Onboarding in 3 steps: the plugin reports its order inventory when connecting, before syncing any order.

= 2.0.2 =
* Un 423 de facturacion restringida (limite del plan o pago pendiente) ya no consume reintentos: la cola espera y se recupera sola al regularizarse la cuenta.

= 2.0.1 =
* Usa el dominio definitivo y aislado `api.sandbox-factulit.es` para Demo.

= 2.0.0 =
* Adds one-installation Demo-to-Production pairing with immutable binding and generation headers.
* Encrypts the environment-specific API credential and versions every local queue row by binding.
* Closes old-generation retries during cutover instead of redirecting or deleting them.

= 1.9.8 =
* Sends pending orders through the Factulit batch endpoint, while preserving per-order retries, ledger evidence and fiscal fingerprints.
* Falls back automatically to the compatible individual route when the backend does not expose batch yet.

= 1.9.7 =
* Fixed fiscal order fingerprints so they include the complete fiscal recipient and line data while excluding contact and technical metadata.
* The stored fingerprint now advances only after Factulit accepts the order, so a timeout cannot hide the change from a later retry.

= 1.9.6 =
* The automatic sync response now reports an independent progress snapshot: total orders inspected, up to date, pending, blocked, and whether the figures are exact. Factulit can therefore show the real remaining workload instead of treating the legacy batch limit as a total.
* Factulit now receives whether the store hosting cron has actually run and the timestamp of its last successful execution, so the connection page can verify the recommended fallback channel.

= 1.9.5 =
* Removed the redundant legacy metrics row from the synchronisation screen. Order progress and blocked items remain available in the clearer progress block above.

= 1.9.4 =
* The synchronisation screen now separates channel health from data progress and shows orders up to date, pending, and waiting for retry or attention. Exact totals and percentages are shown for normal-sized stores; bounded counts are explicitly marked with a plus sign.
* Fixed a pagination bug that could stop the historical sweep after its first 300 orders, leaving later orders untouched while reporting that there was nothing pending.

= 1.9.3 =
* The WordPress sidebar menu now uses the Factulit favicon.

= 1.9.2 =
* Fixed: the bundled Spanish translation now loads on every supported WordPress version, including WordPress 6.1 through 6.6.
* Fixed: global admin notices from other plugins are no longer moved inside the Factulit header card.

= 1.9.1 =
* Security: the API destination is now fixed to Factulit and is no longer editable from the WooCommerce settings screen.

= 1.8.4 =
* Fixed: the tax rate of a line was being deduced by dividing tax by the base amount. WooCommerce stores both already rounded to two decimals, so the quotient drifted into non-existent rates (3.12 over 14.88 gave 20.97%, which does not exist in Spanish VAT). The rate WooCommerce already declares for the line (via its tax-rate table) is now used directly for products, fees, shipping and refund lines; dividing is only a last resort, and even then the result is snapped to the nearest legal rate when it is within 0.25 points of it, so real rounding noise is corrected without masking an actually wrong rate.
* Fixed a related bug in the product/fee tax split: even when WooCommerce did declare a rate, it was silently discarded and re-derived by division right after. The declared rate is now kept as-is.

= 1.8.3 =
* The batch sweep now syncs orders only. Every order already carries its customer block, and Factulit creates or updates the customer from it, so the separate customer pass was re-sending the same work with twice the requests. On a real store this was measured as roughly 300 requests a minute being rejected during a backfill, half of them redundant.
* Customers keep syncing two ways, unchanged: inside their order, and in real time when they are created or edited - which covers the only case orders do not, changing a tax ID or address without buying anything new.
* The pending-customers counter disappears from the progress view, progress is measured on orders, and queue rows left over from the old customer pass are removed on update.

= 1.8.2 =
* The synchronisation block now shows three channel cards - automatic, your store's cron task and manual - instead of a single status line, matching the other Factulit connectors.
* The cron card stays red until a real run from your hosting is detected, and the detection uses its own record so it cannot start green from an inherited value. Scheduling that task is the only route that keeps working if your server ever starts blocking Factulit's calls.
* The automatic card now always explains that limitation, even while it is working: Factulit calls in from the outside, and a firewall, Cloudflare or a hosting change can block it months after you connected.
* The cron setup details moved inside the cron card, where they belong.

= 1.8.1 =
* Only customers with at least one order in the configured window are synced. Sign-ups and profile edits with no purchase behind them no longer travel to Factulit: they cannot produce an invoice, so sending that personal data was pure noise.
* Queue rows left behind by customers that no longer qualify are cleaned up on update. They inflated the local counters and, if they had failed, the filtered sweep would never pick them up again.
* New "Resync everything from scratch" action (discreet link with a confirmation dialog): it clears the local record of what has already been sent so the next synchronisation sends the whole history again. Nothing is deleted from the store or from Factulit, and existing orders are updated rather than duplicated.

= 1.8.0 =
* "Sync now" opens a new tab with a live progress view: pending orders and customers, a progress bar and a typed log, sending data in small batches with pause/resume. Much clearer than the previous single-batch button on stores with a large backlog.
* The cron endpoint URL shown on the plugin screen now includes the access token and has a "Copy URL" button, so it can be pasted as-is into a hosting cron task (wget or curl). The endpoint accepts the token from the URL only as a fallback; Factulit keeps authenticating with the protected Bearer header.
* The plugin screen was reorganised: Factulit logo in the header, the connection block is collapsed once the store is connected, and automation/cron details live inside the synchronisation block in a collapsible section.
* "Rotate cron token" is now a discreet link with a confirmation dialog explaining the implications, to avoid accidental rotations that break existing hosting cron tasks.

= 1.7.0 =
* New synchronisation health block on the plugin screen: a colour-coded status plus the date and channel (automatic or manual) of the last successful sync and the result of the last attempt.
* The plugin now records every sync run (remote automatic runs and manual "Sync now" runs) so you can confirm at a glance that synchronisation is working.
* Clearer guidance on the plugin screen and in this readme: automatic synchronisation is triggered by Factulit while the connection is active, so no server cron is needed; "Sync now" complements it for the first sync or quick checks.
* More resilient retries: temporary service saturation (HTTP 429/503, honouring the Retry-After header) and account-level authentication errors no longer count towards the dead-letter limit, so a transient issue cannot bury pending orders.
* Real-time hooks (checkout, customer updates) now use short timeouts and never interrupt the store flow if the Factulit service is slow or unreachable; the data stays queued and is picked up by the next automatic run.

= 1.6.1 =
* API keys and store data can only be sent to explicitly approved Factulit gateways; arbitrary API URLs are rejected.
* Connection validation continues to send the API key only in the `X-API-KEY` header.

= 1.6.0 =
* Current stable release. Sync of WooCommerce orders, customers and order-status catalog with Factulit; refund tracking with per-line detail; local retry queue with a "dead records" recovery action; HPOS (custom order tables) compatibility declared; admin screen with connection status, synced counters and manual sync; REST cron endpoint protected by a rotatable bearer token; periodic version check with an in-admin update notice.
* Prepared for the WordPress.org plugin directory: English as the source language with a bundled Spanish translation, GPLv2 license, measured compatibility headers, and logs moved to the uploads folder so they survive plugin updates.

== Upgrade Notice ==

= 1.7.0 =
Adds a synchronisation health block (last successful sync, channel and last attempt) and clearer manual vs automatic sync guidance. No breaking changes.

= 1.6.1 =
Restricts API destinations to approved Factulit gateways and rejects arbitrary URLs.

= 1.6.0 =
First version published in the WordPress.org plugin directory. No breaking changes. The admin screen is now translated instead of hard-coded in Spanish, so stores running WordPress in Spanish see no difference. See "External services" for the full data-sharing disclosure.
