=== CatCode Order Sync with NetHunt for WooCommerce ===
Contributors: catcodestudio
Tags: woocommerce, crm, orders, sync, ukraine
Requires at least: 6.2
Tested up to: 7.0
Requires PHP: 7.4
Stable tag: 0.2.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Sends every WooCommerce order to NetHunt CRM as a record: at checkout or on a status change, with de-duplication, retries and an event log.

== Description ==

NetHunt is a third-party product; this is an independent integration, not affiliated with or endorsed by NetHunt.

The plugin connects WooCommerce to your NetHunt account through the public REST API v2 (Bearer token). Every new order in your shop becomes a record in a NetHunt folder with the buyer, the phone and e-mail, the total, the line items, the delivery address and a link back to the order in wp-admin.

= Features =

* Sends the order right after checkout (classic checkout and Checkout Blocks) or when it enters one of the statuses you choose
* Creates the "WooCommerce Orders" folder with all the fields it needs — no manual CRM setup; point it at an existing folder instead and the plugin adds only the fields that are missing
* De-duplication: the NetHunt record id is stored in the order meta, and a database-level lock keeps two parallel hooks from creating the record twice
* After a timeout the plugin asks NetHunt whether the record is already there (by the "Order ID" field) before repeating the attempt
* Line items in a readable list: "2 × Product (SKU) — 300 UAH", with the shipping cost as its own line (optional)
* Payment mark: the Paid checkbox plus a "Paid online" line in the record comment (optional)
* Automatic retries on failure: 3 attempts with 5 min / 30 min / 2 h pauses (WP-Cron)
* Metabox on the order screen: sync status, NetHunt ID, "Resend" button (an order already in the CRM is updated via PATCH instead of duplicated)
* "Test connection" button on the settings page
* Event log with the last sync attempts, their HTTP status and error text
* The API token is encrypted at rest (libsodium, with an HMAC fallback)
* Buyer phone numbers are normalised to E.164 (+380…)
* HPOS-compatible (custom order tables) — order data is read and written through the WooCommerce CRUD only
* `cc_nethunt_order_payload` filter and `cc_nethunt_order_sent` action for site-specific tweaks

= Requirements =

* WooCommerce 6.0 or newer
* PHP 7.4 or newer
* A NetHunt API token (account → Settings → API & MCP → Create token)

= How it works =

1. A customer places an order in your shop.
2. The plugin builds the record values (name, phone, e-mail, total, items, address, payment) and sends `POST /api/v2/folders/{folderId}/records` to NetHunt with the `Authorization: Bearer` header.
3. NetHunt answers with `{"id":"…"}` — the record id is stored in the order meta as `_cc_nethunt_record_id`.
4. If NetHunt is unreachable the attempt is repeated automatically (up to 3 times).
5. Your manager sees the status and the id in the order metabox and in the log.

== Installation ==

1. Upload the plugin folder to `/wp-content/plugins/`, or install the zip from Plugins → Add New → Upload.
2. Activate the plugin.
3. Go to WooCommerce → NetHunt Sync and enter your API token.
4. Save the settings — the plugin creates the orders folder with its fields (or connects the folder id you entered).
5. Press "Test connection", pick the trigger statuses and save.

== Frequently Asked Questions ==

= Where do I get the API token? =

In your NetHunt account: Settings → API & MCP → Create token. The token travels in the `Authorization: Bearer` header and is kept in the WordPress database in encrypted form. The older Zapier-era API v1 key is a different thing and does not work here.

= Do I have to create the fields in NetHunt by hand? =

No. With the "Orders folder" field left empty the plugin creates a folder named "WooCommerce Orders (your-domain)" with every field it uses. If you enter the id of a folder you already have, the plugin only adds the fields that are missing there and leaves the rest untouched.

= Can the same order end up in the CRM twice? =

The plugin stores the NetHunt record id in the order meta and takes a database lock before sending, so parallel hooks (checkout, status change, payment callback) cannot both create it. The remaining case — a request that never gets an answer — is covered by the "Order ID" field: before retrying, the plugin looks the record up by it and adopts the existing one. If the folder has no such field (it was created before 0.2.0 and the field could not be added), the order is flagged in the metabox instead so you can check the CRM yourself.

= What does the "Resend" button do? =

If the order is not in NetHunt yet, it creates the record (`POST …/records`). If it is already there, it updates it (`PATCH …/records/{recordId}`) with the current buyer, items, address and payment data. Fields you do not send stay as they are in NetHunt.

= What happens when I delete the plugin? =

Deleting (not just deactivating) removes the plugin options and the log table. The NetHunt record ids stored on the orders are kept on purpose: they are what stops a reinstall from creating a second copy of an old order in the CRM.

== External services ==

This plugin connects to the NetHunt CRM API (`https://nethunt.com/api/v2`), a third-party service. The connection is the whole purpose of the plugin: it creates and updates your WooCommerce orders as records inside your own NetHunt account.

What is sent and when:

* `POST /folders` and `POST /folders/{folderId}/fields` — when you save the settings, to create the orders folder or add the fields it is missing.
* `GET /folders/{folderId}` — when you save the settings with a folder id, to read its field schema.
* `POST /folders/{folderId}/records` — when a customer places an order, or when the order enters one of the statuses you selected as a trigger. Retried up to 3 times if NetHunt is unavailable.
* `PATCH /folders/{folderId}/records/{recordId}` — when you press "Resend" in the order metabox for an order that already exists in NetHunt.
* `POST /folders/{folderId}/records/filter` — only after an attempt that got no response, to check whether the record already exists before retrying.
* `GET /folders` — when you press "Test connection" on the settings page.

Every request carries your NetHunt API token in the `Authorization` header. The order data sent is: the WooCommerce order number and id, the line items (name, SKU, quantity, price), the order total and currency, the shipping method and its cost, the delivery city and address, the payment method title and whether the order is paid, the customer note, a link to the order in wp-admin, and the buyer's first and last name, e-mail address and phone number as entered at checkout.

No data is sent to any other service, and nothing about your visitors, site or administrators is sent beyond the order data listed above. Nothing is sent until you enter your API token: without it the plugin makes no external requests.

This service is provided by NetHunt: [terms of service](https://nethunt.com/legal/terms), [privacy policy](https://nethunt.com/legal/privacy).

== Screenshots ==

1. Settings: API token, orders folder, trigger statuses
2. Sync log with the last attempts
3. NetHunt metabox on the WooCommerce order with the resend button

== Changelog ==

= 0.2.0 =
* Renamed the plugin to "CatCode Order Sync with NetHunt for WooCommerce" (new slug and text domain). Options, order meta and the log table keep their names, so nothing has to be migrated.
* Fixed: the "Resend" button in the order metabox never worked. The metabox drew its own `<form>` inside the WooCommerce order form, and browsers drop a nested form — the click submitted the order form instead. It is a nonced link now, and the result is shown as an admin notice.
* Fixed: the guard against a double send was a transient, i.e. a read-then-write — two parallel hooks could both pass it and create the record in NetHunt twice. It is now a database-level lock, and the order is re-read past the HPOS order cache before the final check.
* Fixed: uninstalling the plugin left the sync log table in the database forever. It is dropped now; the per-order NetHunt record ids are kept on purpose as the anti-duplicate guard.
* Added: an "Order ID" field in the folder holding the WooCommerce order key. After an attempt that gets no HTTP response the plugin looks the record up by it and adopts the existing one instead of creating a second; orders that cannot be looked up are flagged in the metabox. Folders provisioned by 0.1.0 get the field added automatically.
* Admin styles are now enqueued through a registered handle instead of raw `<style>` output.
* Interface strings are in English with a Ukrainian translation shipped in `/languages`.

= 0.1.0 =
* First release: orders exported to a NetHunt folder (REST API v2), folder and field provisioning, retries, metabox, log, connection test.

== Upgrade Notice ==

= 0.2.0 =
Makes the "Resend" button work at all, fixes a race that could create the same order in NetHunt twice, and stops leaving the log table behind on uninstall.
